๐Ÿ—ฃ๏ธ ์‹ ์ž… ์ธํ„ฐ๋ทฐ/C++

์‹ ์ž… ๊ฐœ๋ฐœ์ž ๊ธฐ์ˆ ๋ฉด์ ‘ C++ ์†์ฝ”๋”ฉ : Array, Vector, List, Stack, Queue, Tree, Heap, Hash ๋ชจ๋“ˆ ์—†์ด ๊ตฌํ˜„

์ซ€๋ƒ  2024. 1. 1. 22:35

https://www.hackerearth.com/practice/notes/big-o-cheatsheet-series-data-structures-and-algorithms-with-thier-complexities-1/
C++ Data Structure's RunTime CheatSheet

 

 

1. Vector, List, Map ์— ๋Œ€ํ•ด์„œ ์„ค๋ช…ํ•ด ๋ณด์„ธ์š”.

stl์— ๋“ฑ๋ก๋˜์–ด ์žˆ๋Š” ์ž๋ฃŒ๊ตฌ์กฐ๋“ค๋กœ์„œ vector๋Š” ๋™์ ๋ฐฐ์—ด๋กœ ์ด๋ฃจ์–ด์ ธ ์žˆ์œผ๋ฉฐ, List๋Š” ๋”๋ธ”๋งํฌ๋“œ ๋ฆฌ์ŠคํŠธ๋กœ ์ด๋ฃจ์–ด์ ธ์žˆ์Šต๋‹ˆ๋‹ค. Map์„ Key์™€ Value๋ฅผ ์Œ์œผ๋กœ ์ด๋ฃจ๋ฉฐ ๋ ˆ๋“œ๋ธ”๋ž™ํŠธ๋ฆฌ ์•Œ๊ณ ๋ฆฌ์ฆ˜์œผ๋กœ ์ด๋ฃจ์–ด์ ธ ์žˆ์–ด์„œ ๋น ๋ฅธ ํƒ์ƒ‰์†๋„๋ฅผ ์ž๋ž‘ํ•ฉ๋‹ˆ๋‹ค.

 

2. Vector, List ์˜ ์ฐจ์ด์— ๋Œ€ํ•ด์„œ ์„ค๋ช…ํ•˜์„ธ์š”.

vector๋Š” ๋™์ ๋ฐฐ์—ด์˜ ํด๋ž˜์Šค ํƒฌํ”Œ๋ฆฟ์ด๋ผ๊ณ  ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

vector๊ฐ์ฒด๋Š” ์š”์†Œ๊ฐ€ ์ถ”๊ฐ€๋˜๊ฑฐ๋‚˜ ์‚ญ์ œ๋  ๋•Œ๋งˆ๋‹ค ์ž๋™์œผ๋กœ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ์žฌํ• ๋‹นํ•˜์—ฌ ํฌ๊ธฐ๋ฅผ ๋™์ ์œผ๋กœ ๋ณ€๊ฒฝํ•ฉ๋‹ˆ๋‹ค.

 

list๋Š” ์ด์ค‘์—ฐ๊ฒฐ๋ฆฌ์ŠคํŠธ์˜ ํด๋ž˜์Šค ํƒฌํ”Œ๋ฆฟ์ด๋ผ๊ณ  ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. 

์ด ์ปจํ…Œ์ด๋„ˆ๋Š” ๋ชจ๋“  ์š”์†Œ์—์„œ ์–‘๋ฐฉํ–ฅ ์ ‘๊ทผ, ๋น ๋ฅธ ์‚ฝ์ž…๊ณผ ์‚ญ์ œ๋ฅผ ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ์ž„์˜ ์ ‘๊ทผ์€ ๋ถˆ๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

๋˜ํ•œ ๋ฆฌ์ŠคํŠธ๋ฅผ ๊ตฌ์„ฑํ•˜๋Š” ๋งํฌ(link)๋Š” ํฌ์ธํ„ฐ์ด๋ฏ€๋กœ, ๋‹ค์Œ๊ณผ ๊ฐ™์€ ํŠน์ • ์ž‘์—…์„ ๋งํฌ๋งŒ ์žฌ๋ฐฐ์น˜ํ•˜๋Š” ๊ฒƒ์œผ๋กœ ์•„์ฃผ ๋น ๋ฅด๊ฒŒ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

3. Tree ์— ๋Œ€ํ•ด์„œ ์•„๋Š”๋Œ€๋กœ ๋งํ•˜์‹œ์˜ค.

