【问题标题】:Node Insertion,Linked Lists节点插入、链表
【发布时间】:2016-08-31 13:47:02
【问题描述】:

我有这段代码,它通过它在开始时插入节点。这段代码还包含一个打印链表的函数,如果为空,它会打印 链表为空。

当我运行此代码时,我的输出为 链接列表为空。

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

void append(node* linkedlist, int data)
{
    node* new_element = NULL;
    new_element = (node*)malloc(sizeof(struct node));
    new_element->data = data;
    if (linkedlist == NULL) {
        linkedlist = new_element;
        new_element->next = NULL;
    }

    else {
        new_element->next = (linkedlist)->next;
        (linkedlist)->next = new_element;
    }
}

int main()
{
    append(start, 4);
    append(start, 5);
    printList(start);
}

更新:

void printList(node* linkedlist)
{
    node* ptr = linkedlist;
    if (linkedlist == NULL) {
        printf("Linked list is empty");
        exit(0);
    }
    else {

        while (ptr != NULL) {
            cout << ptr->data;
            ptr = ptr->next;
        }
    }
}

我可能做错了什么?我应该改变什么才能让它发挥作用?

【问题讨论】:

  • 并且不要使用 C++ 编译器来编译 C。
  • @nobar:void append(node *linkedlist, int data){ 行将无法在 C 中编译,因为 node 不是类型(没有 typedef)。这只是 C 和 C++(的子集)之间的区别之一
  • @KostasRim 我暂时赞成它,我以前做过这种方法,我不知道作为副本传递的值,因此赞成。另外,我会坚持下去多一点看更多答案:)
  • @Downvoter,愿意回答吗?
  • @BOTJr。别担心,这是一个非常常见的错误!

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


【解决方案1】:

你的问题在这里linkedlist = new_element; 将参数传递给函数时,它们是按值传递的。即使您传递了pointer,您实际上也传递了该指针的副本(您可以通过在函数内部和函数外部打印linkedlist 的地址来验证)。语句linkedlist = new_element; 将new_element 分配给一个副本。一旦函数返回,你最终什么都没有(和内存泄漏)。请记住,当您需要更改指针本身时,您必须使用双 pointer **

