散列表

本文介绍了散列表(哈希表)的基本概念,包括其查找算法的优势,以及如何通过散列函数建立关键字与存储位置的对应关系。文章详细讨论了散列函数的选择,如直接定址法、平方取值法等,并阐述了处理冲突的策略,如开放定址法、再散列法和链地址法。此外,还分析了散列表的性能因素,如填装因子对查找效率的影响。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.概念

散列表(也叫哈希表)是一种查找算法,在查找时不需要进行一系列和关键字的比较操作。
散列表算法希望能尽量做到不经过任何比较,通过一次存取就能得到所查找的数据元素,因而必须要在数据元素的存储位置和它的关键字之间建立一个确定的对应关系,使每个关键字和散列表中一个唯一的存储位置相对应。因此在查找时,只要根据这个对应关系找到给定关键字在散列表中的位置即可,这种对应关系被称为散列函数

2.散列函数

散列函数是从关键字到地址区间的映像。
好的散列函数能够使得关键字经过散列后得到一个随机的地址,以便使一组关键字的散列地址均匀地分布在整个地址区间中,从而减少冲突。
常用的构造散列函数方法:
1).直接定址法
取关键字或关键字的某个线性函数值为散列地址,即:
H(key) = key 或 H(key) = a * key + b
2).数字分析法
3).平方取值法
取关键字平方后的中间几位为散列地址。
4).折叠法
将关键字分割成位数相同的几部分(最后一部分的位数可以不同),然后取这几部分的叠加和(舍去进位)作为散列地址。
5).除留余数法
取关键字被某个不大于散列表表长m的数p除后所得的余数为散列地址,即:
H(key) = key MOD p p ≤ m
6).随机数法
选择一个随机函数,取关键字的随机函数值为它的散列地址,即:
H(key) = random(key)

3.处理冲突

对不同的关键字可能得到同一散列地址,即key1 ≠ key2,而h(key1)= h(key2),这种现象称为冲突。具有相同函数值的关键字对该散列函数来说称作同义词
在一般情况下冲突是不可避免的,因此,在创建散列表时不仅要设定一个好的散列函数,而且还要设定一种处理冲突的方法。
常用的处理冲突方法:
1.开放定址法
指可存放新表项的空闲地址既向它的同义词开放,也向它的非同一次开放。
Hi =(H(key) + di) MOD m i =0,1,2,…,k(k ≤ m-1);m表示表长;di为增量序列。
di取法:

1). 线性探测再散列:
di = 0,1,2,3,…,m-1
2). 平方探测法:
di = 02,12,-12,22,-22,…,k2,-k2(k≤m/2)
散列表长度必须是一个可以表示成4k+3的素数.
3). 随机探测再散列:
di = 伪随机数序列.

2.再散列法
Hi = rhi(key) i = 1,2,…,k
rhi均是不同的散列函数。
3.链地址法
将所有关键字为同义词的数据元素存储在同一线性链表中。
4.建立一个公共溢出区

3.性能分析

散列表查找效率取决于三个因素:散列函数,处理冲突方法,填装因子。
填装因子:α=表中记录数n/散列表长度m
散列表平均查找长度依赖于α而不依赖于n,m。直观地看,α越大,表越满,越容易冲突。

4.函数实现

//散列表
typedef struct{
	int* elem;
	int count;
}HashTable;

//初始化
Status InitHashTable(HashTable *H){
    H->count = hash_size;
    H->elem = (int *)malloc(hash_size*sizeof(int));
    for(i = 0;i<hash_size;i++)
        H->elem[i] = NO_KEY;
    return true;
}   

/散列函数
int Hash(int key){
    return key % m;
} 
   
//插入
void InsertHash(HashTable *H,int key){
     int addr = Hash(Key);    
     while(H->elem[addr] != NO_KEY) 
         addr = (addr + 1) % m;        
     H->elem[addr] = key;      
}

//查找
Status SearchHash(HashTable H,int key){
    int addr = Hash(key);     
    while(H.elem[addr] != key){
        addr = (addr + 1) % m;      
        //遇见空或者回到原点
        if(H.elem[addr) == NO_KEY || addr == Hash(key))
            return false;   
    }
    return true;
}  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值