【问题标题】:What is wrong with this linked list delete tail node function?这个链表删除尾节点功能有什么问题?
【发布时间】:2011-04-26 07:06:14
【问题描述】:

我写了这个函数来删除单链表的最后一个节点。

问题是,它可以删除除第一个/起始节点之外的所有节点。

这段代码 sn-p 缺少什么?

请回答我的特殊问题。

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

struct Node
{
    char CharContent;
    struct Node * NextNodePointer;
};
typedef struct Node Node;

#pragma region Prototypes
Node * CreateNewNode(char ch);
Node * AddNode(Node * start, Node * newNode);
void DeleteTailNode(Node * start);
void PrintAllNodes(const Node * start);
#pragma endregion Comments

main()
{
    Node * start = NULL;
    Node * newNode = NULL;

    start = AddNode(start, CreateNewNode('A'));
    start = AddNode(start, CreateNewNode('B'));
    start = AddNode(start, CreateNewNode('C'));
    start = AddNode(start, CreateNewNode('D'));
    PrintAllNodes(start);

    DeleteTailNode(start);
    PrintAllNodes(start);
    DeleteTailNode(start);
    PrintAllNodes(start);
    DeleteTailNode(start);
    PrintAllNodes(start);
    DeleteTailNode(start);
    PrintAllNodes(start);
    DeleteTailNode(start);
    PrintAllNodes(start);

    getch();
}

#pragma region Node * CreateNewNode(char ch)
Node * CreateNewNode(char ch)
{
    struct Node * newNode = (struct Node *) malloc(sizeof(struct Node *));

    newNode->CharContent = ch;
    newNode->NextNodePointer = NULL;

    return newNode;
}
#pragma endregion Comment

#pragma region UnifiedAddNode()
Node * AddNode(Node * start, Node * newNode)
{
    Node * copyOfStart = start;

    if(start == NULL)
    {
        return newNode;
    }
    else
    {
        while(copyOfStart->NextNodePointer != NULL)
        {
            copyOfStart = copyOfStart->NextNodePointer;
        }

        copyOfStart->NextNodePointer = newNode;

        return start;
    }
}
#pragma endregion Comment


void DeleteTailNode(Node * start)
{
    Node * prev = NULL;
    Node * current = start;

    while(current->NextNodePointer != NULL)
    {
        prev = current;
        current = current->NextNodePointer;
    }

    free (current);

    if (prev != NULL)
    {
        prev->NextNodePointer = NULL;
    }
}


#pragma region PrintAllNodes()
void PrintAllNodes(const Node * start)
{
    struct Node * tempRoot = start;

    while(tempRoot != NULL)
    {
        printf("%c, ", tempRoot->CharContent);

        tempRoot = tempRoot->NextNodePointer;
    }

    printf("\n");
}
#pragma endregion Comment

【问题讨论】:

    标签: c singly-linked-list


    【解决方案1】:

    您没有检测到 start 为 NULL 的情况,即列表为空。

    你不想释放下一个节点设置为NULL吗?

    如果开始节点是最后一个节点 prev 将在列表遍历完成时为 NULL,但是当发生这种情况时,您正在删除 (NULL) start-&gt;NextNodePointer,当您想删除 start 本身时。

    试试:

    void DeleteTailNode(Node *& start)
    {
        Node * prev = NULL;
        Node * current = start;
    
        if (start == NULL)
            return;
    
        while(current->NextNodePointer != NULL)
        {
            prev = current;
            current = current->NextNodePointer;
        }
    
        if(current != NULL)
            free(current);
    
        if(current == start)
            start = NULL;
    
        if(prev != NULL)
            prev->NextNodePointer = NULL;
    }
    

    【讨论】:

      【解决方案2】:

      内部CreateNewNode()

      struct Node * newNode = (struct Node *) malloc(sizeof(struct Node *));  
                                                                        ^
                                                                        |  
      
                                                                       Ouch!!
      

      将其更改为:struct Node * newNode = (struct Node *) malloc(sizeof(struct Node));

      编辑 2

      试运行HERE

      【讨论】:

      • 对不起,伙计!这也不起作用。你自己在VC++2008Express上运行过吗?
      • 好吧!您已将参数更改为双指针。我实际上是想避免它。有什么办法可以避免吗?
      • @JMSA:你为什么要避免它?删除最后一个节点后,即A,您必须执行start =NULL,否则PrintAllNodes() 将出现段错误(在这种情况下,start 将是一个悬空指针)。因此,如果不将start 的地址传递给DeleteTailNode,就无法做到这一点。
      • @JMSA:“简单”并不总是“简单”。你刚才看到了。 :-)
      • @Prasoon - 我说的一模一样,我真的很想知道为什么 JMSA 试图避免这种情况
      【解决方案3】:

      你如何理解它是否被删除?如我所见,这里没有任何内容被删除..这是 100% 肯定的内存泄漏..您 not 在 DeleteTailNode 中使用 free ..您只是使分配的内存无法访问..

      编辑:在循环之后调用 free( current )。并且从检查中不需要,如果current为NULL,删除NULL指针是安全的。

      【讨论】:

      • 你做错了(在 else 语句中):使用 free( current ),而不是 free(current->NextNodePointer)
      • @JMSA - 好的,Prasoon 解决方案将完全删除一个节点.. 是一样的,我建议 :)
      • 您正在添加四个“对象”并且您正在尝试删除 5 个。无论如何,这不是问题。您必须为 if (prev != NULL) 添加 else 语句来放置 **start = NULL; **。否则,当前状态未初始化,您正在尝试删除某些内容,没人知道是什么:)
      • 另外,我认为您应该将 start 传递为“Node *”而不是“Node *&”,以便能够在删除指针后将指针重定向到 NULL。
      • 什么?我没明白。我的观点是,问题在于删除最后一个元素。还有什么情况??您仍在从列表末尾删除一个元素。但是当你删除它时,你不能将 start 重定向到指向 NULL,如果你只是将“Node*”传递给函数。你试过了吗?
      猜你喜欢
      • 2017-04-12
      • 2020-05-23
      • 2018-07-31
      • 2018-12-12
      • 2013-10-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多