C K&;R用这个链表在这里做什么?

C K&;R用这个链表在这里做什么?,c,data-structures,linked-list,C,Data Structures,Linked List,我正在用C语言的字典进行黑客攻击,我从K&R的书中撕下了一些代码。我不明白他们是如何用这个在哈希表中建立一桶链表的??在我看来,他们正在将下一个指针链接到链接列表的标题。他们是否以某种方式创造了一个我无法捕捉的水桶?np是一个三成员结构,包含字符串(name,defn)和指向下一个字符串的指针,如果字典中存在np,则查找查找 if ((np = lookup(name)) == NULL){ // file not found np = (struct nlist *) malloc(s

我正在用C语言的字典进行黑客攻击,我从K&R的书中撕下了一些代码。我不明白他们是如何用这个在哈希表中建立一桶链表的??在我看来,他们正在将下一个指针链接到链接列表的标题。他们是否以某种方式创造了一个我无法捕捉的水桶?np是一个三成员结构,包含字符串(name,defn)和指向下一个字符串的指针,如果字典中存在np,则查找查找

if ((np = lookup(name)) == NULL){ // file not found
    np = (struct nlist *) malloc(sizeof(*np));
    if (NULL == np || (np->name = strdup(name)) == NULL){
        return NULL;
    }
    hashval = hash(name);
    np->next = hashtab[hashval]; // WHAT THE HECK ARE THEY DOING HERE?!?!
    hashtab[hashval] = np;
}else{ // already there
    free((void *)np->defn);
}
if((np->defn = strdup(defn)) == NULL){
    return NULL;
}
return np;
为了让代码正常工作,我对代码进行了如下修改,但我有一种烦人的感觉,a错过了他们试图表达的一点

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);
    phE->next = NULL; //if first entry set next to NULL, MOD HERE
    tmpNode = hashtab[hashval]; 
    if (tmpNode == NULL){ // EMPTY SPOT IN HASHTABLE
        hashtab[hashval] = np;
    }else{                         //HASH COLLISION, ADD NODE TO LIST END
        while (tmpNode->next != NULL){
            tmpNode = tmpNode->next;
        }
        tmpNode->next = np;
    }
}else{
    free((void *) np->defn);
}
if ((np->defn = strdup(defn)) == NULL){
    return NULL;
}
return np;

让我们跟踪一下这段代码,看看它的功能:

np->next = hashtab[hashval]; // WHAT THE HECK ARE THEY DOING HERE?!?!
hashtab[hashval] = np;
最初,我们的哈希表如下所示:

    +---+---+---+---   ---+---------+---+---+---+
    |   |   |   |   ...   | hashval |   |   |   |
    +---+---+---+---   ---+---------+---+---+---+
                              |
                              |
                              |      +------+    +-----+
                              +----> | head | -> | ... |
                                     +------+    +-----+
    +---+---+---+---   ---+---------+---+---+---+
    |   |   |   |   ...   | hashval |   |   |   |
    +---+---+---+---   ---+---------+---+---+---+
                              |
                              |
                 +-----+      |      +------+    +-----+
           np -> |     |------+----> | head | -> | ... |
                 +-----+             +------+    +-----+
    +---+---+---+---   ---+---------+---+---+---+
    |   |   |   |   ...   | hashval |   |   |   |
    +---+---+---+---   ---+---------+---+---+---+
                              |
                    +---------+
                    |
                    v         
                 +-----+             +------+    +-----+
           np -> |     |-----------> | head | -> | ... |
                 +-----+             +------+    +-----+
以下是
np

    +---+---+---+---   ---+---------+---+---+---+
    |   |   |   |   ...   | hashval |   |   |   |
    +---+---+---+---   ---+---------+---+---+---+
                              |
                              |
                 +-----+      |      +------+    +-----+
           np -> |     |      +----> | head | -> | ... |
                 +-----+             +------+    +-----+
现在,我们设置
np->next=hashtab[hashval]
。现在情况是这样的:

    +---+---+---+---   ---+---------+---+---+---+
    |   |   |   |   ...   | hashval |   |   |   |
    +---+---+---+---   ---+---------+---+---+---+
                              |
                              |
                              |      +------+    +-----+
                              +----> | head | -> | ... |
                                     +------+    +-----+
    +---+---+---+---   ---+---------+---+---+---+
    |   |   |   |   ...   | hashval |   |   |   |
    +---+---+---+---   ---+---------+---+---+---+
                              |
                              |
                 +-----+      |      +------+    +-----+
           np -> |     |------+----> | head | -> | ... |
                 +-----+             +------+    +-----+
    +---+---+---+---   ---+---------+---+---+---+
    |   |   |   |   ...   | hashval |   |   |   |
    +---+---+---+---   ---+---------+---+---+---+
                              |
                    +---------+
                    |
                    v         
                 +-----+             +------+    +-----+
           np -> |     |-----------> | head | -> | ... |
                 +-----+             +------+    +-----+
