C++는 단순히 unorderset 및 unordermap을 구현합니다.

unorderset 및 unordermap은 C++11 Center에서 도입한 연관 컨테이너입니다. set과 map의 차이는 순회할 때 순서가 있는지 여부인데 unorderset과 unordermap은 순회할 때 순서가 없는 것을 이름에서 알 수 있다. 이러한 차이가 나는 이유는 그들의 하부 구현의 데이터 구조가 다르기 때문인데, unorderset과 unordermap의 하부 layer는 hash table을 통해 구현되고, set과 map의 하부 layer는 red-black tree를 통해 구현된다. . unorderset 및 unordermap의 삽입 및 검색 효율성은 매우 높으며 그 이유 중 하나도 소개합니다. 달성 방법을 살펴 보겠습니다.

이 기사를 읽을 때 먼저 해시
데이터 구조를 이해하고 5분 안에 해시 테이블을 얻을 수 있도록 해야 합니다(권장 수집)!!!

개조 해시 테이블

해시 테이블 구현 방법을 안다면 unorderset 구현의 절반은 실제로 구현됩니다.물론 이것은 단순한 구현일 뿐이며 여전히 STL 라이브러리의 기본 구현과는 조금 다릅니다. 먼저 해쉬 테이블을 캡슐화해야 하는데 여기서는 직접 코드를 제공하겠습니다. val을 통한 키, 저장을 위한 비교로 키 사용

반복자

해시 테이블의 주요 구성원은 포인터 배열이며 포인터 배열을 캡슐화하여 반복자를 구현해야 합니다. 먼저 begin()과 end()의 위치를 ​​이해합시다. begin()은 비어 있지 않은 첫 번째 연결 목록의 헤드 노드여야 하고 end()는 마지막 노드의 다음 위치여야 합니다. 여기서 nullptr 반복자의 가장 어려운 구현은 ++ 연산입니다. Iterator
여기에 이미지 설명 삽입
연결 리스트이기 때문에 단어에 대해 즉, 노드를 캡슐화한 다음 ++ 연산자를 오버로드한 후에는 ++ 연산을 수행할 수 없습니다. ++ 연산을 구현할 때 두 가지 가능성이 있는데, 첫 번째는 다음 노드가 있다는 것이고, 두 번째는 다음 노드가 없다는 것이고, 다음 노드가 있으면 그 노드를 직접 다음 노드로 설정하는 것이다. 존재하지 않는 경우 해시 테이블의 포인터 배열을 사용하여 현재 노드의 해시 위치를 얻은 다음 연결 목록의 비어 있지 않은 다음 헤드 노드를 검색해야 합니다. 찾은 경우 노드를 다음과 같이 설정합니다. 헤드 노드가 발견되고 발견되지 않으면 빈 값을 반환하여 끝을 나타냅니다. 해시 테이블의 전용 멤버를 사용하고 있으므로 이터레이터 클래스를 해시 테이블 클래스의 friend 클래스로 설정해야 합니다.

#include <vector>
#include <iostream>
using namespace std;

template<class K, class V, class KeyOfValue>
class HTable;//声明

template<class V>
struct HashNode
{
    
    
	typedef HashNode<V> Node;
	V _val;
	Node* _next;

	HashNode(const V& val)
		:_val(val)
		,_next(nullptr)
	{
    
    }
};


template<class K, class V, class KeyOfValue>
struct HashIterator
{
    
    
	typedef HashNode<V> Node;
	typedef HashIterator<K, V, KeyOfValue> Self;
	typedef HTable<K, V, KeyOfValue> HT;
	Node* _node;
	HT* _hPtr;

	HashIterator(Node* node, HT* hPtr)
		:_node(node)
		,_hPtr(hPtr)
	{
    
    }

	V& operator*()
	{
    
    
		return _node->_val;
	}

	V* operator->()
	{
    
    
		return &_node->_val;
	}

	bool operator!=(const Self& it)
	{
    
    
		return _node != it._node;
	}

