将第一个节点添加到hashmap中的链表时,为啥必须将新节点直接分配给索引指针?

Posted

技术标签:

【中文标题】将第一个节点添加到hashmap中的链表时,为啥必须将新节点直接分配给索引指针?【英文标题】:When adding first node to linked list in hashmap, why must the new node be assigned directly to the indexed pointer?将第一个节点添加到hashmap中的链表时,为什么必须将新节点直接分配给索引指针? 【发布时间】:2020-01-31 02:16:23 【问题描述】:

这是我在 c 中实现的 hashmap 及其初始化和插入代码。 在 hashmap_t 结构中,我使用指向包含键/值对的节点的指针数组(表)。在 hashmap_init 中,我分配所需数量的节点并循环遍历数组,将每个指针设置为 NULL。

我感到困惑的是 hashmap_put 函数。我找到了应该插入密钥的列表的索引,并且第一个指针由 hm->table[i] 引用。为了清楚起见,我想确保很明显 hm->table[i] 是列表的开头,因此我将其分配给 hashnode_t *head。

所以在插入第一个节点(head == NULL)时,我最初使用了 head = new_node,但我的插入都没有工作。它仅在我使用 hm->table[i] = new_node 时有效。

我不明白为什么会这样。 head 指向相同的东西,为什么设置 head 等于 new_node 不起作用?当 last->next = new_node 确实起作用时,我稍后在函数中也会感到困惑。 last 是一个指针,就像 head 一样,但它在那里工作。

感谢您的澄清。

typedef struct hashnode 
  char key[128];                
  char val[128];                
  struct hashnode *next;        
 hashnode_t;

typedef struct 
  int item_count;             
  int table_size;              
  hashnode_t **table;          
 hashmap_t;

void hashmap_init(hashmap_t *hm, int table_size) 
  hm->table_size = table_size;
  hm->item_count = 0;
  hm->table = malloc(table_size * sizeof(hashnode_t)); 
  for (int i = 0; i < table_size; i++)  // loop through array of pointers to nodes
    hm->table[i] = NULL;
  


int hashmap_put(hashmap_t *hm, char key[], char val[]) 
  hashnode_t *new_node = malloc(sizeof(hashnode_t)); // allocate new node
  strcpy(new_node->key, key);
  strcpy(new_node->val, val);
  new_node->next = NULL;

  int i = hashcode(key) % hm->table_size; // index of list hashed to
  hashnode_t *head = hm->table[i];
  hashnode_t *cur = head;
  hashnode_t *last;

  if (!head)  // list is empty
    new_node->next = head;
    hm->table[i] = new_node;
    //why does head = new_node not work?
    hm->item_count += 1;
    return  1;
  

  while (cur)  // loop through nodes
    if (strcmp(cur->key, key) == 0) 
      strcpy(cur->val, val);
      free(new_node);
      return 0;
    
    last = cur; // save pointer to node that points to NULL
    cur = cur->next;
  
  last->next = new_node;
  //why does it work here?
  hm->item_count += 1;
  return 1;


【问题讨论】:

【参考方案1】:

'head' 指向一个 hashnode_t,'hm->table[i]' 也是如此。因此,它们都指向同一个对象。改变“头”只会使“头”指向其他地方。您实际上并未将 hashmap_t 中的指针分配给“new_node”。

'last' 起作用的原因是您将成员变量更改为新值。并且,由于“last”指向已经在 hashmap_t 中的对象,因此分配更新了 hastmap_t 中指向的对象。因此,对 'last->next = new_node' 的更新与 'hm->table[x]->next = new_node' 相同('x' 是一些任意索引)。

【讨论】:

哦,好吧,这很有意义!有没有办法在不直接执行 hm->table[i] = new_node 的情况下将 hashmap 中的指针分配给新节点?或者那是不可能的。我只是喜欢 head = new_node 看起来多么干净。 这是可能的,但是您需要使用指针地址重构代码,添加令人困惑的解引用并添加额外的错误检查。它会使代码更难阅读。

以上是关于将第一个节点添加到hashmap中的链表时,为啥必须将新节点直接分配给索引指针?的主要内容,如果未能解决你的问题,请参考以下文章

HashMap源码解读

HashMap源码解读

#yyds干货盘点# 面试必刷TOP101:链表中的节点每k个一组翻转

[LeetCode]138复制带随机指针的链表

为啥我的链表内容在退出函数时会消失?

c中的链表返回负数而不是添加节点