[散列 | C++实现]

1.常见的哈希函数

1.1 直接定址法

取关键字的某个线性函数为散列地址:Hash(Key)= A*Key + B

1.2 除留余数法

设散列表中允许的地址数为m,取一个不大于m,但最接近或者等于m的质数p作为除数,按照哈希函 数:Hash(key) = key% p(p<=m),将关键码转换成哈希地址

2. 闭散列

闭散列:也叫开放定址法,当发生哈希冲突时,如果哈希表未被装满,说明在哈希表中必然还有空位置,那 么可以把key存放到冲突位置中的“下一个” 空位置中去。那如何寻找下一个空位置呢?

  • 线性探测
    从发生冲突的位置开始,依次向后探测,直到寻找到下一个空位置为止。
    来看下面的例子:
    在这里插入图片描述
    先插入1,2,3,4,5,6,8;现在要插入44.44 % 10 = 4,显然4已经被占用,此时就一直探测到空位置7,进行插入。
bool Insert(const pair<K, V>& data)
	{
		CheckCapcity();
		int index = data.first % _ht.size();
		while (_ht[index]._state == Exist)
		{
			if (_ht[index]._data.first == data.first)
				return false;
			++index;
			if (index == _ht.size())
				index = 0;
		}
		_ht[index]._data = data;
		_ht[index]._state = Exist;
		++_size;
		return true;
	}
  • 二次探测
    线性探测的缺陷是产生冲突的数据堆积在一块,这与其找下一个空位置有关系,因为找空位置的方式就 是挨着往后逐个去找,因此二次探测为了避免该问题,找下一个空位置的方法为: = ( + )% m, 或者: = ( - )% m。其中:i = 1,2,3…, 是通过散列函数Hash(x)对元素的关键码 key 进行 计算得到的位置,m是表的大小。

2. 开散列

开散列法又叫链地址法(开链法),首先对关键码集合用散列函数计算散列地址,具有相同地址的关键码 归于同一子集合,每一个子集合称为一个桶,各个桶中的元素通过一个单链表链接起来,各链表的头结 点存储在哈希表中。
那么上述的例子插入,将会变成这样:
在这里插入图片描述
即出现哈希冲突时,它会找到这个链表进行头插。

   PNode* Insert(const V& data)  
     {       
     	_CheckCapacity();                
     	// 1. 计算元素所在的桶号   
     	size_t bucketNo = HashFunc(data);   
     	// 2. 检测该元素是否在桶中        
     	PNode pCur = _ht[bucketNo];       
     	 while(pCur){            
     	 	if(pCur->_data == data)               
     	 			 return pCur;                        
     	 	pCur = pCur->_pNext;     
     	 }               
     	 // 3. 插入新元素 
     	 pCur = new Node(data);       
     	 // 采用头插法插入      
     	 pCur->_pNext = _ht[bucketNo];     
     	 _ht[bucketNo] = pCur;      
     	  _size++;               
     	   return pCur;    
     	  }         
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值