一、unordered_map unordered_set 和 map set的区别
1. map set底层采取的红黑树的结构,unordered_xxx 底层数据结构是哈希表。unordered_map容器通过key访问单个元素要比map快,但它通常在遍历元素子集的范围迭代方面效率较低。
2. Java中对应的容器名为 HashMap HashSet TreeMap TreeSet,命名方面比C++好了很多。主要是早期C++并没有实现哈希结构的容器(C++11之前),也就是unordered系列,在C++11中新增了unordered_map,unordered_set,unordered_multimap,unordered_multiset,故因为历史命名问题,取了这样的名字。
3. 它们的使用大体上几乎一致。显著的差别是:
a、map和set为双向迭代器,unordered_xxx和是单向迭代器。
b、map和set存储为有序存储(红黑树结构,中序遍历有序),unordered_xxx为无序存储(哈希表的结构致使)
4. 性能差异:采取哈希表的unordered系列容器在大量数据的增删查改效率更优,尤其是查(搜索)
二、实现代码
HashTable.h
//
// Created by yangzilong on 2022/11/15.
//
#pragma once
#include <utility>
#include <vector>
#include <iostream>
using namespace std;
// 开散列(链地址法)解决哈希表中的哈希冲突
// 哈希表中的结点并不知道自己存储的数据类型,unordered_map为pair,unordered_set为key
template <class T>
struct HashNode
{
HashNode<T>(const T& data)
:_data(data)
{ }
T _data;
HashNode* _next = nullptr;
};
// 哈希表的前置声明,因为迭代器中要用到
template <class , class , class , class , class >
class HashTable;
// 哈希表迭代器,因为数据成员中有哈希表指针,所以这些模板参数都需要
template <class K, class T, class KeyOfT, class Hash, class Equal>
struct __HashTable_Iterator
{
typedef HashNode<T> Node;
typedef HashTable<K, T, KeyOfT, Hash, Equal> HT;
typedef __HashTable_Iterator<K, T, KeyOfT, Hash, Equal> Self;
__HashTable_Iterator(Node* node, HT* ptr)
: _node(node), _tablePtr(ptr)
{ }
bool operator==(const Self& it) const {
return _node == it._node;
}
bool operator!=(const Self& it) const {
return _node != it._node;
}
T& operator*() const {
return _node->_data;
}
T* operator->() const {
return &_node->_data;
}
// unordered_map unordered_set为单向迭代器
Self& operator++() {
// 前置++
if(_node->_next)
_node = _node->_next;
else {
KeyOfT kot;
Hash hash;
size_t hashAddress = hash(kot(_node->_data)) % _tablePtr->_table.size();
++hashAddress;
_node = nullptr;
while(hashAddress < _tablePtr->_table.size() && (_node = _tablePtr->_table[hashAddress]) == nullptr)
++hashAddress;
// while(hashAddress < _tablePtr->_table.size() && _tablePtr->_table[hashAddress] == nullptr)
// ++hashAddress;
// if(hashAddress == _tableP