数据结构:散列2(探测法)

上一章的内容:散列1:分离链接法

对于List和Vector,都是使用自己实现的简单模板。Vector模板的实现 List模板的实现


散列表的填装因子(load factor)λ为散列表中的元素个数和散列表大小的比值。

探测散列表:在找到位置后,发现已经有数据,继续找下一个,直到找到位置。这种表叫做探测散列表。


再散列:当散列表中数据很多的时候,插入可能会失败,这个时候就扩展为原来大于2倍的新散列表,一般是找下一个素数。然后把旧表的数据放到新表中。

当表达式达到某一个填装因子时进行再散列。

再散列是一种非常耗时间的操作,但是因为不是经常发生,所以效果还好。

	//使用探测法(probing hash tables)
	template<typename HashedObj>
	class HashTable2
	{
	public:
		//构造函数
		explicit HashTable2(int size = 101) :array(nextPrime(size))
		{
			makeEmpty();//设定结点的状态
		}
		//是否包含某个实体
		bool contains(const HashedObj& x)const
		{
			return isActive(findPos(x));//找到位置,这个位置是否被使用的
		}
		//清空散列表
		void makeEmpty()
		{
			currentSize = 0;
			for (int i = 0; i < array.size(); i++)
			{
				array[i].info = EMPTY;
			}
		}
		//插入数据
		bool insert(const HashedObj& x)
		{
			int currentPos = findPos(x);//找到位置
			if (isActive(currentPos))//已经有了就不插入了
			{
				return false;
			}
			//构建新的实体
			array[currentPos] = HashEntry(x, ACTIVE);
			++currentSize;
			if (currentSize > array.size()/2)
			{
				rehash();//超过一半就重构
			}
			return true;
		}
		//删除实体
		void remove(const HashedObj& x)
		{
			//找到位置
			int currentPos = findPos(x);
			if (!isActive(currentPos))
			{
				return false;//没有在使用的
			}
			array[currentPos].info = DELETED;//删除掉
			return true;
		}
		enum EntryType{ ACTIVE, EMPTY, DELETED };
	private:
		struct HashEntry 
		{
			HashedObj element;
			EntryType info;
			HashEntry(const HashedObj& e = HashedObj(), EntryType i = EMPTY)
				:element(e), info(i){}
		};
		Vector<HashEntry> array;
		int currentSize;
		//当前位置的状态
		bool isActive(int currentPos)const
		{
			return array[currentPos].info == ACTIVE;
		}
		//找实体的位置,理论上,是不会出现找到最后的位置也被使用掉的情况,因为超过一半了就要重构了
		int findPos(const HashedObj& x)const
		{
			int offset = 1;
			int currentPos = myhash(x);//散列函数
			//如果位置为空或者找到了相等的,就中止
			while (array[currentPos].info != EMPTY && array[currentPos].element != x)
			{
				currentPos += offset;
				offset += 2;
				if (currentPos >= array.size())
				{
					currentPos -= array.size();
				}
			}
			return currentPos;
		}
		//重构一个散列表
		void rehash()
		{
			Vector<HashEntry> oldArray = array;//原来的散列表
			//扩展数组大小,原来的两倍之后的第一个素数
			array.resize(nextPrime(2 * oldArray.size()));
			for (int i = 0; i < array.size(); i++)
			{
				array[i].info = EMPTY;//将信息置为空
			}
			currentSize = 0;
			//插入原来的数据
			for (int i = 0; i < oldArray.size(); i++)
			{
				if (oldArray[i].info == ACTIVE)
				{
					insert(oldArray[i].element);
				}
			}
		}
		//散列函数
		int myhash(const HashedObj& x)const
		{
			int hashVal = hash(x);
			hashVal %= array.size();
			if (hashVal < 0)
			{
				hashVal += array.size();
			}
			return hashVal;
		}
	};


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值