散列是一种以常数平均时间执行插入、删除和查找的技术。理想的散列表数据结构只不过是一个包含有关键字的具有固定大小
的数组。典型情况下,一个关键字就是一个带有相关值得字符串。我们把表的大小记作tableSize。每个关键字经过散列函数都会被映射到0到tableSize-1范围内。通常是保证表的大小为素数。如果不同的关键字映射到了相同的值,这时候就会产生冲突。
解决冲突的方法有分离链接法和开放定址法。
的数组。典型情况下,一个关键字就是一个带有相关值得字符串。我们把表的大小记作tableSize。每个关键字经过散列函数都会被映射到0到tableSize-1范围内。通常是保证表的大小为素数。如果不同的关键字映射到了相同的值,这时候就会产生冲突。
解决冲突的方法有分离链接法和开放定址法。
分离链接法 : 将散列到同一个值得所有元素保留到同一个表中,通过链表实现(如下图)
开放定址法 : 发生冲突后,就会尝试选择另外的单元,直到找到空单元为止。一般来说,装填因子应小于0.5(表中元素个数与表大小的比值)。对于找另外单元的方法通常是线性探测法、平方探测法、双散列
下面是散列的分离链接法实现
头文件hashtable.h
#ifndef HASHTABLE_H_
#define HASHTABLE_H_
struct Node;
struct HashTable;
typedef struct Node *ptrToNode;
typedef ptrToNode *List;
typedef struct HashTable *ptrToHashTable;
typedef int ElementType;
//创建散列表
ptrToHashTable createHashTable(int tableSize);
//散列函数
int hash(ElementType key,int tableSize);
//插入数据
void insert(ptrToHashTable H,ElementType e);
//查找数据
ptrToNode find(ptrToHashTable H,ElementType key);
//输出散列表
void printHashTable(ptrToHashTable H);
//销毁散列表
void destory(ptrToHashTable &H);
#endif /* HASHTABLE_H_ */
具体实现
#include <stdio.h>
#include <stdlib.h>
#include "hashtable.h"
struct Node {
ElementType data;
ptrToNode next;
};
struct HashTable {
int tableSize; //表大小
List tableList; //表头指针列表
};
/*
* 创建散列表表头列表,传入表的大小
* 解决冲突方法:分离链接法
*/
ptrToHashTable createHashTable(int tableSize) {
ptrToHashTable H = (ptrToHashTable) malloc(sizeof(struct HashTable));
if (H == NULL) {
printf("create fail\n");
return NULL;
}
H->tableSize = tableSize;
H->tableList = (List) malloc(sizeof(ptrToNode) * tableSize);
if(H->tableList == NULL){
printf("create fail\n");
free(H);
return NULL;
}
//创建表头
ptrToNode nodeList = (ptrToNode) malloc(sizeof(struct Node) * tableSize);
for (int i = 0; i < tableSize; i++) {
H->tableList[i] = &nodeList[i];
H->tableList[i]->next = NULL;
}
return H;
}
/**
* 插入元素
*/
void insert(ptrToHashTable H, ElementType e) {
//查看元素是否已在表中
ptrToNode ptr = find(H, e);
if (ptr == NULL) {
int index = hash(e, H->tableSize);
ptr = (ptrToNode) malloc(sizeof(struct Node));
if(ptr == NULL){
printf("malloc fail\n");
}
ptr->data = e;
ptr->next = (H->tableList[index])->next;
H->tableList[index]->next = ptr;
}
}
/**
* 查找关键字,如果已在表中就返回它所在的节点指针,否则返回NULL
*/
ptrToNode find(ptrToHashTable H, ElementType key) {
int index = hash(key, H->tableSize);
ptrToNode ptr = H->tableList[index]->next;
while (ptr != NULL && ptr->data != key) {
ptr = ptr->next;
}
return ptr;
}
/**
* 输出散列表的内容
*/
void printHashTable(ptrToHashTable H) {
ptrToNode ptr;
for (int i = 0; i < H->tableSize; i++) {
ptr = H->tableList[i]->next;
while (ptr != NULL) {
printf("%d ", ptr->data);
ptr = ptr->next;
}
printf("\n");
}
}
/**
* 求关键字散列值
*/
int hash(ElementType key, int tableSize) {
return key % tableSize;
}
/**
* 销毁散列表
*/
void destory(ptrToHashTable &H) {
if(H == NULL)
return;
ptrToNode ptr,temp;
for (int i = 0; i < H->tableSize; i++) {
ptr = H->tableList[i]->next;
while (ptr != NULL) {
temp = ptr;
ptr = ptr->next;
free(temp);
}
}
free(H->tableList);
free(H);
H = NULL;
}
测试
#include <stdio.h>
#include "hashtable.h"
int main() {
ptrToHashTable H = createHashTable(7); //创建散列表
//插入数据
insert(H, 2);
insert(H, 3);
insert(H, 7);
insert(H, 9);
insert(H, 25);
insert(H, 30);
insert(H, 8);
insert(H, 4);
insert(H, 12);
insert(H, 6);
insert(H, 17);
insert(H, 19);
insert(H, 99);
insert(H, 19);
insert(H, 99);
//输出
printHashTable(H);
destory(H);//销毁
return 0;
}