【问题标题】:deleting node from a singly linked list从单链表中删除节点
【发布时间】:2020-02-04 17:35:15
【问题描述】:

我有一个简单的函数,可以从单个链表中搜索具有给定键的节点并将其删除。 当具有给定键的节点无处不在时,该函数起作用,除非该节点是列表的头部。 为什么会这样?

#include<stdio.h>
#include<stdlib.h>


struct Node{
    int data;
    struct Node* next;
};

void printlist(struct Node* node){
    while(node!=NULL){
        printf("%d", node->data);
        node = node->next;
    }
    printf("\n");
}

/* Given a reference (pointer to pointer) to the head of a list 
   and a key, deletes the first occurrence of key in linked list */
void deleteNode(struct Node* head, int key){
    if(head->data==key){
        head = head->next;
    }
    else {
        while(head->next->data!=key){
            head = head->next;
        }
        head->next = head->next->next;
    }
}

int main(){

    struct Node* first = (struct Node*)malloc(sizeof(struct Node));
    struct Node* second = (struct Node*)malloc(sizeof(struct Node));
    struct Node* third = (struct Node*)malloc(sizeof(struct Node));
    first->data = 1;
    second->data = 2;
    third->data = 3;
    first->next = second;
    second->next = third;
    third->next = NULL;

    printlist(first); // prints 123

    deleteNode(first, 2);  
    printlist(first); // prints 13

    deleteNode(first, 1);
    printlist(first); // still prints 13
}

【问题讨论】:

  • 在第二次调用deleteNode 之后,您认为first 指向什么?线索:在第一次致电deleteNode 后,您认为它指向什么?
  • 虽然您的函数的注释是正确的,但原型不对应,您没有发送指向指针的指针;) 尝试在发送 &amp;first 时使其工作,而不仅仅是 first
  • @Angevil - 当您输入您的评论时,我正在输入我的答案。也许我做的太多了?让我们看看OP的感受。
  • @Adrian 我习惯教C,所以我更喜欢提供线索而不是解决方案^=^
  • 我也在教学/学习环境中工作。但是,有时,更广泛的“线索”可能会有所帮助:以身作则。

标签: c linked-list reference singly-linked-list


【解决方案1】:

当您调用此函数时:void deleteNode(struct Node* head, int key) 的第一个参数是指向 Node 结构的指针(就像您在 main 中所做的两次一样),那么函数接收的第一个参数是 你给的指针的副本

您可能知道一个函数:void Increment(int n) 可以对它传递的n 做任何它喜欢的事情,而无需更改调用模块中的变量。所以,如果你想让函数真正改变调用块中的值,你给它一个指针:

void Increment(int* n) {
    ++(*n);
}

同样,如果您希望函数更改指针,则必须将 指向该指针的指针传递给它。试试这个:

void deleteNode(struct Node** head, int key){
    Node* temp = *head;
    if(temp->data==key){
        *head = temp->next; // Only need to change *head if its the first one ...
    }
    else {
        while(temp->next->data!=key){
            temp = temp->next;
        }
        temp->next = temp->next->next; // ... else we have already changed the actual "links"
    }
}

并且,在main 中,使用:

deleteNode(&first, 2);

和:

deleteNode(&first, 1);

让我们知道会发生什么。

注意:顺便说一句,这不是“最好的代码” - 通过删除链接而不实际删除指向的对象,您正在造成内存泄漏。

注意 2:另外,如果没有找到 key,当你的代码找到一个 NULL next 指针时,你的代码将“脱落”到列表的末尾!