现在,新创建的单元格的下一个指针和
hashtab[hashval]
都指向同一个对象。从
np
的角度来看,它现在指向通过预先添加新单元格,然后使用所有现有单元格而形成的列表

最后,我们做
hashtab[hashval]=np
,如下所示:

    +---+---+---+---   ---+---------+---+---+---+
    |   |   |   |   ...   | hashval |   |   |   |
    +---+---+---+---   ---+---------+---+---+---+
                              |
                              |
                              |      +------+    +-----+
                              +----> | head | -> | ... |
                                     +------+    +-----+
    +---+---+---+---   ---+---------+---+---+---+
    |   |   |   |   ...   | hashval |   |   |   |
    +---+---+---+---   ---+---------+---+---+---+
                              |
                              |
                 +-----+      |      +------+    +-----+
           np -> |     |------+----> | head | -> | ... |
                 +-----+             +------+    +-----+
    +---+---+---+---   ---+---------+---+---+---+
    |   |   |   |   ...   | hashval |   |   |   |
    +---+---+---+---   ---+---------+---+---+---+
                              |
                    +---------+
                    |
                    v         
                 +-----+             +------+    +-----+
           np -> |     |-----------> | head | -> | ... |
                 +-----+             +------+    +-----+
这会将新元素拼接到链接列表的前面


换言之,这是一个非常典型的列表前置器,使用链表指针数组使其变得更为复杂。

让我们通过跟踪此代码来了解它的功能:

np->next = hashtab[hashval]; // WHAT THE HECK ARE THEY DOING HERE?!?!
hashtab[hashval] = np;
最初,我们的哈希表如下所示:

    +---+---+---+---   ---+---------+---+---+---+
    |   |   |   |   ...   | hashval |   |   |   |
    +---+---+---+---   ---+---------+---+---+---+
                              |
                              |
                              |      +------+    +-----+
                              +----> | head | -> | ... |
                                     +------+    +-----+
    +---+---+---+---   ---+---------+---+---+---+
    |   |   |   |   ...   | hashval |   |   |   |
    +---+---+---+---   ---+---------+---+---+---+
                              |
                              |
                 +-----+      |      +------+    +-----+
           np -> |     |------+----> | head | -> | ... |
                 +-----+             +------+    +-----+
    +---+---+---+---   ---+---------+---+---+---+
    |   |   |   |   ...   | hashval |   |   |   |
    +---+---+---+---   ---+---------+---+---+---+
                              |
                    +---------+
                    |
                    v         
                 +-----+             +------+    +-----+
           np -> |     |-----------> | head | -> | ... |
                 +-----+             +------+    +-----+
以下是
np

    +---+---+---+---   ---+---------+---+---+---+
    |   |   |   |   ...   | hashval |   |   |   |
    +---+---+---+---   ---+---------+---+---+---+
                              |
                              |
                 +-----+      |      +------+    +-----+
           np -> |     |      +----> | head | -> | ... |
                 +-----+             +------+    +-----+
现在,我们设置
np->next=hashtab[hashval]
。现在情况是这样的:

    +---+---+---+---   ---+---------+---+---+---+
    |   |   |   |   ...   | hashval |   |   |   |
    +---+---+---+---   ---+---------+---+---+---+
                              |
                              |
                              |      +------+    +-----+
                              +----> | head | -> | ... |
                                     +------+    +-----+
    +---+---+---+---   ---+---------+---+---+---+
    |   |   |   |   ...   | hashval |   |   |   |
    +---+---+---+---   ---+---------+---+---+---+
                              |
                              |
                 +-----+      |      +------+    +-----+
           np -> |     |------+----> | head | -> | ... |
                 +-----+             +------+    +-----+
    +---+---+---+---   ---+---------+---+---+---+
    |   |   |   |   ...   | hashval |   |   |   |
    +---+---+---+---   ---+---------+---+---+---+
                              |
                    +---------+
                    |
                    v         
                 +-----+             +------+    +-----+
           np -> |     |-----------> | head | -> | ... |
                 +-----+             +------+    +-----+
