【问题标题】:Swapping last node of the linked list is going into a infinte -- C++交换链表的最后一个节点进入无限——C++
【发布时间】:2020-03-21 20:28:22
【问题描述】:

下面是代码,

#include<bits/stdc++.h>
using namespace std;

class node{
public:
    int data;
    node * next;

    node(){
        this->next = NULL;
    }

    node(int data){
        this->data = data;
        this->next = NULL;
    }
};

class linkedList{
public:
    node * head;
    node * tail;

    linkedList(){
        this->head = NULL;
    }

    void getTail(node *& t){
        t = head;
        while(t->next != NULL){
            t = t->next;
        }
    }

    void insertAtEnd(int data){
        node * newNode = new node(data);

        if(head == NULL){
            head = newNode;
            return;
        }

        node * temp = head;
        while(temp->next != NULL){
            temp = temp->next;
        }
        temp->next = newNode;
    }

    void print(){
        node * temp = head;
        while(temp != NULL){
            printf("%d->", temp->data);
            temp = temp->next;
        }
        printf("NULL\n");
    }

    void swap(node *& a, node *& b){ 
        node * temp = a;
        a = b;
        b = temp; 
    } 

    void swapNode(node ** start, node ** end){
        swap(*start, *end);
        swap(((*start)->next), (*end)->next);
    }
};

int main(){
    ///////////////////////////////////////
    linkedList * ll1 = new linkedList(); //
    ll1->insertAtEnd(6);                 //
    ll1->insertAtEnd(2);                 //
    ll1->insertAtEnd(1);                 //
    ll1->insertAtEnd(3);                 //
    ll1->print();                        /////////////////////
    ll1->swapNode(&ll1->head, &ll1->head->next->next->next);// ----> This is working
    //////////////////////////////////////////////////////////

    linkedList * ll2 = new linkedList();
    ll2->insertAtEnd(6);
    ll2->insertAtEnd(2);
    ll2->insertAtEnd(1);
    ll2->insertAtEnd(3);
    ll2->print();
    node * tail;
    ll2->getTail(tail);
    ll2->swapNode(&ll2->head, &tail); // This is not working // Going into a infinte loop
    ll2->print();

}

当尾节点存储在其他变量中时,似乎存在一个永远循环。 当通过使用下一个指针遍历到最后一个给出尾节点时代码正在工作。

所以,下面是链表的第一个示例的输出,即 6->2->1->3->NULL 1->2->6->3->空

对于链表#2,输出如下 6->2->1->3->NULL 3->2->1->3->2->1->3->2->1->3->2->1->3->2->1->3->2- >1->3->2->1->3->2->1->3->2->1->3->2->1->3->2->1->3 ->2->1->3->2->1->3->2->1->3->2->1->3->2->1->3->2-> 1->3->2->1->3->2->1->3->2->1->3->2->1->3->2->1->3- >2->1->3->2->1->3->2->1->3->2->1->3->2->1->3->2->1 ->3->2->1->3->2->1->3->2->1->3->2->1->3->2->1->3-> 2->1->3->2->1->3->2->1->3->2->1->3->2->1->3->2->1- >3->2->1->3->2->1->3->2->1->3->2->1->3->2->1->3->2 ->1->3->2->1->3->2->1->3->2->1->3->2->1->3->2->1-> 3->2->1->3->2->1->3->2->1->3->2->1->3->2->1->3->2- >1->3->2->1->3->2->1->3->2->1->3->2->1->3->2->1->3 ->2->1->3->2->1->3->2->1->3->2->1->3->2->1->3->2-> 1->3->2->1->3->2->1->3->2->1->3->2->1->3->2->1->3- >2->1->3->2->没有结局

【问题讨论】:

  • 第一个例子,交换后列表不应该变成3-&gt;2-&gt;1-&gt;6-&gt;NULL,而不是1-&gt;2-&gt;6-&gt;3-&gt;NULL吗?

标签: c++ pointers data-structures linked-list singly-linked-list


【解决方案1】:

当您交换两个节点 ab 时,您还必须修复指针到达 a 和到达 b。例如

     x1 -> x2 -> a -> x3 -> x4 -> b -> x5 -> x6 -> NULL

交换节点 ab 不需要只修复 a.nextb.next,还需要修复 x2.nextx4.next

您的实现中缺少这部分代码。

【讨论】:

  • ll1->swapNode(&ll1->head, &ll1->head->next->next->next);那为什么要使用这段代码呢?
