使用递归创建链接列表

时间:2015-08-06 01:42:57

标签: c recursion linked-list

我想使用递归创建链接列表。执行代码后,我只得到第一个节点的值,而其余的不被打印。

#include<stdio.h>
#include<malloc.h>

typedef struct node NODE;

struct node
{
    int data;
    struct node *next;
} *start=NULL,*ptr;

void display();
int create(int);

int main()
{
    int n;
    printf("\nEnter the no of node?\t");
    scanf("%d",&n);
    create(n);
    display();
}
int create(int x) 
{
    if(x==0)
        return;

    else{
        NODE *node;
        node=((NODE *)malloc(sizeof(NODE)));

        printf("Enter the data:\n");
        scanf("%d",&node->data);

        node->next=NULL;
        if(start==NULL)
        {
            ptr=start=node;
        }
        else
        {
            ptr=node->next;
            ptr=node;
        }   
        ptr->next=NULL;
    }
    create(x-1);
}

void display()
{
    NODE *ds;
    ds=start;
    while(ds!=NULL)
    {
        printf("%d->",ds->data);
        ds=ds->next;
    }   
}

我认为问题是我打电话给create(x-1);,但我不确定。 我的逻辑是否正确?有人可以指出我的错误吗?

3 个答案:

答案 0 :(得分:2)

尝试更改逻辑,

int create(int x) {
    if (x == 0)
        return 0;
    else {
        NODE *node;
        node = ((NODE *) malloc(sizeof (NODE)));
        printf("Enter the data:\n");
        scanf("%d", &node->data);
        node->next = NULL;
        if (start == NULL) {
            ptr = start = node;
        } else {
            //ptr = node->next;
            ptr->next = node;
            ptr = node;
        }
        ptr->next = NULL;
    }
    create(x - 1);
}

您没有正确重置头部。

检查此实施方案也很好&gt; http://geeksquiz.com/linked-list-set-1-introduction/

答案 1 :(得分:0)

当你这样做时:

ptr=node->next;
ptr=node;

您丢失了对列表尾部的引用,因此未将node添加到列表中。你应该这样做:

ptr->next = node;
ptr = ptr->next;

这会将当前尾部的next指针指向新节点,然后将ptr向下移动到新尾部。

此外,循环结束时的ptr->next=NULL是不必要的,因为ptr现在与node相同,而您已经node->next = NULL

答案 2 :(得分:0)

导致问题的重大错误是您在create(int)中指定了指针。您正确分配了第一个指针,但随后将NULL分配给所有剩余的指针。有几种方法可以解决这个问题,但干净而直接的方法是仅在ptr=ptr->next块中推进else,如下所示:

if (start == NULL)
{
    ptr = start = node;
}
else
{
    ptr->next = node;
    ptr = ptr->next;
}   

您正在动态分配内存,因此这意味着您负责跟踪其使用,保留指向每个分配的起始块的指针,最后在不再使用时释放内存。现在开始。养成在分配时处理内存清理的习惯,而不是简单地依赖程序退出来为你做。虽然现在看起来似乎微不足道,但是当你开始使用多个分配来处理函数时,如果你没有在这方面养成良好的习惯,你的代码可能会像筛子那样泄漏内存。简单的清理功能只不过是:

void destroy()
{
    if (!start) return;

    NODE *ds = start;
    while (ds != NULL)
    {
        NODE *victim = ds;
        ds = ds->next;
        free (victim);
    }
}

malloc问题。 malloc返回分配的内存块的起始地址,不需要在C中转换返回。当您为刚刚声明的数据类型分配内存时,请使用带sizeof的变量的数据类型。 e.g:

NODE *node;
node = malloc (sizeof *node);

而不是

node = malloc (sizeof (NODE));

在处理指针等指针时,这将变得很明显。对变量进行操作比记住是否为NODE*NODE**进行分配更有意义。当分配在代码中的声明下面很多行或者在函数参数列表中接收指针时,尤其如此。

此外,每次分配内存时都需要验证malloc的返回值,以确保您没有耗尽可用内存。 e.g:

NODE *node;
if (!(node = malloc (sizeof *node))) {
    fprintf (stderr, "error: virtual memory exhausted\n");
    exit (EXIT_FAILURE);
}

最后,总结一下,解决问题的方法之一是:

#include <stdio.h>
#include <stdlib.h>   /* for exit & EXIT_FAILURE */

typedef struct node NODE;

struct node {
    int data;
    struct node *next;
} *start=NULL,*ptr;

void display();
void create (int);
void destroy();

int main (void)
{
    int n;
    printf ("\nEnter the no of node: ");
    scanf ("%d",&n);
    create (n);
    display();
    destroy();
    return 0;
}

void create (int x) 
{
    if (x == 0) return;

    NODE *node;
    if (!(node = malloc (sizeof *node))) {
        fprintf (stderr, "error: virtual memory exhausted\n");
        exit (EXIT_FAILURE);
    }

    printf ("Enter the data: ");
    scanf ("%d",&node->data);

    node->next = NULL;
    if (start == NULL)
    {
        ptr = start = node;
    }
    else
    {
        ptr->next = node;
        ptr = ptr->next;
    }   

    create (x-1);
}

void display()
{
    if (!start) return;

    NODE *ds = start;
    while (ds != NULL)
    {
        if (ds == start)
            printf ("%d", ds->data);
        else
            printf("->%d", ds->data);
        ds = ds->next;
    }
    printf ("\n");
}

void destroy()
{
    if (!start) return;

    NODE *ds = start;
    while (ds != NULL)
    {
        NODE *victim = ds;
        ds = ds->next;
        free (victim);
    }
}

示例

$ ./bin/llrecurse

Enter the no of node: 4
Enter the data: 2
Enter the data: 4
Enter the data: 6
Enter the data: 8
2->4->6->8

使用内存检查器

无论您的平台如何,最好使用内存检查程序(如Linux上的valgrind)来检查内存错误并确保已释放已分配的所有内存。内存检查器不仅可以确认所有内存已被释放,而且还会报告您尝试访问已分配内存的方式中的细微错误,这可以提醒您以后可能会遇到的问题。简单易用:

$ valgrind ./bin/llrecurse
==17434== Memcheck, a memory error detector
==17434== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==17434== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==17434== Command: ./bin/llrecurse
==17434==

Enter the no of node: 4
Enter the data: 2
Enter the data: 4
Enter the data: 6
Enter the data: 8
2->4->6->8
==17434==
==17434== HEAP SUMMARY:
==17434==     in use at exit: 0 bytes in 0 blocks
==17434==   total heap usage: 4 allocs, 4 frees, 64 bytes allocated
==17434==
==17434== All heap blocks were freed -- no leaks are possible
==17434==
==17434== For counts of detected and suppressed errors, rerun with: -v
==17434== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)

这应该让你开始,如果你早点学习好习惯,随着你进一步使用C语言进行编程,管理内存将变得更加容易。