字符串类型的关键词
一、分离链接法的结构声明
#define KeyLength 15//关键词字符串的最大长度
typedef char ElementType[KeyLength+1];//关键词类型用字符串
typedef int Index;//散列地址类型
/*-----------单链表定义-------------*/
typedef struct LNode *PtrToLNode;
struct LNode{
ElementType Data;
PtrToLNode Next;
};
typedef PtrToLNode Position;
typedef PtrToLNode List;
/*-------------散列表定义-----------------*/
typedef struct TblNode *HashTable;
struct TblNode{
int TableSize;//表的最大长度
List Heads; //指向链表头结点的数组
};
二、分离链接法的初始化函数
int Prime(int N)
{
//返回小于等于N的最大素数
int i,p;
if(N>=1&&N<=3)p=N;
else p=(N%2)?N:N-1;//取奇数
while(p<=N&&p>4){
for(i=(int)sqrt(p);i>2;i--)
if(!(p%i))break;//p不是素数
if(i==2)break;//p是素数
else p-=2;
}
return p;
}
/*-------------创建-----------------*/
HashTable CreateTable(int TableSize)
{
HashTable H;
int i;
H=(HashTable)malloc(sizeof(struct TblNode)) ;
//保证散列表最大长度是素数
H->TableSize =Prime(TableSize);
//分配链表头结点数组
H->Heads =(List)malloc(sizeof(struct LNode)*H->TableSize );
//初始化表头结点
for(i=0;i<H->TableSize ;i++){
H->Heads[i].Data [0]='\0';
H->Heads[i].Next =NULL;
}
return H;
}
三、查找
/*----------哈希函数-----------*/
int Hash(const char *Key,int TableSize)
{
unsigned int H=0;
while(*Key!='\0')//位移映射
H=(H<<5)+*Key++;
//左移5相对于*2^5
return H%TableSize;
}
/*----------查找-----------*/
Position Find(HashTable H,ElementType Key)
{
Position P;
Index Pos;
Pos=Hash(Key,H->TableSize );
P=H->Heads[Pos].Next ;//从链表的第一个结点开始
//当未到表尾并且Key未被找到时
while(P&&strcmp(P->Data ,Key))
P=P->Next ;
return P;//此时p指向找到的结点,或者NULL
}
四、插入
/*----------插入-----------*/
bool Insert(HashTable H,ElementType Key)
{
//如果关键词已存在就不需要插入
//如果不存在插入单链表的第一个结点
Position P,NewCell;
Index Pos;
P=Find(H,Key);
if(!P){
//关键词未被找到,插入链表的第一个结点
NewCell=(Position) malloc(sizeof(struct LNode)) ;
strcpy(NewCell->Data ,Key);
Pos=Hash(Key,H->TableSize );//初识散列位置
//将NewCell插入为H->Heads[Pos]链表的第一个结点
NewCell->Next =H->Heads[Pos].Next;
H->Heads[Pos].Next =NewCell ;
return true;
}
else{
//关键词被找到
printf("关键词已存在\n");
return false;
}
}
五、删除
过程:
找到需要删除的关键词在散列表中的位置:遍历散列地址+链表
找到关键词删除:找到需要删除的关键词的前驱,删除关键词的前驱结点
未找到关键词: 打印错误信息
bool Delete(HashTable H,ElementType Key)
{
Position P,temp;
Index Pos;
Pos=Hash(Key,H->TableSize );
P=H->Heads+Pos;//注意:是H->Heads+Pos不是H->Heads[Pos]
//当未到链表的结尾并且p的下一个结点不是Key时,对比下一个结点
while(P->Next&&strcmp(P->Next->Data,Key))
P=P->Next ;
if(!P->Next){
printf("Not Find Key!\n");
return false;
}else{//找到了 ,p的下一个结点就是Key
temp=P->Next ;
P->Next =temp->Next ;
free(temp);
printf("%s is deleted from list Heads[%d]\n",Key,Pos);
return true;
}
}
六、销毁
/*----------释放-----------*/
void DestroyTable(HashTable H)
{
//释放CreateTable函数所占用的所以内存空间
int i;
Position P,Tmp;
//释放每一个链表的结点
for(i=0;i<H->TableSize ;i++){
P=H->Heads[i].Next;//从第一个结点开始
while(P){
Tmp=P->Next ;
free(P);
P=Tmp;
}
}
free(H->Heads );//释放头结点数组
free(H);//释放散列表结点
}
七、完整代码
//分离链接法
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<stdbool.h>
#include<math.h>
//关键词类型用字符串,字符串的长度不超过15
/*--------分离链接法的结构声明----------*/
#define KeyLength 15//关键词字符串的最大长度
typedef char ElementType[KeyLength+1];//关键词类型用字符串
typedef int Index;//散列地址类型
/*-----------单链表定义-------------*/
typedef struct LNode *PtrToLNode;
struct LNode{
ElementType Data;
PtrToLNode Next;
};
typedef PtrToLNode Position;
typedef PtrToLNode List;
/*-------------散列表定义-----------------*/
typedef struct TblNode *HashTable;
struct TblNode{
int TableSize;//表的最大长度
List Heads; //指向链表头结点的数组
};
int Prime(int N)
{
//返回小于等于N的最大素数
int i,p;
if(N>=1&&N<=3)p=N;
else p=(N%2)?N:N-1;//取奇数
while(p<=N&&p>4){
for(i=(int)sqrt(p);i>2;i--)
if(!(p%i))break;//p不是素数
if(i==2)break;//p是素数
else p-=2;
}
return p;
}
/*-------------创建-----------------*/
HashTable CreateTable(int TableSize)
{
HashTable H;
int i;
H=(HashTable)malloc(sizeof(struct TblNode)) ;
//保证散列表最大长度是素数
H->TableSize =Prime(TableSize);
//分配链表头结点数组
H->Heads =(List)malloc(sizeof(struct LNode)*H->TableSize );
//初始化表头结点
for(i=0;i<H->TableSize ;i++){
H->Heads[i].Data [0]='\0';
H->Heads[i].Next =NULL;
}
return H;
}
/*----------哈希函数-----------*/
int Hash(const char *Key,int TableSize)
{
unsigned int H=0;
while(*Key!='\0')//位移映射
H=(H<<5)+*Key++;
//左移5相对于*2^5
return H%TableSize;
}
/*----------查找-----------*/
Position Find(HashTable H,ElementType Key)
{
Position P;
Index Pos;
Pos=Hash(Key,H->TableSize );
P=H->Heads[Pos].Next ;//从链表的第一个结点开始
//当未到表尾并且Key未被找到时
while(P&&strcmp(P->Data ,Key))
P=P->Next ;
return P;//此时p指向找到的结点,或者NULL
}
/*----------插入-----------*/
bool Insert(HashTable H,ElementType Key)
{
//如果关键词已存在就不需要插入
//如果不存在插入单链表的第一个结点
Position P,NewCell;
Index Pos;
P=Find(H,Key);
if(!P){
//关键词未被找到,插入链表的第一个结点
NewCell=(Position) malloc(sizeof(struct LNode)) ;
strcpy(NewCell->Data ,Key);
Pos=Hash(Key,H->TableSize );//初识散列位置
//将NewCell插入为H->Heads[Pos]链表的第一个结点
NewCell->Next =H->Heads[Pos].Next;
H->Heads[Pos].Next =NewCell ;
return true;
}
else{
//关键词被找到
printf("关键词已存在\n");
return false;
}
}
/*----------删除-----------*/
/*
过程:
找到需要删除的关键词在散列表中的位置:遍历散列地址+链表
找到关键词删除:找到需要删除的关键词的前驱,删除关键词的前驱结点
未找到关键词: 打印错误信息
*/
bool Delete(HashTable H,ElementType Key)
{
Position P,temp;
Index Pos;
Pos=Hash(Key,H->TableSize );
P=H->Heads+Pos;//注意:是H->Heads+Pos不是H->Heads[Pos]
//当未到链表的结尾并且p的下一个结点不是Key时,对比下一个结点
while(P->Next&&strcmp(P->Next->Data,Key))
P=P->Next ;
if(!P->Next){
printf("Not Find Key!\n");
return false;
}else{//找到了 ,p的下一个结点就是Key
temp=P->Next ;
P->Next =temp->Next ;
free(temp);
printf("%s is deleted from list Heads[%d]\n",Key,Pos);
return true;
}
}
/*----------释放-----------*/
void DestroyTable(HashTable H)
{
//释放CreateTable函数所占用的所以内存空间
int i;
Position P,Tmp;
//释放每一个链表的结点
for(i=0;i<H->TableSize ;i++){
P=H->Heads[i].Next;//从第一个结点开始
while(P){
Tmp=P->Next ;
free(P);
P=Tmp;
}
}
free(H->Heads );//释放头结点数组
free(H);//释放散列表结点
}
//打印结果
void PrintResult(HashTable H)
{
int i;
printf("散列表:散列地址:关键词\n");
for(i=0;i<H->TableSize ;i++){
printf(" %d :",i);
Position P=H->Heads[i].Next;
if(!P)printf(" NULL");
while(P){
printf(" %s",P->Data );
P=P->Next ;
}
printf("\n");
}
}
int main()
{
HashTable H;
printf("请输入散列表的长度:");
int N,i;
scanf("%d",&N);
//创建
H=CreateTable(N);
printf("散列表的真实长度(地址空间大小):%d\n",H->TableSize );
//插入
ElementType Key;
printf("请输入插入的关键词的个数:");
scanf("%d",&N);
getchar();
printf("请输入%d个关键词:\n",N);
for(i=0;i<N;i++){
scanf("%s",Key);
Insert(H,Key);
}
//打印
PrintResult(H);
//删除
printf("请输入删除的关键词的个数:");
scanf("%d",&N);
getchar();
printf("请输入%d个关键词:\n",N);
for(i=0;i<N;i++){
scanf("%s",Key);
Delete(H,Key);
}
PrintResult(H);
//销毁
DestroyTable(H);
printf("散列表已销毁\n");
return 0;
}