如果同一索引中的下一个节点不为 NULL,如何删除单向链表链接哈希表的第一个节点?

问题描述

这是我的功能,如果我用这个功能删除一个节点,它会删除所有剩余的节点->下一个节点,有人可以帮我吗?

struct node* popCH(char ex[]){
    int hash_index = Hash(ex);
    node* temp = head[hash_index];
    
    if(temp==NULL){
        return NULL;
    }
    
    while(temp->next!=NULL && strcmp(temp->next->ex,ex)!=0){
            temp=temp->next;
        }

    if(temp->next==NULL && strcmp(temp->ex,ex)==0){
        free(temp);
        temp=NULL;
        head[hash_index]=NULL;
    }
    
    else if(temp->next!=NULL && strcmp(temp->ex,ex)==0){
        node* temp2 = temp;
        temp = temp->next;
        temp = head[hash_index]->next;
        free(temp2);
        temp2=NULL;
    }
}

解决方法

您应该使用指向节点的指针的指针,以便可以删除该节点并且将指向该节点的指针更新为指向下一个节点,而不管该指针是节点中某个指针的头指针。

struct data* popCH(char ex[]){
    int hash_index = Hash(ex);
    node** temp = &head[hash_index];
    
    if(*temp==NULL){
        return NULL;
    }
    
    while(*temp!=NULL && strcmp((*temp)->ex,ex)!=0){
        temp=&(*temp)->next;
    }

    if(*temp!=NULL){
        node *temp2 = (*temp)->next;
        free(*temp);
        *temp=temp2;
    }

    /* return something not to let caller invoke undefined behavior by using the return value */
    return NULL;
}
,

一种方法是使用指针到指针,一个很好的答案已经涵盖了这一点。

另一种只是简单地跟踪指向前一个节点的指针,当没有前一个节点时该指针为空:

node *prev = NULL;

while (temp != NULL && strcmp(temp->ex,ex) != 0) {
   prev = temp;
   temp = temp->next;
}

if (temp != NULL) { // found matching node
   // retain data pointer to return before freeing
   struct data *data = temp->data;

   // two deletion cases: middle of chain or front
   if (prev)
     prev->next = temp->next;
   else
     head[hash_index] = temp->next;

   free(temp);
   return data;
}

// not found
return NULL;

如果我们给链一个代理父级,我们就可以避免出现两次删除的情况。也就是说,我们在链表的前面添加一个虚拟节点,作为第一个节点的前一个节点:

struct data* popCH(const char *ex){
    int hash_index = Hash(ex);
    // transfer chain into fake extra previous node:
    struct node parent = { .next = head[hash_index] };
    node *prev = &parent;
    node *temp = prev->next;
    

    while (temp != NULL && strcmp(temp->ex,ex) != 0) {
       prev = temp;
       temp = temp->next;
    }

    if (temp != NULL) { // found matching node
       // retain data pointer to return before freeing
       struct data *data = temp->data;

       // splice temp out of list by getting
       // the previous node to skip it
       prev->next = temp->next;

       // transfer updated chain back into table:
       head[hash_index] = parent.next;

       free(temp);
       return data;
    }

    // not found
    return NULL;
}

我们从代码中删除了一些测试,但是有一些不必要的内存写入。在返回之前,我们分配给 head[hash_index] 是否真的有必要;只有 parent.next 发生了变化。此外,我们分配了一个完整的 node 局部变量并初始化了它的所有字段,即使我们只访问过`.我们可以通过避免初始化器来避免这样做:

    int hash_index = Hash(ex);
    // transfer chain into fake extra previous node:
    struct node parent;
    node *prev = &parent;
    node *temp = head[hash_index];

    // initialize just parent.next member by assignment;
    // other members are left uninitialized.
    parent.next = temp;

    // rest of code ...