【讨论】:

  • 或者如果 OP 不想要你的 pointer ** 他们可以返回新的链表:node* append(node *linkedlist,int data){...
  • 或者通过引用void append(node*&amp; linkedlist,int data)
  • @NathanOliver 他使用了malloc(),我假设他放错了 c++ 标签。无论如何,我做了一个编辑,谢谢指出!
  • @KostasRim 不,你是对的。我没有看到 C 标记被删除,仍然认为这是一个 C++ 问题。
【解决方案2】:

您输入了指向 null 的 start 的值。然后将其复制到另一个指针 linkedlist 并将其设置为新值。在函数 start 仍然指向 null 之后,因为您从未更改过 start 的值。

您可以尝试将您的声明更改为

void append(node *&linkedlist,int data)

如果您使用的是 c++ 编译器。

否则

void append(node **linkedlist,int data)
...
append(&start,4);

如果你使用的是 C

【讨论】:

    【解决方案3】:

    首先,您显示的代码不是有效的 C 代码。您正在使用 C++ 元素。所以该程序甚至不会编译为 C 程序。

    由于最初设置为NULL 的节点start 可以通过您必须通过引用传递它的函数来更改。否则函数参数linkedlist是函数的局部变量,在函数中会发生变化,最后在退出函数后销毁。所以原来的指针start本身不会被改变。

    还有这个 else 代码块

        else {
            new_element->next = (linkedlist)->next;
            (linkedlist)->next = new_element;
        }
    

    错了。此代码块不会在列表的开头插入新节点。它在第一个已经存在的节点之后插入一个新节点。

    考虑到函数名append不适合在列表开头插入节点。最好将其命名为insert。 该函数可以如下所示

    int insert( struct node **linkedlist, int data )
    {
        struct node *new_element = malloc( sizeof( struct node ) );
        int success = new_element != NULL;
    
        if ( success )
        {
            new_element->data = data;
            new_element->next = *linkedlist;
            *linkedlist = new_element;
        }
    
        return success;
    }
    

    如果您确实需要一个将节点附加到列表的函数,那么它可以如下所示

    int append( struct node **linkedlist, int data )
    {
        struct node *new_element = malloc( sizeof( struct node ) );
        int success = new_element != NULL;
    
        if ( success )
        {
            new_element->data = data;
            new_element->next = NULL;
    
            while ( *linkedlist != NULL ) linkedlist = &( *linkedlist )->next; 
            *linkedlist = new_element;
        }
    
        return success;
    }
    

    这是一个演示程序

    #include <stdlib.h>
    #include <stdio.h>
    
    struct node 
    {
        int data;
        struct node* next;
    } *start = NULL;
    
    int insert( struct node **linkedlist, int data )
    {
        struct node *new_element = malloc( sizeof( struct node ) );
        int success = new_element != NULL;
    
        if ( success )
        {
            new_element->data = data;
            new_element->next = *linkedlist;
            *linkedlist = new_element;
        }
    
        return success;
    }
    
    int append( struct node **linkedlist, int data )
    {
        struct node *new_element = malloc( sizeof( struct node ) );
        int success = new_element != NULL;
    
        if ( success )
        {
            new_element->data = data;
            new_element->next = NULL;
    
            while ( *linkedlist != NULL ) linkedlist = &( *linkedlist )->next; 
            *linkedlist = new_element;
        }
    
        return success;
    }
    
    void printList( struct node* linkedlist )
    {
        if ( linkedlist == NULL ) 
        {
            puts( "Linked list is empty" );
        }
        else 
        {
            for ( struct node *current = linkedlist; current != NULL; current = current->next ) 
            {
                printf( "%d ", current->data );
            }
            printf( "\n" );
        }
    }
    
    int main( void ) 
    {
        const int N = 10;
    
        for ( int i = 1; i <= N; i++ )
        {
            if ( i % 2 == 0 ) append( &start, i );
            else insert( &start, i );
        }
    
        printList( start );
    
        return 0;
    }
    

    它的输出是

    9 7 5 3 1 2 4 6 8 10
    

    【讨论】:

      【解决方案4】:

      我不认为你的 if 语句是正确的。我会这样做

      if(linkedlist == null)
      {
          //head node is null i.e, linked list is empty hence make the new node as head node
          linkedlist = new_element;  
      }else{
          //make the new node point to the head
          new_element->next = linkedlist;
          //make the new node as head node
          linkedlist = new_element;
      }
      

      【讨论】:

        【解决方案5】:

        你应该在附加函数中

        1. 首先将 newnode 的 next 初始化为 null
        2. 在插入前检查是否有空列表,如果为空则将其设为头部。
        3. 如果它不为空,则使新节点指向列表的头部并使其成为新的头部。
        4. 要反映在 append 中完成的插入,您应该从函数返回修改后的 head(也相应地修改 main)。

        看看这段代码:-

            node *append(node *linkedlist,int data){
                node *new_element=NULL;
                new_element=(node *)malloc(sizeof(struct node));
                new_element->data=data;
                new_element->next=NULL;// initialise next of newnode to  be null here
                // In case of empty list make this as first node
                if(linkedlist==NULL)
                {
                      linkedlist=new_element;
                }
               else
                {
                    new_element->next=(linkedlist);//point the new node to head of list
                    (linkedlist)=new_element;// make new node as head
                }
                return linkedlist;
            }
        
        
            int main()
            {
                start = append(start, 4);
                start = append(start, 5);
                printList(start);
            }
        

        【讨论】:

        • 这和 OP 有同样的问题
        • 抱歉,马上处理
        【解决方案6】:

        当您在 C 中传递参数时,它会创建一个本地副本供函数使用。当你在函数内部修改参数时,它只会改变本地副本。

        void f1( int a )
        {
            a = 1; // modification does not affect the calling function
        }
        
        int b=0;
        f1( b );
        assert( b == 0 ); // b was not changed by f
        

        在C(或C风格的C++)中,如果你想让一个函数修改一个参数,你需要将它作为一个指针传递:

        void f2( int * a )
        {
            (*a) = 1;
        }
        
        int b=0;
        f2( &b );
        assert( b == 1 ); // b was changed by f
        

        如果那个参数已经是一个指针类型,那么你需要把它作为一个指针传递给一个指针:

        void f3( int * * a )
        {
            (*a) = (int*) malloc(sizeof(int));
            (**a) = 1;
        }
        
        int * b = NULL;
        f3( &b );
        assert( b != NULL ); // the pointer was initialized
        assert( *b == 1 ); // the pointed-to value was initialized
        

        在 C++ 中赋值过程可能更简单一些,因为您可以使用 reference parameters 而不是显式指定指针。

        【讨论】:

        • 这两种方法都适用于 C++,C++ 或多或少是 C 的超集。
        猜你喜欢
        • 2019-04-26
        • 2013-02-06
        • 1970-01-01
        • 2018-07-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多