The C Programming Language(第 2 版) 笔记 / 6 结构 / 6.6 表查找

本文探讨了在宏处理器或编译器符号表管理中常见的表查找算法,使用散列方法提高查找效率。介绍了install和lookup两个核心函数,前者用于插入新条目,后者用于查找条目。散列函数通过字符串计算散列值并利用散列表进行快速查找。当条目已存在时,install函数会更新其定义,否则会在表中创建新条目。
摘要由CSDN通过智能技术生成

目录、参考文献


6.6 表查找

为了对结构的更多方面进行深入的讨论,我们来编写一个表查找程序包的核心部分代码
这段代码很典型,可以在宏处理器或编译器的符号表管理例程中找到
例如,考虑 #define 语句,当遇到类似于 #define IN 1 之类的程序行时,就需要把名字 IN 和替换文本 1 存入到某个表中
此后,当名字 IN 出现在某些语句中时,如:statet = IN; 就必须用 1 来替换 IN

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

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

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

散列函数 hashlookupinstall 函数中都被用到
它通过一个 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; 
}

目录、参考文献

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值