如何实现链表删除?

时间:2013-09-02 18:07:41

标签: c

#include<stdio.h>

struct node {
    int info;
    struct node *next;
};

typedef struct node *nodeptr;
nodeptr i;
nodeptr q;
nodeptr p;
nodeptr *plist;

nodeptr getnode(void)
{
    nodeptr p;
    p = (nodeptr) malloc(sizeof(struct node));
    return p;
}

void freenode(nodeptr p)
{
    free(p);
}


int main()
{
    int i;
    nodeptr *k;
    int a;
    int *px;
    int r;
    nodeptr end;
    nodeptr s;
    nodeptr start;

    p = getnode();
    q = getnode();
    q = start;
    p = end;

    for (i = 0; i < 6; i++) {
        printf("enter value");
        scanf("%d", &r);
        p = getnode();
        p->info = r;

        q->next = p;

        q = q->next;

    }

    q = start;

    while ((q->next) != NULL) {
        printf("n%d", (q->next)->info);
        q = q->next;
    }

    scanf("%d", &a);
    end = getnode();
    end->info = a;
    end->next = NULL;

    for (q = start; q->next != NULL; q = q->next)
        ;

    q->next = end;
    q = start;

    while ((q->next) != NULL) {
        printf("n%d", (q->next)->info);
        q = q->next;
    }

    for (q = start; q->next->next != NULL; q = q->next)
        ;

    freenode(q->next);
    q->next = NULL;
    q = start;

    while (q->next != NULL) {
        printf("n%d", (q->next)->info);
        q = q->next;
    }


    return 0;
}
在该程序中

进行alist并在最后插入一个元素 在这个元素被删除但列表没有正确显示 只显示最后两个元素 请帮助,以便显示已删除元素的整个列表

2 个答案:

答案 0 :(得分:4)

有很多错误,不幸的是。正如WhozCraig所说,关于这个话题还有很多其他帖子,所以你应该在发帖前搜索一下。但是,既然你有,让我们一起讨论一些问题。

nodeptr i;
nodeptr q;
nodeptr p;
nodeptr *plist;

在这里,您宣布了大量全局变量,其中大多数都是名字不好。什么&#39; i?什么&#39; p?什么&#39; q?再往下,你重新声明变量具有相同的名称。一些具有相同类型,另一些具有不同类型。这使得知道您引用哪个变量会让人感到困惑。

一般来说,避免使用全局变量并选择描述性名称。在这种情况下,您可以摆脱ipq

此外,您永远不会将plist初始化为任何内容;你应养成将变量初始化为一些理智的默认值的习惯。在这种情况下,NULL可能是合适的,但由于您根本不使用该变量,因此可以将其删除。

nodeptr getnode(void)
{
    nodeptr p;
    p = (nodeptr) malloc(sizeof(struct node));
    return p;
}

这很好,但是在C中你不应该将malloc的结果转换为特定类型,因为这被认为是错误形式,并且可能导致细微且难以检测到错误。只需直接从malloc分配回报。

其次,您永远不会检查以确保malloc成功。当然,它不太可能在你的简单程序中失败,但你应养成检查可能失败的函数的返回值的习惯。

你应该将分配的内存初始化为某个默认值,因为malloc返回给你的内存充满了垃圾。在这种情况下,这样的事情似乎是恰当的:

if(p) /* only if we allocated memory. */
    memset(p, 0, sizeof(struct node));

有些时候你可以跳过这个,但清除内存是一种理智的默认做法。

void freenode(nodeptr p)
{
    free(p);
}

这也没关系,但在调用p之前,您应该考虑验证free不是NULL。再次,这归结为稳健性,这是一个很好的习惯。