【解决方案2】:

在处理链表时,图片通常会有所帮助。这是首发名单。

head
 |
 V
 ------------    ------------    ------------    ------------    
 | 6 | next | -> | 2 | next | -> | 1 | next | -> | 3 | NULL |
 ------------    ------------    ------------    ------------    

现在我们将调用ll1-&gt;swapNode(&amp;ll1-&gt;head, &amp;ll1-&gt;head-&gt;next-&gt;next-&gt;next),它将两个变量添加到图片中。

start
  |
  V
  head                                  end
   |                                     |
   V                                     V
   ------------    ------------    ------------    ------------    
   | 6 | next | -> | 2 | next | -> | 1 | next | -> | 3 | NULL |
   ------------    ------------    ------------    ------------    

接下来是对swap(*start, *end)的调用,它在数据为1的节点中交换头指针和next指针。所以头指针会指向3节点,而1节点会指向6节点。

                                              start
                                                |
                                                V
                                      end       head
                                       |         |
                                       V         V
 ------------    ------------    ------------    ------------    
 | 6 | next | -> | 2 | next | -> | 1 | next |    | 3 | NULL |
 ------------    ------------    ------------    ------------    
 ^                                      |
 |                                      |
 L---------------------------------------

最后,调用swap(((*start)-&gt;next), (*end)-&gt;next),交换数据为36的节点中的next指针。所以3 节点将指向2 节点,而6 节点的指针将变为空。

       start
         |
         V
         head
          |
          V
          ------------
          | 3 | next |
          ------------                end
                 |                     |
                 V                     V
 ------------    ------------    ------------
 | 6 | NULL |    | 2 | next | -> | 1 | next |
 ------------    ------------    ------------
 ^                                      |
 |                                      |
 L---------------------------------------

万岁!节点已交换。


现在看一下调用ll2-&gt;swapNode(&amp;ll2-&gt;head, &amp;tail);,它在初始图片中添加了三个变量。

start                                            end
  |                                               |
  V                                               V
  head                                            tail
   |                                               |
   V                                               V
   ------------    ------------    ------------    ------------    
   | 6 | next | -> | 2 | next | -> | 1 | next | -> | 3 | NULL |
   ------------    ------------    ------------    ------------    

接下来是对swap(*start, *end)的调用,它交换了头指针和tail(不是链表的尾指针,而是main()的局部变量)。

 end                                            start
  |                                               |
  V                                               V
  tail                                            head
   |                                               |
   V                                               V
   ------------    ------------    ------------    ------------    
   | 6 | next | -> | 2 | next | -> | 1 | next | -> | 3 | NULL |
   ------------    ------------    ------------    ------------    

与第一种情况已经有了明显的区别,列表的节点没有改变。嗯……好吧,让我们继续调用swap(((*start)-&gt;next), (*end)-&gt;next),它会交换数据为36 的节点中的next 指针。所以3 节点将指向2 节点,而6 节点的指针将变为空。 这是第一种情况发生的情况,那么它会解决吗?

 end                                            start
  |                                               |
  V                                               V
  tail                                            head
   |                                               |
   V                                               V
   ------------    ------------    ------------    ------------    
   | 6 | NULL |    | 2 | next | -> | 1 | next | -> | 3 | next |
   ------------    ------------    ------------    ------------    
                   ^                                      |
                   |                                      |
                   L---------------------------------------

问题!我们只剩下一个循环了!将1 节点更改为指向6 节点的步骤发生了什么?没错,我们改了tail,结果是灾难。


我会推荐三件主要的事情来将您的代码移动到更强大的基础上。 (也就是说,暂时不要尝试修复当前的错误。先做这些,因为它们会改变竞争环境。)

  1. 摆脱#include&lt;bits/stdc++.h&gt;;而是包含您需要的标题。对于此示例,您只需要 #include &lt;cstdio&gt;
  2. 使node 成为privatelinkedList 的实现细节。鲁棒性往往随着封装而增加。如果没有人知道linkedList 使用的数据结构,那么您就限制了其他代码的功能。由于要考虑的可能性较少,因此更容易确保您考虑了所有可能性。
  3. 不要声明从未使用过的字段 (linkedList::tail)。有人会想在某个时候使用该字段,却没有意识到它包含垃圾。

(还有其他的改进。我认为这三个是最重要的。)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-05-22
    • 2014-10-16
    • 2014-04-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多