【问题标题】:C linked list inserting node at the endC链表在末尾插入节点
【发布时间】:2011-08-13 10:38:23
【问题描述】:

我在 C 中插入链表的方法遇到了一些问题。它似乎只在列表的开头添加。我做的任何其他插入都失败了。而且这个 CodeBlocks 调试器很难理解,我还是不明白。它从来没有给我价值,只是内存中的地址。无论如何,这是我的职责。你看到它失败的任何原因吗?

/* function to add a new node at the end of the list */
int addNodeBottom(int val, node *head){

    //create new node
    node *newNode = (node*)malloc(sizeof(node));

    if(newNode == NULL){
        fprintf(stderr, "Unable to allocate memory for new node\n");
        exit(-1);
    }

    newNode->value = val;

    //check for first insertion
    if(head->next == NULL){
        head->next = newNode;
        printf("added at beginning\n");
    }

    else
    {
        //else loop through the list and find the last
        //node, insert next to it
        node *current = head;
        while(current->next != NULL)
        {
            if(current->next == NULL)
            {
                current->next = newNode;
                printf("added later\n");
            }
            current = current->next;
        }
    }
    return 0;
}

然后在 main 中,只添加了 929。

   //testing addNodeBottom function
    addNodeBottom(929, head);
    addNodeBottom(98, head);
    addNodeBottom(122, head);
    addNodeBottom(11, head);
    addNodeBottom(1034, head);

【问题讨论】:

  • 如果我将 newNode->next 设置为 NULL,它仍然只插入第一个
  • current->next = newNode; 之后执行break;
  • 你能用node的结构定义和新行更新代码吗?还有,你怎么知道是这样的?
  • 您还可以保留一个尾指针,以使您在列表末尾的插入变得简单,而不必遍历列表。
  • +1 同意,保持尾指针追加 O(1)

标签: c insert linked-list binary-tree


【解决方案1】:

此代码将起作用。 samplebias 的答案几乎是正确的,但是您需要进行第三次更改:

int addNodeBottom(int val, node *head){

    //create new node
    node *newNode = (node*)malloc(sizeof(node));

    if(newNode == NULL){
        fprintf(stderr, "Unable to allocate memory for new node\n");
        exit(-1);
    }

    newNode->value = val;
    newNode->next = NULL;  // Change 1

    //check for first insertion
    if(head->next == NULL){
        head->next = newNode;
        printf("added at beginning\n");
    }

    else
    {
        //else loop through the list and find the last
        //node, insert next to it
        node *current = head;
        while (true) { // Change 2
            if(current->next == NULL)
            {
                current->next = newNode;
                printf("added later\n");
                break; // Change 3
            }
            current = current->next;
        };
    }
    return 0;
}

更改 1:newNode->next 必须设置为 NULL,这样我们就不会在列表末尾插入无效指针。

更改 2/3:循环更改为无限循环,当我们找到最后一个元素时会以break; 跳出。注意while(current->next != NULL) 之前与if(current->next == NULL) 的矛盾。

编辑:关于 while 循环,这种方式要好得多:

  node *current = head;
  while (current->next != NULL) {
    current = current->next;
  }
  current->next = newNode;
  printf("added later\n");

【讨论】:

  • 我们为什么要使用malloc?为什么不直接创建一个节点类型的新变量,获取它的指针并将其设置为下一个。
  • @AbhinavManchanda malloc 在函数调用中持久分配堆上的空间。如果我们“只创建一个节点类型的新变量,获取它的指针并将其设置为next。”空间是在函数的堆栈帧中分配的,所以指针会指向某个地方在该函数的堆栈帧中......一旦我们点击返回语句,堆栈帧就会被释放,给我们留下一个指向无处安全的指针。
【解决方案2】:

mallocnode 之后,请确保设置node->next = NULL

int addNodeBottom(int val, node *head)
{    
    node *current = head;
    node *newNode = (node *) malloc(sizeof(node));
    if (newNode == NULL) {
        printf("malloc failed\n");
        exit(-1);
    }    

    newNode->value = val;
    newNode->next = NULL;

    while (current->next) {
        current = current->next;
    }    
    current->next = newNode;
    return 0;
}    

我应该指出,在这个版本中,head 仍然用作虚拟对象,而不是用于存储值。这使您可以仅通过一个 head 节点来表示一个空列表。

【讨论】:

  • 但这不是唯一的错误,f.e.在while 循环中也缺少break;
【解决方案3】:

我知道这是一篇旧帖子,但仅供参考。以下是如何在没有特殊情况检查的情况下追加空列表,尽管代价是看起来更复杂的代码。

void Append(List * l, Node * n)
{
    Node ** next = &list->Head;
    while (*next != NULL) next = &(*next)->Next;
    *next = n;
    n->Next = NULL;
}

【讨论】:

    【解决方案4】:

    在编写代码之前,我想提一下密钥供您参考。

    //键

    temp= malloc 函数分配的新节点的地址(C 中的成员 od alloc.h 库)

    prev= 现有链表最后一个节点的地址。

    next = 包含下一个节点的地址

    struct node {
        int data;
        struct node *next;
    } *head;
    
    void addnode_end(int a) {
        struct node *temp, *prev;
        temp = (struct node*) malloc(sizeof(node));
        if (temp == NULL) {
            cout << "Not enough memory";
        } else {
            node->data = a;
            node->next = NULL;
            prev = head;
    
            while (prev->next != NULL) {
                prev = prev->next;
            }
    
            prev->next = temp;
        }
    }
    

    【讨论】:

      【解决方案5】:

      新节点总是添加在给定链表的最后一个节点之后。例如,如果给定的链表是 5->10->15->20->25 并且我们在末尾添加了一个项目 30,那么链表变为 5->10->15->20->25- >30。 由于链表通常由链表的头部表示,因此我们必须遍历链表直到结束,然后将最后一个节点的下一个节点更改为新节点。

      /* Given a reference (pointer to pointer) to the head
         of a list and an int, appends a new node at the end  */
      
      
          void append(struct node** head_ref, int new_data)
          {
          /* 1. allocate node */
               struct node* new_node = (struct node*) malloc(sizeof(struct node));
      
              struct node *last = *head_ref;  /* used in step 5*/
      
          /* 2. put in the data  */
              new_node->data  = new_data;
      
          /* 3. This new node is going to be the last node, so make next 
                of it as NULL*/
              new_node->next = NULL;
      
          /* 4. If the <a href="#">Linked List</a> is empty, then make the new node as head */
              if (*head_ref == NULL)
              {
             *head_ref = new_node;
             return;
              }  
      
          /* 5. Else traverse till the last node */
              while (last->next != NULL)
              last = last->next;
      
          /* 6. Change the next of last node */
              last->next = new_node;
              return;    
      }
      

      【讨论】:

        【解决方案6】:

        这很好用:

        struct node *addNode(node *head, int value) {
            node *newNode = (node *) malloc(sizeof(node));
            newNode->value = value;
            newNode->next = NULL;
        
            if (head == NULL) {
                // Add at the beginning
                head = newNode;
            } else {
                node *current = head;
        
                while (current->next != NULL) {
                    current = current->next;
                };
        
                // Add at the end
                current->next = newNode;
            }
        
            return head;
        }
        

        示例用法:

        struct node *head = NULL;
        
        for (int currentIndex = 1; currentIndex < 10; currentIndex++) {
            head = addNode(head, currentIndex);
        }
        

        【讨论】: