链表指针数组实现哈希表
哈希表,又称散列表,目的是实现更快的搜索,其利用数组的特性,理想情况下(无冲突,事实上也不可能)可以实现O(1)的时间复杂度.
本文给出用数组来存链表的方式来避免有限集描述更大集的冲突问题。
哈希表数据结构实现
- 结构体定义
typedef struct Node{
int data;
struct Node* next;
}ListNode;
struct HashTable{
ListNode* elem[SIZE];
int count;
}ht;
定义两个结构体,一个为存放链表头指针的数组(初始为空指针),
以及存放在哈希表中的数据数量count。
- 哈希函数实现
#define SIZE 20
#define NODESIZE 200
我们定义链表个数(数组长度)为20,那么如果用整除来实现哈希函数(值到地址(数组下标)的映射关系)
可以另哈希函数为以下:
int CalHash(int key){
return key%(SIZE-1); //宏定义SIZE为20
}
这样相应可以使数据在哈希表中分布更加均匀,提高查找效率(书上是这么说的)。
3.哈希表初始化
因为数组中每一个节点都存放了一个地址,我们将每个数组元素都初始化为NULL指针,以便插入元素时,这个指针来接收malloc函数返回的地址。
void InitializeHash(){
ht.count=0;
for(int i=0;i<SIZE;i++)
ht.elem[i]=NULL;
}
哈希表搜索
函数原型
int SearchHash(int key,int* s)
搜索函数嵌套在插入函数和删除函数里面,在函数之间传递CalHash函数计算得到的数组下标,故此函数要传递两个参数,一个是要查找的关键字,另一个是CalHash返回的数组下标,用一个int* 传递。
详细代码
int SearchHash(int key,int* s){
//(*s)=CalHash(key);
ListNode* current=ht.elem[*s];
while(current!=NULL){
if(current->data==key)
return 1;
current=current->next;
}
return 0;
}
哈希表插入
函数原型
int InsertHash(int e)
形参e为插入的元素值。
详细代码
int InsertHash(int e){
int s;
if(ht.count==NODESIZE){
printf("哈希表已满\n");
return 1;
}
else{
s=CalHash(e);
int r=SearchHash(e,&s);
if(r){
printf("所处链表有重复元素,无法插入\n");
return 0;
}
else{
if(ht.elem[s]==NULL){ //空链表
(ht.elem[s])=(ListNode*) malloc(sizeof(ListNode));
(ht.elem[s])->next=NULL;
(ht.elem[s])->data=e;
ht.count++;
printf("链式哈希表第%d个链表插入头结点%d\n",s,ht.elem[s]->data);
}
else{ //尾插
ListNode* current=(ht.elem[s]);
while(current->next!=NULL)
current=current->next;
current->next=(ListNode*) malloc(sizeof(ListNode));
current->next->data=e;
current->next->next=NULL;
printf("存在冲突,链式哈希表第%d个链表插入尾节点%d\n",s,current->next->data);
ht.count++;
}
}
}
return 1;
}
删除函数
函数原型
int DeleteHash(int key)
详细代码
int DeleteHash(int key){
int s=CalHash(key);
int i=SearchHash(key,&s);
if(i){
ListNode* current=ht.elem[s];
ListNode* prev=NULL;
if(current->data==key){ //头结点删除
ht.elem[s]=current->next;
current->next=NULL;
printf("哈希表第%d个链表删除头结点%d\n",s,current->data);
free(current);
ht.count--;
return 1;
}
while(current!=NULL){ //后续节点删除
if(current->data!=key){
prev=current;
current=current->next;
}
else
break;
}
prev->next=current->next;
current->next=NULL;
printf("哈希表第%d个链表删除中间节点或尾结点%d\n",s,current->data);
free(current);
ht.count--;
return 1;
}
else
printf("你要删除的元素不存在\n");
return 0;
}
free函数
函数原型
void freeHash()
详细代码
void freeHash(){
for(int i=0;i<SIZE;i++){
ListNode* current=ht.elem[i];
while(current!=NULL){
ListNode* temp=current;
current=current->next;
temp->next=NULL;
free(temp);
}
}
}
全部代码
#include <stdio.h>
#include <stdlib.h>
#define SIZE 20
#define NODESIZE 200
void freeHash();
int DeleteHash(int key);
int InsertHash(int e);
int CalHash(int key);
void InitializeHash();
int SearchHash(int key,int* s);
typedef struct Node{
int data;
struct Node* next;
}ListNode;
struct HashTable{
ListNode* elem[SIZE];
int count;
}ht;
int main(void){
InitializeHash();
int a1=InsertHash(1);
int a2=InsertHash(2);
int a3=InsertHash(21);
int a4=DeleteHash(2);
int a5=DeleteHash(21);
freeHash();
return 0;
}
int CalHash(int key){
return key%SIZE;
}
void InitializeHash(){
ht.count=0;
for(int i=0;i<SIZE;i++)
ht.elem[i]=NULL;
}
int SearchHash(int key,int* s){
//(*s)=CalHash(key);
ListNode* current=ht.elem[*s];
while(current!=NULL){
if(current->data==key)
return 1;
current=current->next;
}
return 0;
}
int InsertHash(int e){
int s;
if(ht.count==NODESIZE){
printf("哈希表已满\n");
return 1;
}
else{
s=CalHash(e);
int r=SearchHash(e,&s);
if(r){
printf("所处链表有重复元素,无法插入\n");
return 0;
}
else{
if(ht.elem[s]==NULL){ //空链表
(ht.elem[s])=(ListNode*) malloc(sizeof(ListNode));
(ht.elem[s])->next=NULL;
(ht.elem[s])->data=e;
ht.count++;
printf("链式哈希表第%d个链表插入头结点%d\n",s,ht.elem[s]->data);
}
else{ //尾插
ListNode* current=(ht.elem[s]);
while(current->next!=NULL)
current=current->next;
current->next=(ListNode*) malloc(sizeof(ListNode));
current->next->data=e;
current->next->next=NULL;
printf("存在冲突,链式哈希表第%d个链表插入尾节点%d\n",s,current->next->data);
ht.count++;
}
}
}
return 1;
}
int DeleteHash(int key){
int s=CalHash(key);
int i=SearchHash(key,&s);
if(i){
ListNode* current=ht.elem[s];
ListNode* prev=NULL;
if(current->data==key){ //头结点删除
ht.elem[s]=current->next;
current->next=NULL;
printf("哈希表第%d个链表删除头结点%d\n",s,current->data);
free(current);
ht.count--;
return 1;
}
while(current!=NULL){ //后续节点删除
if(current->data!=key){
prev=current;
current=current->next;
}
else
break;
}
prev->next=current->next;
current->next=NULL;
printf("哈希表第%d个链表删除中间节点或尾结点%d\n",s,current->data);
free(current);
ht.count--;
return 1;
}
else
printf("你要删除的元素不存在\n");
return 0;
}
void freeHash(){
for(int i=0;i<SIZE;i++){
ListNode* current=ht.elem[i];
while(current!=NULL){
ListNode* temp=current;
current=current->next;
temp->next=NULL;
free(temp);
}
}
}
后记
GDB牛逼