以上哪种方法最适合你,取决于你的具体需求,如数据的大小、是否动态变化、是数值还是字符串、查找的频率等。
哈希表是一种基于哈希函数的数据结构,能够以接近常数时间(O(1))对数据进行插入、查找和删除操作。
以 std::unordered_map 为例,这是 C++ 中常见的一种哈希表实现。
插入:
当你向 std::unordered_map 中插入一个元素时,这个元素首先会被哈希函数转化为一个哈希值,这个哈希值决定了元素在哈希表中的位置。因此,不需要遍历整个表就可以找到元素应该插入的位置,所以插入的时间复杂度是 O(1)。
查找:
当你查找一个元素时,这个元素同样会被哈希函数转化为一个哈希值,然后直接在哈希表的这个位置查找元素。所以查找的时间复杂度同样是 O(1)。
删除:
和查找类似,你可以快速定位到要删除的元素,因此删除操作的时间复杂度也是 O(1)。
然而,实际上,这种 O(1) 的时间复杂度是平均时间复杂度。在最坏的情况下,如果多个元素哈希到了同一个位置(这种情况称为哈希冲突),这些元素会以链表的形式存储,此时的查找、插入和删除操作的时间复杂度会退化为 O(N)。
但是,如果哈希函数选得好,哈希冲突的概率会很低,所以在实际使用中,哈希表的操作效率通常都接近 O(1)。
如果你有一个需要频繁执行查找操作的应用,那么哈希表可能会是一个很好的选择。
std::unordered_map 和 std::unordered_set 都是 C++ 标准库中的哈希表实现,它们都能在平均 O(1) 时间复杂度内进行插入、查找和删除操作。不过,它们有一些主要的区别:
std::unordered_map 是一个关联容器,每个元素都是一个键值对,键和值可以是不同的类型。键在 unordered_map 中是唯一的。你可以用键来快速找到对应的值。这种数据结构适合于需要建立对象之间一对一映射关系的情况。
std::unordered_map<std::string, int> um;
um["apple"] = 1;
um["banana"] = 2;
int apple_value = um["apple"]; // apple_value is 1
相反,std::unordered_set 只存储单个元素,而不是键值对。它通常用于检查元素是否存在,或者确保元素的唯一性。
std::unordered_set<int> us;
us.insert(1);
us.insert(2);
bool exists = us.find(1) != us.end(); // exists is true
在内部实现上,std::unordered_map 和 std::unordered_set 都使用哈希表。键或元素的哈希值决定了它在哈希表中的位置。如果两个键或元素的哈希值相同,就会发生哈希冲突,需要用链表等方法解决。
如果你需要使用多个元素作为键来检查其是否存在于 unordered_map 中,你可以使用 pair 或者 tuple,或者自定义的结构体或者类作为 unordered_map 的键。不过要注意,你需要自定义相应的哈希函数。以下是一些例子:
#include
struct pair_hash {
template <class T1, class T2>
std::size_t operator () (const std::pair<T1,T2> &p) const {
auto h1 = std::hash<T1>{}(p.first);
auto h2 = std::hash<T2>{}(p.second);
// Mainly for demonstration purposes, i.e. works but is overly simple
// In the real world, use sth. like boost.hash_combine
return h1 ^ h2;
}
};
std::unordered_map<std::pair<int, int>, int, pair_hash> um;
#include
struct tuple_hash {
template <class T1, class T2, class T3>
std::size_t operator () (const std::tuple<T1,T2,T3> &t) const {
auto h1 = std::hash<T1>{}(std::get<0>(t));
auto h2 = std::hash<T2>{}(std::get<1>(t));
auto h3 = std::hash<T3>{}(std::get<2>(t));
return h1 ^ h2 ^ h3;
}
};
std::unordered_map<std::tuple<int, int, int>, int, tuple_hash> um;
#include
struct my_key {
int x;
int y;
bool operator==(const my_key &other) const {
return x == other.x && y == other.y;
}
};
struct my_key_hash {
std::size_t operator()(const my_key& k) const {
return std::hash<int>()(k.x) ^ std::hash<int>()(k.y);
}
};
std::unordered_map<my_key, int, my_key_hash> um;
来源 :ChatGPT-4