ํŠธ๋ฆฌ๋Š” ํƒ์ƒ‰์—์„œ์˜ ๋›ฐ์–ด๋‚œ ์„ฑ๋Šฅ์„ ๊ฐ€์ง„ ์ปจํ…Œ์ด๋„ˆ๋กœ์„œ ๊ณ„์ธต์ ์ธ ๋ฐ์ดํ„ฐ ๊ฒ€์ƒ‰์— ์••๋„์ ์ธ ์„ฑ๋Šฅ์„ ๋ณด์ž…๋‹ˆ๋‹ค.

์ด์ง„ํŠธ๋ฆฌ ๋ ˆ๋“œ๋ธ”๋ž™ํŠธ๋ฆฌ, ์„ธ๊ทธ๋จผํŠธ ํŠธ๋ฆฌ, AVLํŠธ๋ฆฌ ๋“ฑ ์—ฌ๋Ÿฌ ์ข…๋ฅ˜์˜ ํŠธ๋ฆฌ๊ฐ€ ์žˆ๊ณ , 

์ด์ง„ํŠธ๋ฆฌ๋Š” ๊ฐ๊ฐ์˜ ๋…ธ๋“œ๊ฐ€ ์ตœ๋Œ€ ๋‘๊ฐœ์˜ ์ž์‹๋…ธ๋“œ๋ฅผ ๊ฐ€์ง€๋Š” ํŠธ๋ฆฌ ๊ตฌ์กฐ๋กœ์„œ

๋…ธ๋“œ๋‹น ๋‘๊ฐœ์˜ ์ž์‹๋…ธ๋“œ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ์™„์ „์ด์ง„ํŠธ๋ฆฌ๋กœ ๊ตฌ์„ฑ์ด ๋œ๋‹ค๋ฉด ์•„์ฃผ ์ข‹์€ ํŠธ๋ฆฌ๊ฐ€ ๋˜์ง€๋งŒ, ๊ทธ๋ ‡์ง€ ์•Š์€ ๊ฒฝ์šฐ์—๋Š” ํŠธ๋ฆฌ๋ฅผ ์“ฐ๋Š๋‹ˆ๋งŒ ๋ชปํ•œ ๊ฒฐ๊ณผ๋ฅผ ์ดˆ๋ž˜ ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด๋Ÿฌํ•œ ๋‹จ์ ์„ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด์„œ ๋ฐœ์ „๋œ ํ˜•ํƒœ๊ฐ€ ๋ ˆ๋“œ๋ธ”๋ž™ํŠธ๋ฆฌ๊ฐ€ ์žˆ๋Š”๊ฒƒ์œผ๋กœ ์•Œ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.


Array

C++์—์„œ ๊ณ ์ • ํฌ๊ธฐ์˜ ๋ฐฐ์—ด์€ ๊ธฐ๋ณธ์ ์œผ๋กœ ์ง€์›๋ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์–ด ๋‹ค๋ฃจ๋Š” ๊ฒƒ์„ ์›ํ•œ๋‹ค๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๊ฐ„๋‹จํ•˜๊ฒŒ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. C++์—์„œ๋Š” ๊ณ ์ • ํฌ๊ธฐ ๋ฐฐ์—ด์ด ์ž๋™์œผ๋กœ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๊ด€๋ฆฌํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋ณ„๋„์˜ ์†Œ๋ฉธ์ž๊ฐ€ ํ•„์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

template<typename T, size_t S>
class StaticArray {
private:
    T m_Array[S]; // ๊ณ ์ • ํฌ๊ธฐ์˜ ๋ฐฐ์—ด

public:
    T& operator[](size_t index) {
        return m_Array[index];
    }

    const T& operator[](size_t index) const {
        return m_Array[index];
    }

    size_t Size() const { return S; }
};

 

Vector

std::vector์™€ ๊ฐ™์€ ๋™์  ๋ฐฐ์—ด์„ ๊ฐ„๋‹จํ•˜๊ฒŒ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ์€ ์กฐ๊ธˆ ๋” ๋ณต์žกํ•˜์ง€๋งŒ, ๋‹ค์Œ์€ ๊ทธ ๊ธฐ๋ณธ์ ์ธ ํ˜•ํƒœ์ž…๋‹ˆ๋‹ค.

