散列查找——分离链接法

字符串类型的关键词

一、分离链接法的结构声明

#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;
}

八、运行

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值