【问题标题】:Confused about insertion into linked list对插入链表感到困惑
【发布时间】:2020-07-20 15:09:49
【问题描述】:

这是节点类本身的代码:

struct Node {
  int data;
  struct Node * next;
  Node(int x) {
    data = x;
    next = NULL;
  }
};

下面的代码在链表的开头插入一个新节点。我的问题是为什么第四行没有弄乱列表的顺序。如果 head 之前位于 new_node 之后的位置,则不会将 head 设置为等于 new_node 弄乱列表。当我运行代码时,它按预期工作,但我不知道为什么。

Node *insertAtBegining(Node *head, int newData) {
   Node* new_node = new Node(newData);
   new_node -> next = head;
   head = new_node;
   return head;
}

我的第二个问题是关于以下代码,它应该在链表的末尾插入一个项目。我明白这个是如何工作的,我只是不明白为什么它的简化版本也不起作用。

Node *insertAtEnd(Node *head, int newData)  {
    Node* new_node = new Node(newData);
    if(head == nullptr){
        head = new_node;
        return head;
    }
    else{
        Node* trav = head;
       while(trav -> next != nullptr){
           trav = trav -> next;
       }    
       trav -> next = new_node;
       return head;
    }
}

简化版

Node *insertAtEnd(Node *head, int newData)  {
    Node* new_node = new Node(newData);
    Node* trav = head;
    while(trav != nullptr){
        trav = trav -> next;
    }
    trav = new_node;
}

简化版仅将您尝试添加的最后一个节点附加到列表末尾。因此,如果您尝试附加 1、2 和 3,则只会添加 3 个。由于 trav 指针刚刚成为最后一个 next 指针,它不应该做同样的事情吗?

【问题讨论】:

  • “简化”版本不返回任何内容。
  • head 不是节点,它是一个保存节点地址的变量。 head = new_node; 不移动任何节点!
  • 还要注意head = new_node 并没有真的做任何事情。您可以删除该行,并将返回语句更改为return new_node,代码将执行相同的操作。
  • 简化版的正文可以进一步简化为等效的Node* trav = new Node(newData);。你能发现问题吗?
  • trav 指针不会成为最后一个 next 指针。它变成了 nullptr。

标签: c++ linked-list


【解决方案1】:

head 不是节点。它是一个保存节点地址的变量。

head = new_node; 不移动任何节点!它查看new_node 变量中的值(这是一个节点的地址)并将相同的值存储到head 变量中。它不会更改列表。它只会更改 head 变量。

这一行更改了新节点。它表示新节点之后的节点是head变量中地址为当前的那个。

new_node -> next = head;

请注意,我们还没有将新节点算作列表的一部分,因为您无法从第一个节点(地址在 head 变量中的那个节点)到达它。

这一行:

head = new_node;

head 设置为新节点的地址。 现在我们可以说新节点在列表中,因为现在“第一个节点”——地址在head变量中的那个节点——是新的一。不是因为我们更改了节点,而是因为我们更改了head 变量。


请注意,head 是函数内的局部变量。如果你调用这个函数并且你只是做insertAtBeginning(head, 5) 那么它不会“改变列表”,因为你的 head 变量仍然指向它之前所做的那个。函数中的变量已更改,但不再使用该变量。你必须做head = insertAtBeginning(head, 5)

【讨论】:

    【解决方案2】:

    第一个代码

    您正在创建一个newnode,并且要在前面插入,您需要将next of newnode 设置为current head,然后将newnode 设置为head(并将其作为当前头部返回存储)

    这正是第一个代码所做的。所以这里没问题。

    第二个代码(简化版)

    • 这里您没有存储 head(就像您返回头部并正确存储的第一个代码)
    • 此外,您正在遍历直到它变为 null(您已超过最后一个元素)并创建 newnode
    • 您没有将newnode 链接到链接列表的末尾

    二次代码解决方案(简化版)

    Node *insertAtEnd(Node *head, int newData)  {
        
        Node* new_node = new Node(newData);
    
        // if this is the first node (head will be NULL)
        if (!head) {
           return new_node; 
        }
    
        Node* trav = head;
        while(trav->next != nullptr){
            trav = trav -> next;
        }
        trav->next = new_node;
        return head;
    }
    

    【讨论】:

    • 但是在它变成null的那一点,不就是在最后一个节点的next指针吗?我假设当我在简化版本中执行 trav = new_node 时,我正在更改最后一个节点的下一个指针。
    • 是的,它是最后一个节点的 next 指针,但在编程上它是 NULL ,所以现在您只需将 trav (NULL) 设置为 trav (new_node)。您没有将新节点与链表链接。
    【解决方案3】:

    在 insertAtEnd 中,如果列表为空,则 head 将为空。如果 head 为空,则需要设置 head。然后您可以返回新的头部。

    if(trav != nullptr) {do something}
    else head = new_node;
    

    现在它将更新头部但不更新下一个值。您可以通过停止最后一个值并将其“next”指针设置为 new_node 指针来解决此问题。

    while(trav->next != nullptr){
        trav = trav -> next;
    }
    trav->next = new_node;
    

    所以最终结果看起来像这样:

    Node *insertAtEnd(Node *head, int newData)  {
        Node* new_node = new Node(newData);
        Node* trav = head;
        if(trav != nullptr) {
            while(trav->next != nullptr) 
                trav = trav -> next;
            trav->next = new_node;
        }else head = new_node;
        return head;
    }
    

    【讨论】:

      猜你喜欢
      • 2019-05-10
      • 2012-07-14
      • 2022-01-20
      • 1970-01-01
      • 2013-08-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多