template<typename T>
class Vector {
private:
    T* data;
    size_t capacity;
    size_t size;

    void reallocate(size_t newCapacity) {
        T* newData = new T[newCapacity];
        size_t newSize = size > newCapacity ? newCapacity : size;
        for (size_t i = 0; i < newSize; ++i) {
            newData[i] = std::move(data[i]);
        }
        delete[] data;
        data = newData;
        capacity = newCapacity;
        size = newSize;
    }

public:
    Vector() : data(nullptr), capacity(0), size(0) {}

    void push_back(const T& value) {
        if (size >= capacity) {
            size_t newCapacity = capacity == 0 ? 1 : capacity * 2;
            reallocate(newCapacity);
        }
        data[size++] = value;
    }

    ~Vector() {
        delete[] data;
    }
};

 

List

์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ๋Š” ๋…ธ๋“œ๋“ค์ด ํฌ์ธํ„ฐ๋ฅผ ํ†ตํ•ด ์—ฐ๊ฒฐ๋˜์–ด ์žˆ๋Š” ๊ตฌ์กฐ์ž…๋‹ˆ๋‹ค. ๋‹ค์Œ์€ ๋‹จ์ˆœ ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ(Singly Linked List)์˜ ๊ธฐ๋ณธ์ ์ธ ๊ตฌํ˜„์ž…๋‹ˆ๋‹ค.

template<typename T>
class List {
private:
    struct Node {
        T value;
        Node* next;
        Node(const T& val) : value(val), next(nullptr) {}
    };

    Node* head;

public:
    List() : head(nullptr) {}

    void push_front(const T& value) {
        Node* newNode = new Node(value);
        newNode->next = head;
        head = newNode;
    }

    ~List() {
        Node* current = head;
        while (current != nullptr) {
            Node* temp = current;
            current = current->next;
            delete temp;
        }
    }
};

 

Stack

Stack์€ LIFO(Last In, First Out) ์ •์ฑ…์„ ๋”ฐ๋ฅด๋Š” ์ž๋ฃŒ๊ตฌ์กฐ๋กœ, ๊ฐ€์žฅ ๋งˆ์ง€๋ง‰์— ๋“ค์–ด์˜จ ์š”์†Œ๊ฐ€ ๊ฐ€์žฅ ๋จผ์ € ๋‚˜๊ฐ‘๋‹ˆ๋‹ค. ๋ฐฐ์—ด์„ ์‚ฌ์šฉํ•˜์—ฌ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

template<typename T>
class Stack {
private:
    struct Node {
        T value;
        Node* next;
        Node(const T& val) : value(val), next(nullptr) {}
    };

    Node* topNode;

public:
    Stack() : topNode(nullptr) {}

    void push(const T& value) {
        Node* newNode = new Node(value);
        newNode->next = topNode;
        topNode = newNode;
    }

    ~Stack() {
        while (topNode != nullptr) {
            Node* temp = topNode;
            topNode = topNode->next;
            delete temp;
        }
    }
};

Queue

Queue๋Š” FIFO(First In, First Out) ์ •์ฑ…์„ ๋”ฐ๋ฅด๋Š” ์ž๋ฃŒ๊ตฌ์กฐ๋กœ, ๊ฐ€์žฅ ๋จผ์ € ๋“ค์–ด์˜จ ์š”์†Œ๊ฐ€ ๊ฐ€์žฅ ๋จผ์ € ๋‚˜๊ฐ‘๋‹ˆ๋‹ค. ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

template<typename T>
class Queue {
private:
    struct Node {
        T value;
        Node* next;
        Node(const T& val) : value(val), next(nullptr) {}
    };

    Node* frontNode;
    Node* backNode;

public:
    Queue() : frontNode(nullptr), backNode(nullptr) {}

    void enqueue(const T& value) {
        Node* newNode = new Node(value);
        if (backNode) {
            backNode->next = newNode;
        }
        backNode = newNode;
        if (!frontNode) {
            frontNode = backNode;
        }
    }

    ~Queue() {
        while (frontNode != nullptr) {
            Node* temp = frontNode;
            frontNode = frontNode->next;
            delete temp;
        }
    }
};

Binary Tree

template<typename T>
class BinaryTree {
private:
    struct Node {
        T value;
        Node *left, *right;

        Node(T val) : value(val), left(nullptr), right(nullptr) {}
    };

    Node* root;

