Computer-Science

Fundamental Data Structures

1. Arrays

๋ฐฐ์—ด์€ ํ™•์‹คํ•˜๊ฒŒ ์ •ํ•ด์ง„ ์ˆœ์„œ๋กœ ๋ฌด์–ธ๊ฐ€๋ฅผ ์ €์žฅํ•  ๋•Œ๋Š” ์œ ์šฉํ•˜๊ณ , ๊ฐ„๋‹จํ•˜๊ฒŒ ์ ์šฉ๋  ์ˆ˜ ์žˆ์ง€๋งŒ. ์•ฝ๊ฐ„์˜ ๋‹จ์ ์ด ์กด์žฌํ•œ๋‹ค.
๋ฐฐ์—ด์€ ๋ณ€ํ™”์— ์ทจ์•ฝํ•˜๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ๋ฐฐ์—ด์€ ๋ฏธ๋ฆฌ ํฌ๊ธฐ n์„ ์ •ํ•ด์•ผ ํ•˜๋ฉฐ ๋ฐฐ์—ด์˜ ํฌ๊ธฐ๋ฅผ ๋‹ค์‹œ ์ •ํ•˜๋Š” ๊ฒƒ์ด ์–ด๋ ต๋‹ค. (STL ๋ฒกํ„ฐ์—์„œ ์ด ๋‹จ์ ์€ ํ•ด๊ฒฐ๋œ๋‹ค.)
๊ทธ๋ฆฌ๊ณ  ์›์†Œ ์ถ”๊ฐ€๋ฅผ ์œ„ํ•ด ์ถ”๊ฐ€๋  ๊ณต๊ฐ„์„ ๋งŒ๋“ค๊ฑฐ๋‚˜, ์›์†Œ ์ œ๊ฑฐ ํ›„์— ๋นˆ ๊ณต๊ฐ„์„ ์ฑ„์šฐ๋Š” ๋“ฑ, ์›์†Œ๋“ค์˜ ์ด๋™์ด ์š”๊ตฌ๋˜๊ธฐ ๋•Œ๋ฌธ์—, ๋ฐฐ์—ด์—์„œ์˜ ์‚ฝ์ž…๊ณผ ์ œ๊ฑฐ์— ์–ด๋ ค์›€์ด ์žˆ๋‹ค.

2. Linked Lists

Singly Linked List, Doubly Linked List and Circularly Linked List

(1) Singly Linked List

๋งํฌ๋“œ ๋ฆฌ์ŠคํŠธ(linked list)์˜ ๋…ธ๋“œ ๋‚ด๋ถ€์˜ next ํฌ์ธํ„ฐ๋Š” ๋‹ค๋ฅธ ๋…ธ๋“œ์— ๋Œ€ํ•œ link ๋˜๋Š” pointer๋กœ ๋ณผ ์ˆ˜ ์žˆ๋‹ค. next ์ฐธ์กฐ๋ฅผ ํ†ตํ•ด ํ•œ ๋…ธ๋“œ์—์„œ ๋‹ค๋ฅธ ๋…ธ๋“œ๋กœ ์ด๋™ํ•˜๋Š” ๊ฒƒ์€ link hopping ๋˜๋Š” pointer hopping ์ด๋ผ๊ณ  ํ•œ๋‹ค.

๋งํฌ๋“œ ๋ฆฌ์ŠคํŠธ์˜ ์ œ์ผ ์ฒ˜์Œ๊ณผ ๋งˆ์ง€๋ง‰ ๋…ธ๋“œ๋ฅผ ๊ฐ๊ฐ ๊ทธ ๋ฆฌ์ŠคํŠธ์˜ head์™€ tail์ด๋ผ ๊ฐ๊ฐ ๋ถ€๋ฅธ๋‹ค. ๊ทธ๋ž˜์„œ ๋ฆฌ์ŠคํŠธ๋ฅผ head์—์„œ ์‹œ์ž‘ํ•ด์„œ tail๊นŒ์ง€ ๋ฐฉ๋ฌธํ•  ์ˆ˜ ์žˆ๋‹ค. null์„ ์ฐธ์กฐํ•˜๋Š” next ๊ฐ’์„ ๊ฐ€์ง„ node๋กœ tail์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

๊ฐ ๋…ธ๋“œ๊ฐ€ ๋‹จ์ผ ์—ฐ๊ฒฐ์„ ์ €์žฅํ•˜๋ฏ€๋กœ ์ด๋Ÿฌํ•œ ๊ตฌ์กฐ๋ฅผ Singly Linked List๋ผ๊ณ  ๋ถ€๋ฅธ๋‹ค.

