表查找

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

表查找

为了对结构的更多方面进行深入的讨论,我们来编写一个表查找程序包的核心部分代码。

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

#define IN 1

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

statet = IN;

就必须用1来替换IN。

以下两个函数用来处理名字和替换文本。install(s, t)函数将名字s 和替换文本t

记录到某个表中,其中s和t仅仅是字符串。lookup(s)函数在表中查找s,若找到,则返回指向该处的指针;若没找到,则返回NULL。

该算法采用的是散列查找方法——将输入的名字转换为一个小的非负整数,该整数随后

将作为一个指针数组的下标。数组的每个元素指向某个链表的表头,链表中的各个块用于描述具有该散列值的名字。如果没有名字散列到该值,则数组元素的值为NULL(参见图6-4)。图6-4

链表中的每个块都是一个结构,它包含一个指向名字的指针、一个指向替换文本的指针

以及一个指向该链表后继块的指针。如果指向链表后继块的指针为NULL,则表明链表结束。struct nlist { /* table entry: */

struct nlist *next; /* next entry in chain */

char *name; /* defined name */

char *defn; /* replacement text */

};

相应的指针数组定义如下:

#define HASHSIZE 101

static struct nlist *hashtab[HASHSIZE]; /* pointer table */

散列函数hash 在lookup 和install 函数中都被用到,它通过一个for 循环进行计

算,每次循环中,它将上一次循环中计算得到的结果值经过变换(即乘以31)后得到的新值同字符串中当前字符的值相加(*s + 31 * hashval),然后将该结果值同数组长度执行取

模操作,其结果即是该函数的返回值。这并不是最好的散列函数,但比较简短有效。

/* hash: form hash value for string s */

unsigned hash(char *s)

{

unsigned hashval;

for (hashval = 0; *s != '\0'; s++)

hashval = *s + 31 * hashval;

return hashval % HASHSIZE;

}

由于在散列计算时采用的是无符号算术运算,因此保证了散列值非负。

散列过程生成了在数组hashtab中执行查找的起始下标。如果该字符串可以被查找到,

则它一定位于该起始下标指向的链表的某个块中。具体查找过程由lookup 函数实现。如果

lookup函数发现表项已存在,则返回指向该表项的指针,否则返回NULL。

/* lookup: look for s in hashtab */

struct nlist *lookup(char *s)

{

struct nlist *np;

for (np = hashtab[hash(s)]; np != NULL; np = np->next)

if (strcmp(s, np->name) == 0)

return np; /* found */

return NULL; /* not found */

}

lookup函数中的for循环是遍历一个链表的标准方法,如下所示:

for (ptr = head; ptr != NULL; ptr = ptr->next)

...

install函数借助lookup函数判断待加入的名字是否已经存在。如果已存在,则用新

的定义取而代之;否则,创建一个新表项。如无足够空间创建新表项,则install函数返回

NULL。

struct nlist *lookup(char *);

char *strdup(char *);

/* install: put (name, defn) in hashtab */

struct nlist *install(char *name, char *defn)

{

struct nlist *np;

unsigned hashval;

if ((np = lookup(name)) == NULL) { /* not found */

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 /* already there */

free((void *) np->defn); /*free previous defn */

if ((np->defn = strdup(defn)) == NULL)

return NULL;

return np;

}

练习6-5 编写函数undef,它将从由lookup和install维护的表中删除一个变量

及其定义。

练习6-6 以本节介绍的函数为基础,编写一个适合C 语言程序使用的#define 处理

器的简单版本(即无参数的情况)。你会发现getch和ungetch函数非常有用。

相关文档
最新文档