    void Clear(Node* node) {
        if (node != nullptr) {
            Clear(node->left);
            Clear(node->right);
            delete node;
        }
    }

public:
    BinaryTree() : root(nullptr) {}

    // ์ด์ง„ ํŠธ๋ฆฌ์— ์š”์†Œ๋ฅผ ์‚ฝ์ž…ํ•˜๊ณ  ์‚ญ์ œํ•˜๋Š” ๋“ฑ์˜ ๋ฉ”์„œ๋“œ ๊ตฌํ˜„ ํ•„์š”

    ~BinaryTree() {
        Clear(root);
    }
};

Binary Heap

์ด์ง„ ํž™์€ ๋ฐฐ์—ด์„ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•˜๋Š” ์™„์ „ ์ด์ง„ ํŠธ๋ฆฌ์ž…๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ๋Š” ์ตœ๋Œ€ ํž™(Max Heap)์˜ ๊ฐ„๋‹จํ•œ ๊ตฌํ˜„์„ ๋ณด์—ฌ๋“œ๋ฆฝ๋‹ˆ๋‹ค.

template<typename T>
class BinaryHeap {
private:
    std::vector<T> heap;

    void HeapifyDown(int index) {
        int left = 2 * index + 1;
        int right = 2 * index + 2;
        int largest = index;

        if (left < heap.size() && heap[left] > heap[largest])
            largest = left;
        if (right < heap.size() && heap[right] > heap[largest])
            largest = right;

        if (largest != index) {
            std::swap(heap[index], heap[largest]);
            HeapifyDown(largest);
        }
    }

    void HeapifyUp(int index) {
        while (index != 0 && heap[(index - 1) / 2] < heap[index]) {
            std::swap(heap[(index - 1) / 2], heap[index]);
            index = (index - 1) / 2;
        }
    }

public:
    void Insert(T element) {
        heap.push_back(element);
        HeapifyUp(heap.size() - 1);
    }

    T ExtractMax() {
        if (heap.size() == 0)
            throw std::out_of_range("Heap is empty");

        T root_value = heap[0];
        heap[0] = heap.back();
        heap.pop_back();
        HeapifyDown(0);
        return root_value;
    }

    bool IsEmpty() const {
        return heap.empty();
    }
};

Binary Search Tree

์ด์ง„ ํƒ์ƒ‰ ํŠธ๋ฆฌ

template<typename T>
class BinarySearchTree {
private:
    struct Node {
        T value;
        Node *left, *right;

        Node(const T& val) : value(val), left(nullptr), right(nullptr) {}
    };

    Node* root;

    void clear(Node* node) {
        if (node) {
            clear(node->left);
            clear(node->right);
            delete node;
        }
    }

public:
    BinarySearchTree() : root(nullptr) {}

    ~BinarySearchTree() {
        clear(root);
    }
};

Priority Queue - Max Heap

MaxPriorityQueue ํด๋ž˜์Šค๋Š” ์š”์†Œ๋ฅผ ๋‚ด๋ฆผ์ฐจ์ˆœ์œผ๋กœ ์ •๋ ฌํ•˜์—ฌ, ๊ฐ€์žฅ ํฐ ์š”์†Œ๊ฐ€ ํ•ญ์ƒ ๋งจ ์•ž์— ์˜ค๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.

heapifyUp๊ณผ heapifyDown ๋ฉ”์„œ๋“œ๋Š” ํž™ ์†์„ฑ์„ ์œ ์ง€ํ•˜๊ธฐ ์œ„ํ•ด ์š”์†Œ๋ฅผ ์ ์ ˆํ•œ ์œ„์น˜๋กœ ์ด๋™์‹œํ‚ต๋‹ˆ๋‹ค. push ๋ฉ”์„œ๋“œ๋Š” ์ƒˆ๋กœ์šด ์š”์†Œ๋ฅผ ํž™์— ์ถ”๊ฐ€ํ•˜๊ณ , pop ๋ฉ”์„œ๋“œ๋Š” ํž™์—์„œ ์ตœ๋Œ“๊ฐ’ ๋˜๋Š” ์ตœ์†Ÿ๊ฐ’์„ ์ œ๊ฑฐํ•˜๊ณ  ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. top ๋ฉ”์„œ๋“œ๋Š” ํž™์˜ ์ตœ๋Œ“๊ฐ’ ๋˜๋Š” ์ตœ์†Ÿ๊ฐ’์„ ์กฐํšŒํ•˜์ง€๋งŒ ์ œ๊ฑฐํ•˜์ง€๋Š” ์•Š์Šต๋‹ˆ๋‹ค. empty์™€ size ๋ฉ”์„œ๋“œ๋Š” ํž™์ด ๋น„์–ด ์žˆ๋Š”์ง€ ์—ฌ๋ถ€๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ณ , ํž™์˜ ํฌ๊ธฐ๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

