๐Ÿ“š Hash table

๐Ÿ“š Hash table ์ •๋ฆฌ


๐Ÿ”Ž Hash table์ด๋ž€?

  • ๋ฐ์ดํ„ฐ๋ฅผ ํšจ์œจ์ ์œผ๋กœ ์ €์žฅํ•˜๊ณ  ๊ฒ€์ƒ‰ํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•˜๋Š” ์ž๋ฃŒ๊ตฌ์กฐ
  • ํ‚ค-๊ฐ’(key-value pair) ์Œ์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•˜๋ฉฐ ๋‚ด๋ถ€์ ์œผ๋กœ๋Š” ํ•ด์‹œ ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•ด ํ‚ค๋ฅผ ํŠน์ • ์œ„์น˜์— ๋งคํ•‘ํ•œ๋‹ค.
  • C++ STL(Standard Template Library)์—์„œ๋Š” ์ฃผ๋กœ unordered_map ๊ณผ unordered_set ์œผ๋กœ ํ•ด์‹œํ…Œ์ด๋ธ”์„ ๊ตฌํ˜„ํ•œ๋‹ค.

๐Ÿ’ก ํŠน์ง•

1. ๋น ๋ฅธ ๊ฒ€์ƒ‰

  • ํ‰๊ท ์ ์œผ๋กœ (O(1))์˜ ์‹œ๊ฐ„ ๋ณต์žก๋„๋กœ ๊ฒ€์ƒ‰, ์‚ฝ์ž…, ์‚ญ์ œ๋ฅผ ์ˆ˜ํ–‰ํ•œ๋‹ค. ์ตœ์•…์˜ ๊ฒฝ์šฐ๋Š” ์ถฉ๋Œ์ด ๋งŽ์„ ๋•Œ (O(n))์ด๋‹ค.

2. ํ‚ค- ๊ฐ’(key-value) ์Œ์œผ๋กœ ์ €์žฅ

3. ํ•ด์‹œ ํ•จ์ˆ˜

  • ํ‚ค๋ฅผ ํŠน์ • ๋ฒ„ํ‚ท์œผ๋กœ ๋งคํ•‘ํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋œ๋‹ค. ํ•ด์‹œํ•จ์ˆ˜๊ฐ€ ์ถฉ๋Œ์„ ์ตœ์†Œํ™” ํ• ์ˆ˜๋ก ์„ฑ๋Šฅ์ด ์˜ฌ๋ผ๊ฐ„๋‹ค. **

๐Ÿ’ป ๊ตฌํ˜„

#include <iostream>
#include <string>
#include <unordered_map>

using namespace std;

int main()
{
    unordered_map<string, int> hash_table {
        {"apple", 5},
        {"banana", 3},
        {"pear", 10}
    };

    cout << hash_table["apple"] << endl;

    //๋ชจ๋“  ํ‚ค๊ฐ’ ์ถœ๋ ฅํ•ด๋ณด๊ธฐ
    //์ถœ๋ ฅํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ๋‘๊ฐ€์ง€๊ฐ€ ์กด์žฌ


    // 1. range-based for loop
    for(const auto& pair : hash_table)
    {
        cout << pair.first << " : " << pair.second << endl;
    }

    // 2. iterator
    for(auto it = hash_table.begin(); it != hash_table.end(); it++)
    {
        cout << it->first << " : " << it->second << endl;
    }


    return 0;
}

๐Ÿ’ป ์ฝ”๋“œ ๊ณต๋ถ€

unordered_map<string, int> hash_table {
        {"apple", 5},
        {"banana", 3},
        {"pear", 10}
    };
  • ํ•ด์‹œ ํ…Œ์ด๋ธ”์„ ์ ๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค.
  • unordered_map<key, value> ํ•จ์ˆ˜๋ช… { };
  • ํ•ด์‹œ ํ…Œ์ด๋ธ”์€ ๋ฐ์ดํ„ฐ๋ฅผ ์ž…๋ ฅํ•œ ์ˆœ์„œ๋Œ€๋กœ ์ €์žฅํ•˜์ง€ ์•Š๋Š”๋‹ค. ๊ทธ๋ž˜์„œ ๋งŒ์•ฝ ์ „๋ถ€ ์ถœ๋ ฅํ•œ๋‹ค๋ฉด ๋žœ๋ค์œผ๋กœ ์ •๋ ฌ๋˜์–ด ์ถœ๋ ฅ๋œ๋‹ค.
