尝试理解K& R中讨论的简单散列查找算法的链表/结构实现的以下代码:
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;
我不明白的一些事情。这一行:
np = (struct nlist *) malloc(sizeof(*np));
if语句将值lookup(name)
赋给np后发生。那么malloc任务有什么作用呢?它是否重新初始化了价值?如果是这样,那么下面这行是什么?
if ((np = lookup(name)) == NULL)
如果malloc重新初始化它,它不会总是为空吗?或者malloc是否只是简单地分配内存而不会弄乱先前分配给np的值?如果是这种情况,那么为什么如果np为NULL,如果它已经在初始if语句中执行了那么它为什么再次检查?
说到np->next
代码,我完全迷失了。为什么np->接下来似乎是指自己?
以下是lookup()函数的代码:
/* 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 */
}
这是nlist结构:
struct nlist { /* table entry: */
struct nlist *next; /* next entry in chain */
char *name; /* defined name */
char *defn; /* replacement text */
};
答案 0 :(得分:10)
if ((np = lookup(name)) == NULL)
做两件事。首先,它将lookup(name)
的结果分配给np
。其次,它测试该分配的结果,看它是否为NULL
。
如果if
语句为真,则表示np
为NULL
,因此它们会为malloc
提供一个值。
现在,如果malloc
无法分配内存,则返回NULL
。 strdup
内部调用malloc
,这就是下一行
if (np == NULL || (np->name = strdup(name)) == NULL)
确保刚刚发生的两次分配都成功。
你是对的,因为新分配的条目 np->next
指向自己。这就是他们如何表明清单的结尾。其他实现使用NULL
来表示列表末尾。
编辑:我是个傻瓜,你让我说服你错了!
首先,哈希表如下所示:它是一个指向链表的指针表。数组中的索引是哈希值:
现在我们添加一个新条目:
np->next = hashtab[hashval];
hashtab[hashval] = np;
hashtab[hashval]
已经是具有相同哈希的条目列表的开头。它可能是NULL。此代码将新条目添加到列表的 front !因此,我们将新条目的next
指针指向现有列表,并将哈希表设置为指向新条目,因此它现在是第一个。
他们将节点添加到列表的前面,以便插入是O(1)操作。