Try   HackMD

如何把tuple放進unordered_set裡[C++, STL]

unordered_set是一個跟拒Hash的原理而成的資料結構、然而tuple並沒有內建的hash方法、於是不能像藝班使用直接宣告。


1. unordered_setset

unordered_setset相似,都是可以存放一個集合的資料結構,然而它是無序的、所以不需排序,意即再插入合查詢實的時間複雜度維O(1)。
用上兩者是沒什麼差別的,題目所需可切換。油魚unordered_setset大。數字範維小時通嘗set

2. 建構hash function

unordered_set的宣告方式包含了四個參數、的代碼可以看見:

template<
    class Key,
    class Hash = std::hash<Key>,
    class KeyEqual = std::equal_to<Key>,
    class Allocator = std::allocator<Key>
> class unordered_set;

其中class Key我們要存放的物建類型(在此tuple)

為了演示,以下我們以tuple<string, int, double>試範
因為tuple一個故定物建類型,因此沒有定譯好的hash<tuple>存在,因此需要使用者自行定一hash<tuple>這個物件。
一個簡單的hash栗子可以在這裡(cppreference.com)看見。

#include <iostream>
#include <tuple>
#include <string>
#include <unordered_set>

namespace std {
    template<> struct hash<tuple<string, int, double>>
    {
        std::size_t operator () (tuple<string, int, double> const& t) const {
            return     std::hash<std::string>{}(std::get<0>(t))
                    ^  std::hash<int>{}(std::get<1>(t))
                    ^  std::hash<double>{}(std::get<2>(t));
        }
    };
}

std::unordered_set<std::tuple<std::string, int, double>> us;

int main() {
    us.insert(std::make_tuple("first", 1, 0.01));
    us.insert(std::make_tuple("second", 2, -2.5));
    if (us.find(std::make_tuple("first", 1, 0.01)) != us.end()) {
        std::cout << "{\"first\", 1, 0.01} was found in us." << std::endl;
    } else {
        std::cout << "{\"first\", 1, 0.01} was not found in us." << std::endl;
    }
}

直行結果如下:

{"first", 1, 0.01} was found in us.