int main()
{
    int i;
    nodeptr *k;
    int a;
    int *px;
    int r;
    nodeptr end;
    nodeptr s;
    nodeptr start;

同样,这里我们有很多单元化变量,但至少有一些名称更好一些。但请注意发生了什么:

您声明了一个名为i的{​​{1}}类型的变量。但是您已经声明了一个名为int的全局变量i。所以现在,局部范围中的变量(nodeptr阴影(即,它隐藏它)全局变量。因此,在int内,名称main引用i。当有人正在阅读你的程序时,这只会增加混乱。

int

好的......所以,在这里你分配了两个新节点,并使 p = getnode(); q = getnode(); p指向这些节点。到目前为止一切都很好。

q

哎呀......现在这是一个问题。我们现在将 q = start; p = end; p指向qstart分别指向的位置。

那些指向哪里?谁知道。 endstart都是单元化的,因此可以指向任何内容。从现在开始,您的计划展示undefined behavior:这意味着任何都可能发生。最有可能的是,在这种情况下,它只会崩溃。

不幸的是,从这里开始,事情变得更加令人困惑。我不是试图解释一切,而是给出一些一般评论。

end

这个循环应该读取6个整数并将它们放在我们的链表中。这似乎是一件简单的事情,但存在问题。

首先,您永远不会检查 for (i = 0; i < 6; i++) { printf("enter value"); scanf("%d", &r); p = getnode(); p->info = r; q->next = p; q = q->next; } 的返回值以了解输入操作是否成功。正如我之前所说,您应该始终检查可能失败的函数的返回值并相应地处理失败。但在这种情况下,请忽略该规则。

一个很大的问题是scanf指向内存中的随机位置。所以我们处于未定义的行为之地。

另一个大问题是需要考虑两种情况:当列表为空时(即我们第一次在q时向列表中添加数字时)以及列表不为空时(即每隔一次)。这两种情况的行为有所不同。当i == 0我们无法盲目设置i == 0时,因为即使q->next没有指向随机位置,概念上也不会{{1}它在这里使用的方式。

我们需要的是一些额外的逻辑:如果这是我们创建的第一个节点,请将q设置为指向该节点。否则,将q设置为该节点,然后然后设置q

另请注意,您永远不会在任何地方设置q->next,这会导致您的列表不会以NULL结尾(您在此处和其他循环中依赖的东西)。 q = q->next中的p->next修正纠正了这个问题,但一般情况下,如果您的代码需要特定行为(&#34;未链接的节点&{39}}指针点,则应确保为NULL;列表以NULL结尾&#34;)你应该有代码来确保这种行为。

memset

同样,在这里,我们重置getnode以指向仍未未初始化的next并指向垃圾。

    q = start;

这是一个经典的印刷循环。这里没有任何错误,虽然我认为在风格上,q周围的那些括号是过度的,并且使得阅读代码变得比以前更困难。我的指导原则是只有当括号有必要覆盖C 的默认评估顺序时才添加括号,当括号有助于在视觉上向读者解释当如何将表达式分组时在心理上解析代码。

start

除了 while ((q->next) != NULL) { printf("n%d", (q->next)->info); q = q->next; } 的错误检查问题外,这很好,但您不会提示用户输入数字。但是,您正确明确地将q->next指向 scanf("%d", &a); end = getnode(); end->info = a; end->next = NULL; ,这很棒。

scanf

同样,这里的问题是end->next设置为NULL,不幸的是,仍然指向垃圾。

    for (q = start; q->next != NULL; q = q->next)
        ;

这是您第二次输入此代码来打印列表。通常,您应该避免代码重复。如果您发现需要在多个位置使用特定代码块,则将其拆分为函数并使用该函数是有意义的。这使得理解和维护代码变得更容易。

q

由于start位,这个循环很难理解。问问自己&#34;如果我正在阅读此内容,我是否立即确保 q->next = end; q = start; while ((q->next) != NULL) { printf("n%d", (q->next)->info); q = q->next; } 无法为空?&#34;如果你不是,那么你真的应该重写这个循环。

    for (q = start; q->next->next != NULL; q = q->next)
        ;

再次,q->next->next指向q->next,它是酉的。但是,嘿,如果我们还没有崩溃......;)

    freenode(q->next);
    q->next = NULL;
    q = start;

再次......这应该真的是一个功能。

q

为了更好地实现,我将向您推荐其中一个问题(仅搜索&#34;链接列表删除&#34;。Khalid Waseem在此问题中的实现也可能有所帮助,但它& #39;没有很好的文档记录,所以你必须仔细研究和分析代码,以确保你理解它。

答案 1 :(得分:0)

有关更好的理解,请参阅以下实施。

struct node {
    int info;
    struct node *next;
};

typedef struct node node;

//Function to print a given single linked list.
void print_list(node *start)
{
    //Check if the given list is empty. 
    if(start == NULL)
            printf("List Empty!!!");
    else
    {
            printf("Current List:");
            //Visit each node one by one 
            while(start != NULL)
            {
                    printf(" %d", start->info);
                    start = start->next;
            }
    }
}
//Function to insert a node at end of single linked list with given data 
node* insert_at_end(node *start, int data)
{
    node *ptr;

    //Create a new node and assign memory using malloc  
    node* new_node = (node*)malloc(sizeof(node));
    if(new_node != NULL)
    {
        //Initialize new node with data.
        new_node->info = data;
        new_node->next = NULL;
    }
    else
    {   //Panic
        printf("\nMemory not allocated. Insertion failed!!!");
        return start;
    }

    //If input list is empty. then new_node becomes the first node of link list.
    if(start == NULL)
            return new_node;
    else
    {
            //travel to the last node of list
            ptr = start;
            while(ptr->next != NULL)
                    ptr = ptr->next;
            //Attach the newly created node at end of list.
            ptr->next = new_node;
            return start;
    }
}

//Delete a node from the end of a Single linked list
node* delete_at_end(node *start)
{
    node *ptr;

    //If input list is empty. nothing to delete just return. 
    if(start == NULL)
            return NULL;
    //Just one node in the given linked list.
    else if(start->next == NULL)
    {
            //Free the memory assigned to the node.
            free(start);
            return NULL;
    }
    else
    {       //Travel to the second last node of the linked list.
            ptr = start;
            while(ptr->next->next != NULL)
                    ptr = ptr->next;
            //free the last node. 
            free(ptr->next);
            ptr->next = NULL;
            return start;
    }
}

int main()
{
    int i, data;
    node *Head_node = NULL;

    for(i = 1; i<=5 ; i++)
    {
            printf("\nEnter node %d :", i);
            scanf("%d", &data);

            // Insert at End
            Head_node = insert_at_end(Head_node, data);

            // Print current List
            print_list(Head_node);
    }

    for(i = 5; i>=1 ; i--)
    {
            printf("\nDeleting node %d :\n", i);

            // Delete at End
            Head_node = delete_at_end(Head_node);

            // Print current List
            print_list(Head_node);
    }

    return 0;
}