散列表的查找和插入算法

散列表查找

散列表查找是一种特殊的查找方法,它能够通过对关键字的值快速定位待查找元素的位置。再查找方面,散列表有着极高的效率。但是一个散列表或多或少会存在冲突,为了解决冲突,我们设计了两个方法,一个是开放定址法,另一个就是拉链法
开放定址法又分为线性探查法,二分探查法和双重散列法,就效率而言,双重散列法的效率是最优的,但是其中最为直观的方法还是线性探查法。

基本思想

使用某种方法在散列表中形成一个探查序列,沿着此序列逐个单元进行比较,直到找到一个空的单元并将新节点插入其中。假设待散列空间为T[0…m-1],散列函数为H(KEY),则开放定址法的一般形式为:

Hi = (H(KEY)+Di)%m 且 i>=0&&i<=m-1

而拉链法就是开放定址法在链式存储上的一章算法体现而已。理解了开放定址法,拉链法就不会让人感到晦涩难懂。

线性探查法解决冲突的查找和插入算法

#define M 1003					//M为表长
typedef struct {				//定义一个结构体NodeType
	KeyType key;				
	DataType data;
}NodeType;
typedef NodeType HashTable[M];		//定义一个哈希表,表长为M
//定义散列函数
int h(KeyType HT,KeyType K,int m){
	return K%m;					//除余法定义散列函数
}
//采用线性探查法的散列表查找算法
int HashSearch1(HashTable HT,KeyType K,int m){
	int d,temp;					
	d = h(K,m);						//调用散列函数获取散列地址
	temp = d;						//temp防止进入重复循环
	while(HT[d].key!=-32768)		//如果Key不为空
	{
		if(HT[d].Key == K){			//查找成功
			return d;
		}else{
			d = (d+1)%m;				//计算下一个地址
		}
		if(d==temp){					//循环一次
			return -1;						//找不到可用地址返回-1
		}
		return d;
	}
}
//在散列表上插入一个节点的算法
int HashInsert1(HashTable HT,NodeType s,int m){
	int d;
	d = HashSearch1(HT,s,m);		//查找可用地址
	if (d==1)return -1;			
	else{
		if (HT[d].key == s.key){return 0;}			//表中已有该节点
		else{
			HT[d] =s ;						//插入结点
			return 1;							//返回1表示成功
		}
	}
}

拉链法建立散列表上的查找和插入运算

//类型定义
typedef struct node{
	KeyType key;
	DataType data;
	struct HTNode* HT[M]; 
}
int h(KeyType HT,KeyType K,int m){
	return K%m;					//除余法定义散列函数
}
//查找算法
HTNode* HashSeaerch2(HT T,KeyType K,int m){
	HTNode* p = T[h(K,m)];			//取K所在链表的头指针
	while(p!=NULL && p->key!=K){	//如果当前链表头指针不为空,且不为待查找结点
		p=p->next;					//遍历
	}
	return p;
}
//插入算法
int HashInsert2(HT T,HTNode* s,int m)
{
	int d;
	HTNode* p = HashSearch2(T,s->key,m);		//查找当前结点
	if(p!=NULL)return 0;						//表明表中没有待插入结点
	else{										//将*s插入在相应链表的表头上
		d = h(s->key,m);						//获取待插入结点的头指针
		s->next=T[d];							
		T[d]=s;
		return 1;								//插入成功
	}
}
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页