hash查找

一个表查找程序包的核心代码。这段代码很典型,可以在宏处理器或编译器的符号表管理例程中找到。例如考虑#define 语句。当遇到类似于

#define IN 1

之类的程序行时,就需要把名字IN和替换文本1存入到某个表中。伺候,当名字IN出现在某些语句中时,如:

state=IN;

就必须用1来替换IN。

以下两个函数用来处理名字和替换文本。install(s,t)函数将名字s和替换文本t记录在某个表中,其中s和t仅仅是字符串。lookup(s)函数在表中查找s,若找到,则返回指向该处的指针;若没找到,则返回null。

该算法采用的是散列查找方法——将输入的名字转换为一个小的非负整数,该整数随后将作为一个指针数组的下标。数组的每个元素指向某个链表的表头,链表中的各个块用于描述具有该散列值的名字。如果没有名字散列到该值,则数组元素的值为null。

链表的每个元素都是一个结构,它包含一个指向名字的指针、一个指向替换文本的指针以及一个指向该链表后继块的指针。如果指向链表后继块的指针为null,则表明该链表结束。

源代码如下:

#include <stdio.h>

#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#define HASHSIZE 100
struct nlist{/*链表项*/
struct nlist *next/*链表中的下一表项*/;
    char *name;/*定义的名字*/
    char *defn;/*替换的文本*/
};
static struct nlist *hashtab[HASHSIZE];/*指针表,每个元素指向一个链表的表头,链表的每一个块都是一个结构*/
/*复制s到某个位置*/
char *strdup(char *s){
char *p;
p=(char *) malloc(strlen(s)+1);/*执行加一操作是为了在结尾加上字符‘\0’*/
if(p!=NULL){
strcpy(p,s);
}
return p;
}
/*为一个字符串生成一个散列值:将之前的字符值乘以31之后再加上当前的字符值,再同数组长度进行取模*/
unsigned hash(char *s){
unsigned hashval;


for(hashval=0;*s!='\0';s++){
hashval=*s+31*hashval;
}
return hashval%HASHSIZE;
}/*通过hash函数计算,为字符串生成一个数组下标*/
/*lookup函数:在hashtab表中查找s*/
struct nlist *lookup(char *s){
struct nlist *np;
for(np=hashtab[hash(s)];np!=NULL;np=np->next){
if(strcmp(s,np->name)==0){/*strcmp函数是string.h中用于比较字符串是否相等的函数*/
return np;/*找到s*/
}
}
return null;/*没找到s*/
}
/*install函数:将(name,defn)加入到hashtab中*/
struct nlist *install(char *name,char *defn){
struct nlist *np;
unsigned hashval;


if((np=lookup(name))==null){/*未找到*/
np=(struct nlist *) malloc(sizeof(*np));
if(np == NULL||(np->name= strdup(name))==NULL){
return NULL;/*没有可用位置空间*/
}
hashval = hash(name);
np->next = hashtab[hashval];
hashtab[hashval]=np;
}else{/*已存在*/
free((void *) np->defn);/*释放前一个defn*/
}
if((np->defn=strdup(defn))==null){
return null;
}
return up;

}

关于hash函数:hash(s)通过一个for循环进行计算,每次循环中,它将上次的计算结果经过变换(乘以31)得到的新值同字符串进行相加,然后与数组长度取模。其结果作为该函数的返回值。这并不是最好的散列函数,但是比较简短有效。由于散列函数使用了无符号的计算,因此得到的是非负值。

关于查找链表的一个标准方法就是:for(ptr=head;ptr!null;ptr=ptr->next)......

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值