	Self& operator++()
	{
    
    
		//下一个结点存在
		if (_node->_next)
		{
    
    
			_node = _node->_next;
		}
		else//不存在下一个节点
		{
    
    
			//则需要找到下一个非空的链表的头结点
			//计算当前节点在哈希表中的位置
			KeyOfValue kov;
			size_t idx = kov(_node->_val) % _hPtr->_ht.size();
			//从下一个哈希位置开始查找
			++idx;
			for (; idx < _hPtr->_ht.size(); ++idx)
			{
    
    
				if (_hPtr->_ht[idx])//找到下一个非空结点
				{
    
    
					_node = _hPtr->_ht[idx];
					break;
				}
			}
			//没找到非空链表,则表示走到末尾,则为空
			if (idx == _hPtr->_ht.size())
				_node = nullptr;
		}
		return *this;
	}

};

template<class K, class V, class KeyOfValue>
class HTable
{
    
    
public:
	typedef HashIterator<K, V, KeyOfValue> iterator;
	typedef HashNode<V> Node;

	template<class K, class V, class KeyOfValue>
	friend struct HashIterator;

	HTable(int n = 10)
		:_ht(n)
		,_size(0)
	{
    
    }

	iterator begin()
	{
    
    
		//第一个非空链表的头结点
		for (size_t i = 0; i < _ht.size(); ++i)
		{
    
    
			if (_ht[i])
			{
    
    
				return iterator(_ht[i], this);
			}
		}
		return iterator(nullptr, this);
	}

	iterator end()
	{
    
    
		return iterator(nullptr, this);
	}

	pair<iterator, bool> insert(const V& val)
	{
    
    
		//0.检查容量
		checkCapacity();

		//1.计算hash位置
		KeyOfValue kov;
		int idx = kov(val) % _ht.size();

		//2.查找
		Node* cur = _ht[idx];
		while (cur)
		{
    
    
			if (kov(cur->_val) == kov(val))
				return make_pair(iterator(cur, this), false);
			cur = cur->_next;
		}

		//3.插入--头插
		cur = new Node(val);
		cur->_next = _ht[idx];
		_ht[idx] = cur;
		++_size;
		return make_pair(iterator(cur, this), true);
	}

	void checkCapacity()
	{
    
    
		if (_size == _ht.size())
		{
    
    
			int newC = _size == 0 ? 10 : 2 * _size;

			//创建新的指针数组
			vector<Node*> newHt(newC);

			KeyOfValue kov;
			//遍历旧表
			for (size_t i = 0; i < _ht.size(); ++i)
			{
    
    
				Node* cur = _ht[i];
				//遍历单链表
				while (cur)
				{
    
    
					Node* next = cur->_next;
					//计算新的位置
					int idx = kov(cur->_val) % newHt.size();
					//头插
					cur->_next = newHt[idx];
					newHt[idx] = cur;

					cur = next;
				}
				//旧表指针置空
				_ht[i] = nullptr;
			}

			//交换新表和旧表
			swap(_ht, newHt);
		}
	}
private:
	//指针数组
	vector<Node*> _ht;
	int _size;
};

정렬되지 않은 구현

template<class K>
class UnorderedSet
{
    
    
	struct SetKeyOfValue
	{
    
    
		const K& operator()(const K& key)
		{
    
    
			return key;
		}
	};
public:
	typedef typename HTable<K, K, SetKeyOfValue>::iterator iterator;
	pair<iterator, bool> insert(const K& key)
	{
    
    
		return _ht.insert(key);
	}

	iterator begin()
	{
    
    
		return _ht.begin();
	}

	iterator end()
	{
    
    
		return _ht.end();
	}
private:
	HTable<K, K, SetKeyOfValue> _ht;
};

시험:
여기에 이미지 설명 삽입

무순 맵 구현

template<class K, class V>
class UnorderedMap
{
    
    
	struct MapKeyOfValue
	{
    
    
		const K& operator()(const pair<K, V>& val)
		{
    
    
			return val.first;
		}
	};
public:
	typedef typename HTable<K, pair<K, V>, MapKeyOfValue>::iterator iterator;
	
	pair<iterator, bool> insert(const pair<K, V>& val)
	{
    
    
		return _ht.insert(val);
	}
	iterator begin()
	{
    
    
		return _ht.begin();
	}

	iterator end()
	{
    
    
		return _ht.end();
	}
	V& operator[](const K& key)
	{
    
    
		pair<iterator, bool> ret = _ht.insert(make_pair(key, V()));
		return ret.first->second;
	}
private:
	HTable<K, pair<K, V>, MapKeyOfValue> _ht;
};

시험:
여기에 이미지 설명 삽입

추천

출처blog.csdn.net/qq_44443986/article/details/117293321