#include <vector>
#include <algorithm> // For std::swap
#include <stdexcept> // For std::out_of_range

template<typename T>
class MaxPriorityQueue {
private:
    std::vector<T> heap;

    void heapifyDown(int currentIdx) {
        int leftIdx = 2 * currentIdx + 1;
        int rightIdx = 2 * currentIdx + 2;
        int largestIdx = currentIdx;

        if (leftIdx < heap.size() && heap[leftIdx] > heap[largestIdx]) {
            largestIdx = leftIdx;
        }

        if (rightIdx < heap.size() && heap[rightIdx] > heap[largestIdx]) {
            largestIdx = rightIdx;
        }

        if (largestIdx != currentIdx) {
            std::swap(heap[currentIdx], heap[largestIdx]);
            heapifyDown(largestIdx);
        }
    }

    void heapifyUp(int currentIdx) {
        while (currentIdx != 0 && heap[(currentIdx - 1) / 2] < heap[currentIdx]) {
            std::swap(heap[(currentIdx - 1) / 2], heap[currentIdx]);
            currentIdx = (currentIdx - 1) / 2;
        }
    }

public:
    void push(const T& value) {
        heap.push_back(value);
        heapifyUp(heap.size() - 1);
    }

    T pop() {
        if (heap.empty()) throw std::out_of_range("PriorityQueue is empty");

        T maxValue = heap[0];
        heap[0] = heap.back();
        heap.pop_back();
        heapifyDown(0);
        return maxValue;
    }

    const T& top() const {
        if (heap.empty()) throw std::out_of_range("PriorityQueue is empty");
        return heap[0];
    }

    bool empty() const {
        return heap.empty();
    }

    size_t size() const {
        return heap.size();
    }
};

Priority Queue - Min Heap

Priority Queue๋Š” ๋‚ด๋ถ€์ ์œผ๋กœ ๋ณดํ†ต ์ด์ง„ ํž™(Binary Heap) ๊ตฌ์กฐ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. C++์—์„œ๋Š” ์ด๋ฅผ std::vector๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ๊ธฐ๋ณธ์ ์œผ๋กœ ์ตœ๋Œ€ ํž™(Max Heap)์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

 

MinPriorityQueue ํด๋ž˜์Šค๋Š” ์š”์†Œ๋ฅผ ์˜ค๋ฆ„์ฐจ์ˆœ์œผ๋กœ ์ •๋ ฌํ•˜์—ฌ, ๊ฐ€์žฅ ์ž‘์€ ์š”์†Œ๊ฐ€ ํ•ญ์ƒ ๋งจ ์•ž์— ์˜ค๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.

heapifyUp๊ณผ heapifyDown ๋ฉ”์„œ๋“œ๋Š” ํž™ ์†์„ฑ์„ ์œ ์ง€ํ•˜๊ธฐ ์œ„ํ•ด ์š”์†Œ๋ฅผ ์ ์ ˆํ•œ ์œ„์น˜๋กœ ์ด๋™์‹œํ‚ต๋‹ˆ๋‹ค. push ๋ฉ”์„œ๋“œ๋Š” ์ƒˆ๋กœ์šด ์š”์†Œ๋ฅผ ํž™์— ์ถ”๊ฐ€ํ•˜๊ณ , pop ๋ฉ”์„œ๋“œ๋Š” ํž™์—์„œ ์ตœ๋Œ“๊ฐ’ ๋˜๋Š” ์ตœ์†Ÿ๊ฐ’์„ ์ œ๊ฑฐํ•˜๊ณ  ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. top ๋ฉ”์„œ๋“œ๋Š” ํž™์˜ ์ตœ๋Œ“๊ฐ’ ๋˜๋Š” ์ตœ์†Ÿ๊ฐ’์„ ์กฐํšŒํ•˜์ง€๋งŒ ์ œ๊ฑฐํ•˜์ง€๋Š” ์•Š์Šต๋‹ˆ๋‹ค. empty์™€ size ๋ฉ”์„œ๋“œ๋Š” ํž™์ด ๋น„์–ด ์žˆ๋Š”์ง€ ์—ฌ๋ถ€๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ณ , ํž™์˜ ํฌ๊ธฐ๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

