哈希表的构造之开链法

前面总体介绍了一下有关哈希算法(哈希表如何构造,怎样减少哈希冲突等)

今天主要来实现一下哈希表的构造之开链法,这种方法可以将负载因子延伸到1,即_size==_tables.size(),这样对空间的利用率提高了许多,首先来看一下它的原理:



下面是代码实现:

template<class K>
struct GetKType
{
	size_t operator()(const K& key)
	{
		return key;
	}
};

template<>
struct GetKType<string>      //模板的特化
{
	//字符串哈希算法(将字符串转为整型)
	static size_t BKDRHash(const char* str)  //BKDRHash算法
	{
		unsigned int seed= 131;// 31 131 1313 13131 131313
		unsigned int hash= 0;
		while(*str)
		{
			hash=hash*seed+(*str++);
		}
		return(hash& 0x7FFFFFFF);
	}

	size_t operator()(const string& str)
	{
		return BKDRHash(str.c_str());
	}
};

template<class K,class V>
struct HashListNode
{
	HashListNode<K,V>* _next;
	K _key;
	V _value;

	HashListNode(const K& key,const V& value)
		:_key(key)
		,_value(value)
		,_next(NULL)
	{}
};

template<class K,class V,class HashFunc=GetKType<K> >
class HashList
{
	typedef HashListNode<K,V> Node;
public:
	HashList()
		:_size(0)
	{
		_tables.resize(_GetNextPrime(0));
	}

	~HashList()
	{
		if(_tables.empty())
			return;

		for(size_t i=0;i<_tables.size();++i)
		{
			Node* cur=_tables[i];
			while(cur)
			{
				Node* tmp=cur;
				cur=cur->_next;
				delete tmp;
				tmp=NULL;
			}
		}
		_size=0;
		_tables.clear();
	}

	bool Insert(const K& key,const V& value)
	{
		_CheckSize();
		size_t index=_HashFunc(key,_tables.size());
		//先检查该元素是否已在表中了
		Node* cur=_tables[index];
		while(cur)
		{
			if(cur->_key==key)
				return false;

			cur=cur->_next;
		}

		//采取头插
		Node* NewNode=new Node(key,value);
		NewNode->_next=_tables[index];
		_tables[index]=NewNode;

		++_size;
	}

	bool Find(const K& key)
	{
		size_t index=_HashFunc(key,_tables.size());
		Node* cur=_tables[index];    //先定位到在表中哪个位置
		while(cur)
		{
			if(cur->_key==key)
				return true;

			else
				cur=cur->_next;
		}
		return false;
	}

	bool Remove(const K& key)
	{
		if(_tables.empty())
			return false;

		size_t index=_HashFunc(key,_tables.size());
		Node* cur=_tables[index];
		Node* prev=NULL;
		while(cur)
		{
			//1.删除头结点
			//2.删除中间节点及尾节点
			if(cur->_key==key)
			{
				if(prev==NULL)
				{
					_tables[index]=cur->_next;
				}
				else
				{
					prev->_next=cur->_next;
				}
				delete cur;
				cur=NULL;
				--_size;
				return true;
			}
			prev=cur;
			cur=cur->_next;
		}
		return false;
	}


	void Print()
    {
        if (_size == 0)
            return;

        for (size_t i = 0; i < _tables.size(); ++i)
        {
            Node* cur = _tables[i];
            //cout << "_tables[" << i << "]" << "->";
			printf("_tables[%d]:",i);
            while (cur)
            {
                cout << cur->_key << "->";
                cur = cur->_next;
            }
            cout << "NULL" << endl;
        }
    }

protected:
	void _Swap(HashList<K,V,HashFunc>& hl)
	{
		std::swap(hl._tables,_tables);
		std::swap(hl._size,_size);
	}

	size_t _HashFunc(const K& key,size_t size)
	{
		HashFunc hf;
		return hf(key)%size;
	}

	size_t _GetNextPrime(size_t num)
	{
		const int _PrimeSize= 28;
        static const unsigned long _PrimeList[_PrimeSize] =
        {
			53ul, 97ul, 193ul, 389ul, 769ul,
			1543ul, 3079ul, 6151ul, 12289ul, 24593ul,
			49157ul, 98317ul, 196613ul, 393241ul,
			786433ul,
			1572869ul, 3145739ul, 6291469ul, 12582917ul,
			25165843ul,
			50331653ul, 100663319ul, 201326611ul, 402653189ul,
			805306457ul,
			1610612741ul, 3221225473ul, 4294967291ul
       };

		for(size_t i=0;i<_PrimeSize;++i)
		{
			if(num < _PrimeList[i])
			{
				return _PrimeList[i];
			}
			return _PrimeList[i-1];
		}
		return _PrimeList[_PrimeSize-1];   //如果size大于或等于素数表中数据,就返回表中最大数  
	}
	
	void _CheckSize()
	{
		if(_size >= _tables.size())      //负载因子为1就开始扩容
		{
			size_t NewSize=_GetNextPrime(_tables.size());
			//通过原表中的数据算出在新表中的位置
			vector<Node*> newTables;      //出了这个作用域就销毁
			newTables.resize(NewSize);
			for(size_t i=0;i<_tables.size();++i)
			{
				Node* cur=_tables[i];
				while(cur)
				{
					Node* tmp=cur->_next;
					cur=cur->_next;
					size_t index=_HashFunc(tmp->_key,newTables.size());
					newTables[index]=tmp;   	
				}
			}
			_tables.swap(newTables);
		}
	}

protected:
	vector<Node*> _tables;
	size_t _size;
};


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值