// 1. range-based for loop
    for(const auto& pair : hash_table)
    {
        cout << pair.first << " : " << pair.second << endl;
    }
  • ๋ฒ”์œ„ ์ง€์ •ํ•ด ๋ฐ˜๋ณตํ•ด์„œ ํ•ด์‹œ ํ…Œ์ด๋ธ” ๊ฐ’๋“ค ์ „๋ถ€ ์ถœ๋ ฅํ•ด๋ณด๊ธฐ
  • auto ๋Š” ์ž๋™ ํƒ€์ž… ์ถ”๋ก ์„ ํ•ด์ฃผ๋Š” ํ‚ค์›Œ๋“œ์ด๋‹ค. ๋ณ€์ˆ˜ ์„ ์–ธ ์‹œ ์ดˆ๊ธฐํ™” ๊ฐ’์˜ ํƒ€์ž…์„ ์ž๋™์œผ๋กœ ์ถ”๋ก ํ•˜์—ฌ ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ๊ฒฐ์ •ํ•œ๋‹ค
  • ๋˜ํ•œ &(reference)๊ฐ€ ๋ถ™์€ ์ด์œ ๋Š” ๋ถˆํ•„์š”ํ•œ ๋ฉ”๋ชจ๋ฆฌ ๋ณต์‚ฌ๋ฅผ ๋ง‰๊ธฐ ์œ„ํ•จ์ด๋‹ค. ๋งŒ์•ฝ hash_table์˜ ํฌ๊ธฐ๊ฐ€ ๋งค์šฐ ํฌ๋‹ค๋ฉด ๋ณต์‚ฌ๋ฅผ ํ•˜๋Š”๋ฐ ๋งŽ์€ ๋ฉ”๋ชจ๋ฆฌ๊ฐ€ ๋‚ญ๋น„๋˜๋ฏ€๋กœ ํ”„๋กœ๊ทธ๋žจ์ด ์ €ํ•˜๋œ๋‹ค. ๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— ์›๋ณธ์„ ์ฐธ์กฐํ•˜๋„๋ก &(reference)๋ฅผ ๋ถ™์—ฌ์ค€๋‹ค.
// 2. iterator
    for(auto it = hash_table.begin(); it != hash_table.end(); it++)
    {
        cout << it->first << " : " << it->second << endl;
    }
  • iterator ๋ฐ˜๋ณต์ž๋ฅผ ํ†ตํ•ด ํ•ด์‹œํ…Œ์ด๋ธ” ์ „๋ถ€ ๋ฝ‘์•„๋ณด๊ธฐ