【讨论】:

    【解决方案2】:

    该函数处理原始头部的副本。因此副本的更改不会影响原始节点。您应该通过指针通过引用传递头节点,或者从函数返回更改后的头节点。您还必须在函数的开头检查头节点是否等于 NULL。否则该函数会调用未定义的行为。

    例如

    void deleteNode( struct Node **head, int key )
    {
        while( *head != NULL && ( *head )->data != key ) head = &( *head )->next;
    
        if ( *head != NULL ) *head = ( *head )->next;
    }
    

    然后这样称呼它

    deleteNode( &first, 1 );
    

    这是一个演示程序

    #include<stdio.h>
    #include<stdlib.h>
    
    struct Node{
        int data;
        struct Node* next;
    };
    
    void printlist(struct Node* node){
        while(node!=NULL){
            printf("%d", node->data);
            node = node->next;
        }
        printf("\n");
    }
    
    /* Given a reference (pointer to pointer) to the head of a list 
       and a key, deletes the first occurrence of key in linked list */
    void deleteNode( struct Node **head, int key )
    {
        while( *head != NULL && ( *head )->data != key ) head = &( *head )->next;
    
        if ( *head != NULL ) *head = ( *head )->next;
    }
    
    int main(){
    
        struct Node* first = (struct Node*)malloc(sizeof(struct Node));
        struct Node* second = (struct Node*)malloc(sizeof(struct Node));
        struct Node* third = (struct Node*)malloc(sizeof(struct Node));
        first->data = 1;
        second->data = 2;
        third->data = 3;
        first->next = second;
        second->next = third;
        third->next = NULL;
    
        printlist(first); // prints 123
    
        deleteNode(&first, 2);  
        printlist(first); // prints 13
    
        deleteNode(&first, 1);
        printlist(first); // still prints 13
    }
    

    它的输出是

    123
    13
    3
    

    或者

    struct Node * deleteNode( struct Node *head, int key )
    {
        if ( head != NULL )
        {
            if ( head->data == key )
            {
                head = head->next;
            }
            else 
            {
                struct Node *current = head;
                while( current->next != NULL && current->next->data != key )
                {
                    current = current->next;
                }
                if ( current->next != NULL ) current->next = current->next->next;
            }
        }
    
        return head;
    }
    

    然后这样称呼它

    first = deleteNode( first, 1 );
    

    这是另一个演示程序

    #include<stdio.h>
    #include<stdlib.h>
    
    struct Node{
        int data;
        struct Node* next;
    };
    
    void printlist(struct Node* node){
        while(node!=NULL){
            printf("%d", node->data);
            node = node->next;
        }
        printf("\n");
    }
    
    /* Given a reference (pointer to pointer) to the head of a list 
       and a key, deletes the first occurrence of key in linked list */
        struct Node * deleteNode( struct Node *head, int key )
        {
            if ( head != NULL )
            {
                if ( head->data == key )
                {
                    head = head->next;
                }
                else 
                {
                    struct Node *current = head;
                    while( current->next != NULL && current->next->data != key )
                    {
                        current = current->next;
                    }
                    if ( current->next != NULL ) current->next = current->next->next;
                }
            }
    
            return head;
        }
    
    int main(){
    
        struct Node* first = (struct Node*)malloc(sizeof(struct Node));
        struct Node* second = (struct Node*)malloc(sizeof(struct Node));
        struct Node* third = (struct Node*)malloc(sizeof(struct Node));
        first->data = 1;
        second->data = 2;
        third->data = 3;
        first->next = second;
        second->next = third;
        third->next = NULL;
    
        printlist(first); // prints 123
    
        first = deleteNode(first, 2);  
        printlist(first); // prints 13
    
        first = deleteNode(first, 1);
        printlist(first); // still prints 13
    }
    

    它的输出又是

    123
    13
    3
    

    通常列表的节点是动态分配的。所以删除节点的函数也应该释放被删除的节点或从函数中返回它。

    【讨论】:

    • 几乎同时出现的答案一直在发生,@Adrian。这是不可避免的。不要担心。只要确保你的尽可能好,然后等待。如果您的仍然是,则很有可能会被选中。没有人有义务删除他们自己的独立答案,因为它与另一个人有相同的基础。这通常意味着两个答案大部分都是正确的。放松!
    猜你喜欢
    • 2021-02-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-14
    相关资源
    最近更新 更多