现在,新创建的单元格的下一个指针和
hashtab[hashval]
都指向同一个对象。从
np
的角度来看,它现在指向通过预先添加新单元格,然后使用所有现有单元格而形成的列表

最后,我们做
hashtab[hashval]=np
,如下所示:

    +---+---+---+---   ---+---------+---+---+---+
    |   |   |   |   ...   | hashval |   |   |   |
    +---+---+---+---   ---+---------+---+---+---+
                              |
                              |
                              |      +------+    +-----+
                              +----> | head | -> | ... |
                                     +------+    +-----+
    +---+---+---+---   ---+---------+---+---+---+
    |   |   |   |   ...   | hashval |   |   |   |
    +---+---+---+---   ---+---------+---+---+---+
                              |
                              |
                 +-----+      |      +------+    +-----+
           np -> |     |------+----> | head | -> | ... |
                 +-----+             +------+    +-----+
    +---+---+---+---   ---+---------+---+---+---+
    |   |   |   |   ...   | hashval |   |   |   |
    +---+---+---+---   ---+---------+---+---+---+
                              |
                    +---------+
                    |
                    v         
                 +-----+             +------+    +-----+
           np -> |     |-----------> | head | -> | ... |
                 +-----+             +------+    +-----+
这会将新元素拼接到链接列表的前面


换句话说,这是一个非常典型的列表前缀,使用链表指针数组会使它变得有点棘手。

您看到的是将新节点作为列表中的第一个节点插入的基本习惯用法

如果
head
指向列表的当前开头(空列表为空指针),并且
node
指向新节点,则只需

node->next = head;
head = node;
你就完了

这两行代码正是您在引用的K&R代码中看到的

您的代码版本坚持在列表末尾插入新节点。在散列集的基本实现中,bucket中元素的顺序实际上并不重要,这就是为什么K&R实现只是在每个bucket的开头插入新节点。正如您所看到的,它非常简单和高效

如果您想按照每个bucket的节点到达的顺序存储它们,那么必须在列表的末尾添加新节点,这在您的实现中效率明显较低。但是,如果您坚持这样做,您可以使用另一种惯用的方法,这允许您避免对空桶执行特殊的
if
分支

struct nlist **pnext = &hashtab[hashval];
for (; *pnext != NULL; pnext = &(*pnext)->next);

*pnext = np;
np->next = NULL;

当然,更有效的方法是为每个bucket存储两个指针:指向列表的第一个和最后一个元素。

您看到的是将新节点作为列表中的第一个节点插入的基本习惯用法

如果
head
指向列表的当前开头(空列表为空指针),并且
node
指向新节点,则只需

node->next = head;
head = node;
你就完了

这两行代码正是您在引用的K&R代码中看到的

您的代码版本坚持在列表末尾插入新节点。在散列集的基本实现中,bucket中元素的顺序实际上并不重要,这就是为什么K&R实现只是在每个bucket的开头插入新节点。正如您所看到的,它非常简单和高效

如果您想按照每个bucket的节点到达的顺序存储它们,那么必须在列表的末尾添加新节点,这在您的实现中效率明显较低。但是,如果您坚持这样做,您可以使用另一种惯用的方法,这允许您避免对空桶执行特殊的
if
分支

struct nlist **pnext = &hashtab[hashval];
for (; *pnext != NULL; pnext = &(*pnext)->next);

*pnext = np;
np->next = NULL;

当然,一种更有效的方法是为每个bucket存储两个指针:指向列表的第一个和最后一个元素。

它们插入到链接列表的头部。插入到链接列表的头部意味着插入是O(1),而不是O(n),就像遍历列表以找到结尾一样。有时,需要结束插入的列表也会在控制块中存储一个“结束”指针以避免这种情况。@0xsmash0th:What't
phE
?在代码的其他任何地方都没有提到它。它们是插入到链表的开头。插入到链表的开头意味着插入是O(1),而不是O(n),就像遍历列表以找到结尾一样。有时,需要结束插入的列表也会在控制块中存储一个“结束”指针以避免这种情况。@0xsmash0th:What't
phE
?在你的代码中没有提到它。我确实错过了他们所做的事情的要点!我从来没有想过预挂!伟大的绘画也很有帮助!我真的错过了他们所做的事情的要点!我从来没有想过预挂!伟大的绘画也很有帮助!非常有帮助,我完全有一个心理障碍,就是只需要在末尾添加一个节点。如果我将来需要挂起一个节点,我将使用这个for循环!非常有帮助,我完全有一个心理障碍,就是只需要在末尾添加一个节点。如果我将来需要挂起一个节点,我将使用这个for循环!