๐Ÿ›  ์ฃผ์š” ๋ฉ”์†Œ๋“œ

  • insert() : ์‚ฝ์ž… ```cpp #include #include

int main() { std::unordered_map<int, std::string> umap; umap.insert({1, โ€œappleโ€}); umap.insert({2, โ€œbananaโ€});

// ํ‚ค๊ฐ€ ์กด์žฌํ•˜๋ฉด ์‚ฝ์ž…๋˜์ง€ ์•Š์Œ
umap.insert({1, "grape"});

std::cout << umap[1] << std::endl;  // apple
return 0; } ``` ์ƒˆ๋กœ์šด (key, value) ๋ฅผ ์‚ฝ์ž…ํ•œ๋‹ค.
  • operator[] : ํ‚ค๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ ‘๊ทผ
    umap[3] = "cherry";  // ์ƒˆ๋กœ์šด (3, "cherry") ์‚ฝ์ž…
    std::cout << umap[3] << std::endl;  // ์ถœ๋ ฅ: cherry
    

    ํ‚ค๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐ’(value)์— ์ ‘๊ทผ ๋งŒ์•ฝ ํ‚ค๊ฐ€ ์—†๋‹ค๋ฉด ๊ธฐ๋ณธ๊ฐ’์„ ์‚ฝ์ž…ํ•˜๊ณ  ๋ฐ˜ํ™˜

  • emplace() : insert()์™€ ๋น„์Šทํ•˜์ง€๋งŒ ๊ฐ์ฒด๋ฅผ ์ง์ ‘ ์ƒ์„ฑํ•ด์„œ ๋„ฃ์Œ
     // ๋ฐ”๋กœ ์ƒ์„ฑํ•˜๊ณ  ๋ฐ”๋กœ (key, value)๋„ฃ์Œ
    umap.emplace(4, "mango");
    
  • count() : ํŠน์ • ํ‚ค ์กด์žฌ ๊ฒ€์ƒ‰
    if (umap.count(2)) {
      std::cout << "Key 2 exists\n";
    }
    

    ๋ฐ˜ํ™˜๊ฐ’์ด 1 ์ด๋ฉด ์กด์žฌ 0 ์ด๋ฉด ์กด์žฌํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ๋œป

  • find() : ํ‚ค๋ฅผ ์ฐพ์•„ intertor ๋ฐ˜ํ™˜
    auto it = umap.find(2);
    if (it != umap.end()) {
      std::cout << "Key 2 found: " << it->second << std::endl;
    }
    

    ํ‚ค๊ฐ€ ์กด์žฌํ•˜๋ฉด ํ•ด๋‹น ํ‚ค-๊ฐ’์˜ ํฌ์ธํ„ฐ ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ณ  ์—†์œผ๋ฉด operator.end() ๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

  • erase() : ํŠน์ • ํ‚ค ์‚ญ์ œ ```cpp umap.erase(2); // ํ‚ค 2 ์‚ญ์ œ

// ์ดํ„ฐ๋ ˆ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•ด ์‚ญ์ œํ•  ์ˆ˜๋„ ์žˆ์Œ auto it = umap.find(3); if (it != umap.end()) { umap.erase(it); }


- **clear() : ๋ชจ๋“  ์š”์†Œ ์‚ญ์ œ**
```cpp
umap.clear();
  • size() : ํ˜„์žฌ ํ•ด์‰ฌํ…Œ์ด๋ธ”์˜ ์›์†Œ ๊ฐœ์ˆ˜ ๋ฐ˜ํ™˜
    std::cout << "Size: " << umap.size() << std::endl;
    
  • empty() : ๋งต์ด ๋น„์–ด์žˆ๋Š”์ง€ true or false ๋กœ ๋ฐ˜ํ™˜
    if (umap.empty()) {
      std::cout << "Hash table is empty" << std::endl;
    }
    
  • begin(), end() : ์ฒซ ๋ฒˆ์งธ์™€ ๋ ๋‹ค์Œ ์œ„์น˜ ๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” ์ดํ„ฐ๋ ˆ์ดํ„ฐ๋ฅผ ๋ฐ˜ํ™˜

๐Ÿ“Œ ์ •๋ฆฌ

c++ ์—์„œ hash table ์€ unordered_map ๊ณผ unordered_set ์œผ๋กœ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค. ๋น ๋ฅธ ๊ฒ€์ƒ‰, ์‚ฝ์ž…, ์‚ญ์ œ๋ฅผ ์ œ๊ณตํ•˜์ง€๋งŒ ์ถฉ๋Œ๊ณผ ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰ ๊ด€๋ฆฌ๊ฐ€ ์ค‘์š”ํ•œ ์š”์†Œ์ด๋ฉฐ, ๋ฐ์ดํ„ฐ ์ˆœ์„œ๋ฅผ ์œ ์ง€ํ•˜๋ ค๋ฉด map์„ ์‚ฌ์šฉํ•ด์•ผํ•œ๋‹ค. (์—ฌ๊ธฐ์„œ๋Š” unordered_map๋งŒ ๋‹ค๋ค˜๋Š”๋ฐ unordered_set์€ ์ค‘๋ณต๋˜์ง€ ์•Š์€ ๊ณ ์œ ํ•œ ํ‚ค๋งŒ ์ €์žฅํ•˜๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค.)


์ถ”๊ฐ€ ๋‚ด์šฉ(03-06)

  • hash table ์—์„œ ๋งŒ์•ฝ ์ €์žฅ๋˜์–ด ์žˆ์ง€ ์•Š๋Š” ๊ฐ’์ด ๋‚˜์˜จ๋‹ค๋ฉด ์ž๋™์ ์œผ๋กœ 0์˜ ๊ฐ’์œผ๋กœ ์ฒ˜๋ฆฌ ํ•œ๋‹ค

์ถ”๊ฐ€ ๋‚ด์šฉ(03-07)