第五章第一节(散列简介及分离链接法实现)

散列是一种用于以常数平均时间执行插入,删除,查找的技术。
散列函数:将每个关键字映射到适当的单元。理想情况下,它应该运算简单并且保证任何两个不同的关键字映射到不同的单元。
冲突:当两个关键字散列到同一个值的时候。

key关键字,TableSize散列表大小,当散列表的大小为素数时,可以使关键字分布更加均匀,减少冲突。
当key为整数时。一般采用 key % TableSize,来确定散列的位置。

当key为字符串时,可以将key的每一个字符的ASCII值加起来,再 %TableSize。

int Hash(const char *key, int tableSize){
	unsigned int hashVal = 0;
	while(*key != NULL){
		hashVal += *key++;
	}
	return hashVal % tableSize;
}

也可以只考虑字符串的前三个字符,值27为26个英文字母加上空格的个数。

int Hash(const char *key,int tableSize){
	return (key[0]+27*key[1]+729*key[2]) % tableSize;
}

使用关键字中的所有字符,可以用32的多项式函数作为散列函数,可以实现关键字的较均匀分布。

int Hash(const char *key,int tableSize){
	unsigned int hashVal = 0;
	while(*key != NULL){
		hashVal = (hashVal<<5)+*key++;
	}
	return hashVal % tableSize;
}

如果当一个元素被插入时,另一个元素已经存在(散列值相同),就产生一个冲突,就要去消除冲突。常用的解决冲突的方法:分离链接法和开放定址法;

下面时分离链接法:
分离链接法是将散列到同一个值的元素保留到一个表中(链表);
代码实现:

数据结构:

#include<stdio.h>
#include <stdlib.h>
#include <math.h>
#include<string.h>

//分离链接法,将散列到同一个值的所有元素保留到一个表中。
typedef char* ElementType;
typedef struct ListNode *Postion;
struct ListNode {
	char Element[20];	//	元素值
	Postion Next;		// 下一个节点
};
typedef struct HashTbl *HashTable;
typedef Postion List;
struct HashTbl {	//哈希表结构
	int TableSize;	//哈希表大小
	List *TheLists;	//链表组
};
//函数声明
int Hash(const char *key,int TableSize);	//哈希函数
HashTable InitializeTable(int TableSize);	//哈希表初始化函数
void DestroyTable(HashTable H);				//销毁哈希表函数
Postion find(ElementType key,HashTable H);	//查找函数	
void Insert(ElementType key, HashTable H);	//插入函数
void Delete(ElementType key, HashTable H);	//删除函数
int NextPrime(int TableSize);				//寻找素数函数

函数实现:
哈希函数,使用32的多项式函数。

int Hash(const char *key, int TableSize) {	//哈希函数
	unsigned int HashVal = 0;	//无符号数,避免溢出,变为负数
	while (*key != '\0')
		HashVal = (HashVal << 5) + *key++;
	return HashVal % TableSize;
}
int NextPrime(int TableSize) {
	int i, j, flag;
	i = TableSize;
	while(1){
		flag = 1;
		for (j = 2; j <= sqrt(i); j++) {
			if (i%j == 0) {
				flag = 0;
				break;
			}
		}
		if (flag == 1) {
			break;
		}
		i++;
	}
	return i;
}
HashTable InitializeTable(int TableSize) {	//初始化哈希表
	HashTable H;
	int i;
	H = (HashTbl*)malloc(sizeof(struct HashTbl));
	if (H == NULL) {
		printf("初始化错误\n");
		return H;
	}
	H->TableSize = NextPrime(TableSize);	//初始化为素数;
	H->TheLists = (List*)malloc(sizeof(List)*H->TableSize);
	if (H->TheLists == NULL) {
		printf("初始化错误\n");
		return H;
	}
	//把每个位置都初始化为一个空链表
	for (i = 0; i < H->TableSize; i++) {
		H->TheLists[i] = (Postion)malloc(sizeof(struct ListNode));
		if (H->TheLists[i] == NULL) {
			printf("初始化错误\n");
			return H;
		}
		else {
			H->TheLists[i]->Next = NULL;	//链表为空,链表的首个节点为空节点
		}
	}
	return H;
}
Postion find(ElementType key, HashTable H) {	//找到节点
	Postion P;
	List L;
	L = H->TheLists[Hash(key, H->TableSize)];	//找到位置
	P = L->Next;
	while (P != NULL && strcmp(P->Element, key)) {	//在链表中寻找
		P = P->Next;
	}
	return P;	//返回节点的位置,若P为NULL,则在哈希表中无该值
}
void Insert(ElementType key, HashTable H) {	//插入函数
	Postion Pos, NewCell;
	List L;
	Pos = find(key, H);	//在哈希表寻找该值
	if (Pos == NULL) {	//Pos为空,哈希表中没有该值,则插入
		NewCell = (Postion)malloc(sizeof(struct ListNode));	//申请节点空间
		if (NewCell == NULL) {
			printf("初始化失败/n");
			return;
		}
		else {
			//在已经找到的位置,插入节点
			L = H->TheLists[Hash(key, H->TableSize)];
			NewCell->Next = L->Next;
			strcpy_s(NewCell->Element, strlen(key)+1,key);
			L->Next = NewCell;	
		}
	}
}
void Delete(ElementType key,HashTable H) {	//删除一个key的哈希节点
	List L;
	Postion P;
	L = H->TheLists[Hash(key, H->TableSize)];
	while (strcmp(L->Next->Element, key)) {	//找到节点
		L = L->Next;
	}
	P = L->Next;
	L->Next = P->Next;
	free(P);	//删除操作
}
void DestroyTable(HashTable H) {	//销毁哈希表
	List L;
	Postion P;
	for (int i = 0; i < H->TableSize; i++) {	//将每个位置的链表销毁
		L = H->TheLists[i];
		while (L->Next != NULL) {
			P = L->Next;
			L->Next = P->Next;
			free(P);
		}
		free(L);
	}
	free(H);	//最后将哈希节点销毁
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值