๋ฐฐ์—ด์—์„œ์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ Singly Linked List๋„ ํŠน์ • ์ˆœ์„œ๋Œ€๋กœ ์›์†Œ๋“ค์„ ์ €์žฅํ•˜๋ฉฐ, ์ด ์ˆœ์„œ๋Š” next ๋งํฌ์˜ ์—ฐ๊ฒฐ๋กœ์จ ๊ฒฐ์ •๋œ๋‹ค. ๋‹ค๋งŒ ๋ฐฐ์—ด๊ณผ๋Š” ๋‹ค๋ฅด๊ฒŒ, Singly Linked List๋Š” ๋ฏธ๋ฆฌ ์„ ์–ธ๋˜์–ด ๊ณ ์ •๋œ ํฌ๊ธฐ๋ฅผ ๊ฐ–๋Š”๋‹ค. ๋…ธ๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜ ์‚ญ์ œํ•จ์œผ๋กœ์จ ์‚ฌ์ด์ฆˆ๋ฅผ ์žฌ์กฐ์ • ํ•  ์ˆ˜ ์žˆ๋‹ค.

Inserting at the Head

IMG_B9767E3CC7BB-1

  1. Allocate a new node and insert new element
  2. Have new node print to old head
  3. Update head to point to new node

Time Complexity : O(1)

Inserting at the tail

IMG_2D2B47330F77-1

  1. Allocate a new node and insert new element
  2. Have new node point to new node
  3. Have old last node point to new node
  4. Update tail to point to new node

Time Complexity : O(n)

Removing at the Head

IMG_7BDC1F68FD37-1

  1. Update head to point to next node in the list
  2. Allow garbage collector to reclaim the former first node

Time Complexity : O(1)

Removing at the Tail

IMG_7F3ADAA7E9D7-1

Time Complexity : O(2n-1) = O(n)


Implementing a Generic Singly Linked List

#include <string>
using std::string;

// Code Fragment 3.13: A node in a singly linked list of strings.
class StringNode
{ // a node in a list of strings
private:
    string elem;                   // element value
    StringNode *next;              // next item in the list
    friend class StringLinkedList; // provide StringLinkedList access
};

// Code Fragment 3.14: A class definition for a singly linked list of strings.
class StringLinkedList
{ // a linked list of strings
public:
    StringLinkedList();             // empty list constructor
    ~StringLinkedList();            // destructor
    bool empty() const;             // is list empty?
    const string &front() const;    // get front element
    void addFront(const string &e); // add to front of list
    void removeFront();             // remove front item list
private:
    StringNode *head; // pointer to the head of list
    // ๊ตฌํ˜„์— ๋”ฐ๋ผ tail์„ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒฝ์šฐ๋„ ์žˆ๋‹ค.
};

// Code Fragment 3.15: Some simple member functions of class StringLinkedList.
StringLinkedList::StringLinkedList() // constructor
    : head(NULL)
{
}
StringLinkedList::~StringLinkedList() // destructor
{
    while (!empty())
        removeFront();
}
bool StringLinkedList::empty() const // is list empty?
{
    return head == NULL;
}
const string &StringLinkedList::front() const // get front element
{
    return head->elem;
}

// Code Fragment 3.16: Insertion to the front of a singly linked list.
void StringLinkedList::addFront(const string &e)
{                                   // add to front of list
    StringNode *v = new StringNode; // create new node
    v->elem = e;                    // store data
    v->next = head;                 // head now follows v
    head = v;                       // v is now the head
}

// Code Fragment 3.17: Removal from the front of a singly linked list.
void StringLinkedList::removeFront()
{                           // remove front item
    StringNode *old = head; // save current head
    head = old->next;       // skip over old head
    delete old;             // delete the old head
}

(2) Doubly Linked List

Singly Linked List์˜ tail์—์„œ ์›์†Œ๋ฅผ ์ง€์šฐ๋Š” ๊ฒƒ์€ ์‰ฝ์ง€ ์•Š๋‹ค. ์‚ฌ์‹ค, Singly Linked List์—์„œ ์ง€์šฐ๋ ค๋Š” ๋…ธ๋“œ์˜ ๋ฐ”๋กœ ์ด์ „ ๋…ธ๋“œ๋กœ ๋ฐ”๋กœ ์ ‘๊ทผํ•˜๊ธฐ ์œ„ํ•œ ๋น ๋ฅธ ๋ฐฉ๋ฒ•์ด ์—†๊ธฐ ๋•Œ๋ฌธ์— head์—์„œ ๋ฉ€๋ฆฌ ์žˆ๋Š” ๋…ธ๋“œ๋ฅผ ์ง€์šฐ๋Š” ๊ฒƒ์€ ์‹œ๊ฐ„์ด ๋งŽ์ด ์†Œ๋ชจ๋œ๋‹ค.