#include <vector>
#include <algorithm> // For std::swap
#include <stdexcept> // For std::out_of_range

template<typename T>
class MinPriorityQueue {
private:
    std::vector<T> heap;

    void heapifyDown(int currentIdx) {
        int leftIdx = 2 * currentIdx + 1;
        int rightIdx = 2 * currentIdx + 2;
        int smallestIdx = currentIdx;

        if (leftIdx < heap.size() && heap[leftIdx] < heap[smallestIdx]) {
            smallestIdx = leftIdx;
        }

        if (rightIdx < heap.size() && heap[rightIdx] < heap[smallestIdx]) {
            smallestIdx = rightIdx;
        }

        if (smallestIdx != currentIdx) {
            std::swap(heap[currentIdx], heap[smallestIdx]);
            heapifyDown(smallestIdx);
        }
    }

    void heapifyUp(int currentIdx) {
        while (currentIdx != 0 && heap[(currentIdx - 1) / 2] > heap[currentIdx]) {
            std::swap(heap[(currentIdx - 1) / 2], heap[currentIdx]);
            currentIdx = (currentIdx - 1) / 2;
        }
    }

public:
    void push(const T& value) {
        heap.push_back(value);
        heapifyUp(heap.size() - 1);
    }

    T pop() {
        if (heap.empty()) throw std::out_of_range("PriorityQueue is empty");

        T minValue = heap[0];
        heap[0] = heap.back();
        heap.pop_back();
        heapifyDown(0);
        return minValue;
    }

    const T& top() const {
        if (heap.empty()) throw std::out_of_range("PriorityQueue is empty");
        return heap[0];
    }

    bool empty() const {
        return heap.empty();
    }

    size_t size() const {
        return heap.size();
    }
};

 

Unordered Map

template<typename KeyType, typename ValueType>
class UnorderedMap {
private:
    struct Node {
        KeyType key;
        ValueType value;
        Node* next;

        Node(const KeyType& key, const ValueType& value) : key(key), value(value), next(nullptr) {}
    };

    std::vector<Node*> buckets;
    size_t bucketCount;

    size_t GetBucketIndex(const KeyType& key) const {
        std::hash<KeyType> hashFn;
        return hashFn(key) % bucketCount;
    }

public:
    UnorderedMap(size_t numBuckets) : bucketCount(numBuckets) {
        buckets.resize(bucketCount, nullptr);
    }

    void insert(const KeyType& key, const ValueType& value) {
        size_t bucketIdx = GetBucketIndex(key);
        Node* newNode = new Node(key, value);
        newNode->next = buckets[bucketIdx];
        buckets[bucketIdx] = newNode;
    }

    // UnorderedMap์˜ ๋‚˜๋จธ์ง€ ๊ตฌํ˜„ ๋ถ€๋ถ„ (๊ฒ€์ƒ‰, ์‚ญ์ œ ๋“ฑ)

    ~UnorderedMap() {
        for (Node* head : buckets) {
            while (head != nullptr) {
                Node* temp = head;
                head = head->next;
                delete temp;
            }
        }
    }
};

 

๋ฒˆ์™ธ) Unordered Map UPGRADE

์—ฌ๊ธฐ์„œ๋Š” ์ฒด์ด๋‹ ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•˜์—ฌ ์ถฉ๋Œ์„ ํ•ด๊ฒฐํ•˜๋Š” ๊ธฐ๋ณธ์ ์ธ unordered_map์„ ๊ตฌํ˜„ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ์ด ๊ตฌํ˜„์€ ํ•ด์‹œ ํ…Œ์ด๋ธ”์˜ ํ•ต์‹ฌ ์•„์ด๋””์–ด๋ฅผ ํฌํ•จํ•˜์ง€๋งŒ, ์‹ค์ œ ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ์—์„œ ์‚ฌ์šฉํ•˜๊ธฐ์—๋Š” ๋” ๋งŽ์€ ์ตœ์ ํ™”์™€ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

 

