【问题标题】:Delete Node - Linked List - C删除节点 - 链表 - C
【发布时间】:2019-05-10 22:32:18
【问题描述】:

我正在尝试从链表中删除一个节点,但我对双指针的概念仍然很陌生,所以我尝试使用全局变量来保存头指针。但是,在删除中间节点后尝试打印列表时,我得到了错误的结果。

我看到了这个问题 deleting a node in the middle of a linked list 我不知道我的删除节点功能与答案有何不同。

这是我的代码:

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

typedef unsigned char u8;
typedef struct Node node;
void addfirstnode( u8 );
void addnode( u8 );
void print( void );
void deletenode( u8 key );
void deleteonlynode();
void deletefirstnode();

struct Node
{
    u8 x;
    node *next;
};
node *head;
u8 length = 0;


void main( void )
{
    u8 x;
    printf( "\nTo add node enter 0\nTo print linked list enter 1\nTo exit press 2\nTo delete node press 3\nYour Choice:" );
    scanf( "%d", &x );
    if ( x == 2 )
    {
        printf( "\nThank You\nGood Bye" );
    }
    while ( x != 2 )
    {
        switch ( x )
        {
            u8 n;
            u8 key;
            case 0:            //Add node
                printf( "\nPlease enter first value:" );
                scanf( "%d", &n );
                if ( length == 0 )
                {
                    addfirstnode( n );
                    //printf("%d",head->x);
                }
                else
                {
                    addnode( n );
                }
                printf( "\nNode added , Thank you\n" );
                break;

            case 1:            //Print
                print();
                break;

            case 3:            //DeleteNode
                printf( "\nPlease enter value to be deleted:" );
                scanf( "%d", &key );
                deletenode( key );
                //deletefirstnode();
                break;

            default:
                printf( "\nInvalid Choice please try again\n" );
        }
        printf( "\nTo add node enter 0\nTo print linked list enter 1\nTo exit press 2\nTo delete node press 3\nYour Choice:" );
        scanf( "%d", &x );
        if ( x == 2 )
        {
            printf( "\nThank You\nGood Bye" );
        }
    }
    //where do I use free();
}

void addfirstnode( u8 n )
{
    head = ( node * ) malloc( sizeof( node ) );
    head->next = NULL;
    head->x = n;
    length++;
}

void addnode( u8 n )
{
    node *last = head;
    while ( ( last->next ) != NULL )
    {
        last = last->next;
    }
    last->next = ( node * ) malloc( sizeof( node ) );
    ( last->next )->next = NULL;
    ( last->next )->x = n;
    length++;
}

void print( void )
{
    node *last = head;
    u8 count = 1;
    printf( "\n---------------------" );
    if ( last == NULL )
    {
        printf( "\nList is empty" );
    }
    while ( last != NULL )
    {
        printf( "\nNode Number %d = %d", count, last->x );
        last = last->next;
        count++;
    }
    printf( "\n---------------------" );
    printf( "\n" );
}

void deletenode( u8 key )
{
    node *last = head;
    //node*postlast = NULL;
    if ( ( last->x == key ) && ( last->next == NULL ) )
    {
        deleteonlynode();
    }
    else
    {
        while ( last != NULL )
        {
            if ( ( last->x ) == key )
            {
                printf( "value to be deleted is found" );
                node *temp = last->next;
                last->next = last->next->next;
                free( temp );
                length--;
            }
            last = last->next;
        }
    }
}

void deleteonlynode()
{
    printf( "\n Deleting the only node" );
    free( head );
    head = NULL;
    length--;
}

void deletefirstnode()
{
    printf( "\n Deleting the first node" );
    node *temp = head;
    head = head->next;
    free( temp );
    length--;
}

【问题讨论】:

  • 为什么几乎所有初学者都投malloc?你在哪里学的?
  • @Broman 我最初认为这是唯一的方法,但你的问题让我查了一下,我发现了这个link
  • 但我很好奇。你从哪里得到这个想法的?这不像是在没有人告诉你的情况下你做的事情。
  • @Broman 我可能在 tutorialspoint 的代码示例中看到了它,并猜测这是唯一的方法。
  • 这就解释了。不要相信那个网站。

标签: c linked-list global-variables


【解决方案1】:

代码正在从链表中删除错误的项目:

见:

        if ( ( last->x ) == key )
        {
            printf( "value to be deleted is found" );
            node *temp = last->next;     // last->next? No, just last.
            last->next = last->next->next;
            free( temp );
            length--;
        }

last 指向要删除的元素。但随后代码将temp 分配为指向last-&gt;next(而不是last),然后将其从列表中删除。

因此,通过查看node-&gt;next 而不是当前节点,可以将其修剪掉,因为您是从要删除的指针之前的指针开始的。基本上你的代码已经差不多了。

void deletenode( u8 key )
{
    node *ptr = head;

    if ( ( ptr->x == key ) )
    {
        // Delete the first/head element
        node *temp = ptr;
        head = head->next;
        free( temp );
        length--;
    }
    else
    {
        while ( ptr->next != NULL )
        {
            if ( ( ptr->next->x ) == key )
            {
                printf( "value to be deleted is found" );
                node *temp = ptr->next;
                ptr->next = ptr->next->next;
                free( temp );
                length--;
            }
            ptr = ptr->next;
        }
    }
}

我还冒昧地将last 重命名为ptr,因为这让我很困惑。

编辑:更新后也可以干净地移除头部。

【讨论】:

  • 非常感谢我现在明白了
  • 我更新了函数,如果在那里找到密钥,也可以删除第一个节点:if ((last-&gt;x == key)) { deletefirstnode(); } 但是当我使用这个条件时//if ((last-&gt;x == key) &amp;&amp; (last == head)) 函数不能正常工作,在这里是实现:void deletefirstnode() { printf("\n Deleting the first node"); node* temp = head; head = head-&gt;next; free(temp); length--; }
  • 如果需要移除头节点,只需保留指向它的指针,然后head = head-&gt;next;。不要试图让它变得复杂 ;) head-&gt;next 要么是 NULL 要么只是另一个节点指针。
  • 顺便说一句:您注意到删除功能中的错误了吗?它实际上是删除所有匹配的非头节点。 break 会修复它。
  • 是的,你是对的,我没有注意到那个错误。非常感谢我会添加一个休息时间。
【解决方案2】:

您的代码似乎正在删除last-&gt;next,而last 应该是与键匹配的节点。 我猜下面的代码可能会更短,并进行删除

node* head;

/* returns the node* the previous_node->next should be after the deletion */
node* delete_node(node* current, u8 key) {
    if (current == NULL) return NULL;  // deletion comes to end
    if (head->x == key) {
        node* temp = current->next;
        free(current);
        return delete_node(temp, key);
    }
    current->next = delete_node(current->next, key);
    return current;
}


int main() {
    // build the linked list
    // ...
    head = delete_node(head, key);
    return 0;
}

但是,如果列表太长,此工具(使用递归而不是循环)可能会导致 StackOverFlow。我没有测试 gcc 是否会优化递归。

【讨论】:

  • 我仍在处理短名单,所以我认为这不会成为问题。非常感谢
猜你喜欢
  • 2021-07-25
  • 1970-01-01
  • 1970-01-01
  • 2017-10-21
  • 2013-08-30
  • 2016-01-02
  • 2019-05-10
  • 2016-03-02
  • 1970-01-01
相关资源
最近更新 更多