Linked List์—์„œ ์•ž ๋ฐฉํ–ฅ๊ณผ ๋ฐ˜๋Œ€ ๋ฐฉํ–ฅ ๋“ฑ ์–‘ ๋ฐฉํ–ฅ์œผ๋กœ ํƒ์ƒ‰์„ ๊ฐ€๋Šฅ์ผ€ ํ•ด์ฃผ๋Š” Linked List์˜ ์ข…๋ฅ˜๊ฐ€ ์žˆ๋‹ค. Doubly Linked List๋Š” ์›์†Œ ๋ฉค๋ฒ„ ์ด์™ธ์—, ๋ฆฌ์ŠคํŠธ์˜ ๋‹ค์Œ ๋…ธ๋“œ์™€ ์ด์ „ ๋…ธ๋“œ๋ฅผ ๊ฐ๊ฐ ๊ฐ€๋ฆฌํ‚ค๋Š” next ๋งํฌ์™€ prev ๋งํฌ๋ฅผ ๊ฐ€์ง„๋‹ค. ์ด๋Ÿฌํ•œ ๋ฆฌ์ŠคํŠธ๊ธ€์€ ์–ด๋Š ์œ„์น˜์—์„œ๋“  ํšจ์œจ์ ์ธ ์‚ฝ์ž… ๋ฐ ์ œ๊ฑฐ๋ฅผ ํฌํ•จํ•œ ๋‹ค์–‘ํ•œ ๋น ๋ฅธ ์—…๋ฐ์ดํŠธ ์—ฐ์‚ฐ์„ ์ œ๊ณตํ•œ๋‹ค.

Insertion

IMG_0AC93EA9E87B-1

Time Complexity : O(n+1) = O(n)

(3) Circularly Linked List

Queue with a Circularly Linked List

์šฉ์–ด๋“ค์€ ๊ตฌํ˜„์— ๋”ฐ๋ผ ์ฐจ์ด๊ฐ€ ์žˆ์„ ์ˆ˜ ์žˆ๋‹ค.

C++ Implementation
#include <string>
using std::string;

// Code Fragment 3.28 : A node of a circularly linked list.
typedef string Elem; // element type
class CNode
{ // circularly linked list node
private:
    Elem elem;               // linked list element value
    CNode *next;             // next item in the list
    friend class CircleList; // provide CircleList access
};

// Code Fragment 3.29: Implementation of a circularly linked list class.
class CircleList
{ // a circularly linked list
public:
    CircleList();              // constructor
    ~CircleList();             // destructor
    bool empty() const;        // is list empty?
    const Elem &front() const; // element at cursor
    const Elem &back() const;  // element following cursor
    void advance();            // advance cursor
    void add(const Elem &e);   // add after cursor
    void remove();             // remove node after cursor
private:
    CNode *cursor; // the cursor
};

// Code Fragment 3.30: The constructor and destructor.
CircleList::CircleList() // constructor
    : cursor(NULL)
{
}
CircleList::~CircleList() // destructor
{
    while (!empty())
        remove();
}

// Code Fragment 3.31: Simple member functions.
bool CircleList::empty() const // is list empty?
{
    return cursor == NULL;
}
const Elem &CircleList::back() const // element at cursor
{
    return cursor->elem;
}
const Elem &CircleList::front() const // element following cursor
{
    return cursor->next->elem;
}
void CircleList::advance() // advance cursor
{
    cursor = cursor->next;
}

// Code Fragment 3.32: Inserting a node just after the cursor of a circularly linked list.
void CircleList::add(const Elem &e)
{                         // add after cursor
    CNode *v = new CNode; // create a new node
    v->elem = e;
    if (cursor == NULL)
    {                // list is empty?
        v->next = v; // v points to itself
        cursor = v;  // cursor points to v
    }
    else
    {                           // list is nonempty?
        v->next = cursor->next; // link in v after cursor
        cursor->next = v;
    }
}

// Code Fragment 3.33: Removing the node following the cursor
void CircleList::remove()
{                              // remove node after cursor
    CNode *old = cursor->next; // the node being removed
    if (old == cursor)         // removing the only node?
        cursor = NULL;         // list is now empty
    else
        cursor->next = old->next; // link out the old node
    delete old;                   // delete the old node
}