์ด ์ฝ”๋“œ๋Š” UnorderedMap์„ ์œ„ํ•œ ๊ธฐ๋ณธ์ ์ธ ๊ตฌํ˜„์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

  • ์ฒด์ด๋‹(Chaining): ๊ฐ ๋ฒ„ํ‚ท์€ std::list<KeyValuePair>๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ‚ค-๊ฐ’ ์Œ์„ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ํ•ด์‹œ ์ถฉ๋Œ์„ ํ•ด๊ฒฐํ•ฉ๋‹ˆ๋‹ค.
  • ํ•ด์‹œ ํ•จ์ˆ˜(Hash Function): ๊ธฐ๋ณธ ํ•ด์‹œ ํ•จ์ˆ˜๋กœ std::hash<KeyType>๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ์‚ฌ์šฉ์ž ์ •์˜ ํƒ€์ž…์— ๋Œ€ํ•ด ํŠน์ˆ˜ํ™”๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์žฌํ•ด์‹œ(Rehashing): ์š”์†Œ์˜ ์ˆ˜๊ฐ€ ๋ฒ„ํ‚ท์˜ ์ˆ˜์˜ 75%๋ฅผ ์ดˆ๊ณผํ•˜๋ฉด, ๋ฒ„ํ‚ท ๋ฐฐ์—ด์˜ ํฌ๊ธฐ๋ฅผ ๋‘ ๋ฐฐ๋กœ ๋Š˜๋ฆฝ๋‹ˆ๋‹ค.

insert, at, size, contains ๋“ฑ์˜ ๊ธฐ๋ณธ์ ์ธ ๋ฉ”์„œ๋“œ๋ฅผ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค. ์‹ค์ œ ์‚ฌ์šฉ์„ ์œ„ํ•ด์„œ๋Š” ๋” ๋งŽ์€ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ, ์ดํ„ฐ๋ ˆ์ดํ„ฐ ์ง€์›, ๋ณต์‚ฌ ๋ฐ ์ด๋™ ์ƒ์„ฑ์ž ๋ฐ ํ• ๋‹น ์—ฐ์‚ฐ์ž์˜ ๊ตฌํ˜„ ๋“ฑ์ด ํ•„์š”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

#include <list>
#include <vector>
#include <functional>
#include <stdexcept>

template<typename KeyType, typename ValueType, typename Hash = std::hash<KeyType>>
class UnorderedMap {
private:
    struct KeyValuePair {
        KeyType key;
        ValueType value;
        KeyValuePair(const KeyType& key, const ValueType& value) : key(key), value(value) {}
    };

    std::vector<std::list<KeyValuePair>> buckets;
    Hash hasher;
    size_t numElements;

    size_t getBucketIndex(const KeyType& key) const {
        return hasher(key) % buckets.size();
    }

    void rehash(size_t newBucketCount) {
        std::vector<std::list<KeyValuePair>> newBuckets(newBucketCount);
        for (auto& bucket : buckets) {
            for (auto& kv : bucket) {
                size_t newBucketIndex = hasher(kv.key) % newBucketCount;
                newBuckets[newBucketIndex].push_back(kv);
            }
        }
        buckets = std::move(newBuckets);
    }

public:
    UnorderedMap(size_t bucketCount = 8) : buckets(bucketCount), numElements(0) {}

    void insert(const KeyType& key, const ValueType& value) {
        size_t bucketIndex = getBucketIndex(key);
        for (auto& kv : buckets[bucketIndex]) {
            if (kv.key == key) {
                kv.value = value;
                return;
            }
        }
        buckets[bucketIndex].emplace_back(key, value);
        numElements++;

        if (numElements > buckets.size() * 0.75) { // Load factor of 0.75 for rehashing
            rehash(buckets.size() * 2);
        }
    }

    ValueType& at(const KeyType& key) {
        size_t bucketIndex = getBucketIndex(key);
        for (auto& kv : buckets[bucketIndex]) {
            if (kv.key == key) {
                return kv.value;
            }
        }
        throw std::out_of_range("Key not found");
    }

    size_t size() const {
        return numElements;
    }

    bool contains(const KeyType& key) const {
        size_t bucketIndex = getBucketIndex(key);
        for (const auto& kv : buckets[bucketIndex]) {
            if (kv.key == key) {
                return true;
            }
        }
        return false;
    }

    // ์ถ”๊ฐ€์ ์ธ ๋ฉ”์„œ๋“œ (์‚ญ์ œ, ํฌ๊ธฐ ์กฐ์ ˆ ๋“ฑ)๋ฅผ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
};