【问题标题】:Reverse doubly-link list in C++C++中的反向双向链表
【发布时间】:2010-07-07 20:35:55
【问题描述】:

我一直在试图弄清楚如何反转双向链表的顺序,但由于某种原因,在我的函数 void reverse() 中运行了一次 while 循环,然后由于某种原因而崩溃。为了回答前面的一些问题,我在兄弟们的帮助下自学。这不是全部代码,但我有一个 display() 函数,它按时间顺序从 start_ptr 打印所有节点,还有一个开关可以激活某些功能,如

    case 1 : add_end(); break;
    case 2 : add_begin(); break;
    case 3 : add_index(); break;
    case 4 : del_end(); break;
    case 5 : del_begin(); break;
    case 6 : reverse(); break;

这是我的代码的精髓:

#include <iostream>
using namespace std;

struct node
{
    char name[20];
    char profession[20];
    int age;
    node *nxt;
    node *prv;
};

node *start_ptr = NULL;

void pswap (node *pa, node *pb)
{
    node temp = *pa;
    *pa = *pb;
    *pb = temp;
    return;
}

void reverse()
{
    if(start_ptr==NULL)
    {
        cout << "Can't do anything" << endl;
    }
    else if(start_ptr->nxt==NULL)
    {
        return;
    }
    else
    {
        node *current = start_ptr;
        node *nextone = start_ptr;
        nextone=nextone->nxt->nxt;
        current=current->nxt;
        start_ptr->prv=start_ptr->nxt;
        start_ptr->nxt=NULL;
        //nextone=nextone->nxt;
        while(nextone->nxt!= NULL)
        {
            pswap(current->nxt, current->prv);
            current=nextone;
            nextone=nextone->nxt;
        }
        start_ptr=nextone;
    }
}

【问题讨论】:

  • 您正在交换节点的内容,而不仅仅是节点指针。你确定要这样做吗?
  • 在相关说明中,您可以从不同的角度看待事物。与其反转双向链接列表本身的内容,不如专注于反向迭代列表的内容,这应该很简单,因为列表是双向链接的。例如,为您的列表实现 STL 样式的双向迭代器。它们可以与std::reverse_iterator&lt;&gt; 适配器一起使用(用于rbegin()rend())。一旦实现了这些方法,就可以很容易地利用 STL 算法,包括std::reverse()。这是一个有趣的练习,IMO。

标签: c++ linked-list reverse


【解决方案1】:

试试这个:

node *ptr = start_ptr;
while (ptr != NULL) {
    node *tmp = ptr->nxt;
    ptr->nxt = ptr->prv;
    ptr->prv = tmp;
    if (tmp == NULL) {
        end_ptr = start_ptr;
        start_ptr = ptr;
    }
    ptr = tmp;
}

【讨论】:

  • 最好的,虽然我脑子里放了个屁,因为你没有用指向 NULL 的指针结束列表
  • 哇,非常感谢,我对您的代码进行了一些修改,它看起来比我所有其他尝试都漂亮。您所要做的就是在start_ptr==NULL || start_ptr-&gt;nxt==NULL 时添加一个限定条件,并使您的代码部分以else 结尾。在那之内,我确定了最后的代码,end_ptr-&gt;nxt=NULL; 非常感谢
  • 我不太确定您为什么需要这些检查 - 我认为我提供的代码在没有它们的情况下也能正常工作。最后,end_ptr->nxt 将为 NULL,因为在开始时,start_ptr->prv 为 NULL。但无论如何,我们不客气。
  • @Borealid 我们不能只将head 指针分配给最后一个节点,将NULL 分配给起始节点的prv 吗?
  • @Dan :我知道 9 年过去了,但是 - end_ptr 没有在任何地方定义。你做了那个改变吗?
【解决方案2】:

编辑:我的第一个实现,正确但不完美。 您的实现非常复杂。你可以试试这个吗:

node * reverse(Node * start_ptr)
{
    Node *curr = start_ptr; 
    Node * prev = null;
    Node * next = null;
    while(curr)
    {
        next = curr->nxt;
        curr->nxt = prev;
    curr->prv = next;
        prev = curr;
        curr = next;
    }
    return start_ptr=prev;
}

这是我的更新解决方案:

node * reverse()
{
    node *curr = start_ptr; 
    node * prev = NULL;
    node * next = NULL;
    while(curr)
    {
        next = curr->nxt;
        curr->nxt = prev;
        curr->prv = next;
        prev = curr;
        curr = next;
    }
    return start_ptr=prev;
}

逻辑是正确的。但问题是我在输入参数 start_ptr 中接受了。这意味着我正在返回它的本地副本。现在它应该可以工作了。

【讨论】:

  • 我就是想不通我是怎么做到的。谁能确认这个实现是否创建了一个循环链表?谢谢...
  • 嗨,Danutenshu,我已经更新了我的解决方案。我知道您的问题已经解决了,但如果您能告诉我我所做的更改是否正确,我会感觉更好?
【解决方案3】:

您可以大大简化您的reverse()。我会做这样的事情:

void reverse()
{
    if(start_ptr == NULL)
    {
        cout << "Can't do anything" << endl;
    }
    else
    {
        node *curr = start_ptr;
        while(curr != NULL)
        {
            Node *next = curr->next;
            curr->next = curr->prev;
            curr->prev = next;
            curr = next;
        }
        start_ptr = prev;       
    }
}

解释:基本思想是简单地访问每个Node并将链接交换到previousnext。当我们将curr 移动到下一个Node 时,我们需要存储下一个节点,因此当我们将curr.next 设置为prev 时,我们仍然有一个指向它的指针。

【讨论】:

  • 我认为您错过了将第一个节点的 prev 更新为第二个节点。
  • 确实,我一开始就一头雾水。现在应该好多了。
【解决方案4】:

简单的解决方案。在列表上的总迭代次数不到一半的时间内反转

template<typename E> void DLinkedList<E>::reverse() {
    int median = 0;
    int listSize = size();
    int counter = 0;

    if (listSize == 1)
    return;

    DNode<E>* tempNode = new DNode<E>();

    /**
     * A temporary node for swapping a node and its reflection node
     */
    DNode<E>* dummyNode = new DNode<E>();

    DNode<E>* headCursor = head;
    DNode<E>* tailCursor = tail;

    for (int i = 0; i < listSize / 2; i++) {
        cout << i << "\t";

        headCursor = headCursor->next;
        tailCursor = tailCursor->prev;

        DNode<E>* curNode = headCursor;
        DNode<E>* reflectionNode = tailCursor;

        if (listSize % 2 == 0 && listSize / 2 - 1 == i) {
            /**
             * insert a dummy node for reflection
         * for even sized lists
         */
        curNode->next = dummyNode;
        dummyNode->prev = curNode;

        reflectionNode->prev = dummyNode;
        dummyNode->next = reflectionNode;

    }
    /**
     * swap the connections from previous and 
             * next nodes for current and reflection nodes
     */

    curNode->prev->next = curNode->next->prev = reflectionNode;

    reflectionNode->prev->next = reflectionNode->next->prev = curNode;

    /**
     * swapping of the nodes
     */

    tempNode->prev = curNode->prev;
    tempNode->next = curNode->next;

    curNode->next = reflectionNode->next;
    curNode->prev = reflectionNode->prev;

    reflectionNode->prev = tempNode->prev;
    reflectionNode->next = tempNode->next;

    if (listSize % 2 == 0 && listSize / 2 - 1 == i) {
        /**
         * remove a dummy node for reflection
         * for even sized lists
         */
        reflectionNode->next = curNode;
        curNode->prev = reflectionNode;
    }

    /**
     * Reassign the cursors to position over the recently swapped nodes
     */
        tailCursor = curNode;
        headCursor = reflectionNode;

    }

    delete tempNode, dummyNode;
}

template<typename E> int DLinkedList<E>::size() {
    int count = 0;
    DNode<E>* iterator = head;

    while (iterator->next != tail) {
        count++;
        iterator = iterator->next;
    }
    return count;
}

【讨论】:

    【解决方案5】:

    我建议保持到最后一个节点的链接。
    如果没有,找到最后一个节点。 使用“以前的”链接(或在您的情况下为prv)遍历列表。

    实际上没有必要改变周围的链接。使用prv指针遍历会自动倒序访问节点。

    【讨论】:

      【解决方案6】:

      看看

      valuesnextone=nextone->nxt->nxt;
      

      这里nextone-&gt;nxt可以为空。

      除此之外,尝试在交换函数中使用指向指针的指针。

      【讨论】:

        【解决方案7】:

        您的 pswap 功能错误 您应该交换指针而不是尝试创建临时对象并交换它们。 应该是这样(后面可能有其他错误)

        void pswap (node *&pa, node *&pb)
        {
            node* temp = pa;
            pa = pb;
            pb = temp;
            return;
        }
        

        【讨论】:

        • 这实际上不会做任何事情。您需要传递指向指针的指针或指向指针的引用,以便更改应用于原始对象,而不是本地副本。
        • 你说的很对,我没看签名功能。刚刚修复了临时对象创建错误
        【解决方案8】:

        使用两个指针的非常简单且 O(n) 的解决方案:

        start = 双重 LL 的头

        struct node *temp, *s;
        s = start;
        
        while(s != NULL){
          temp = s->prev;
          s->prev = s->next;
          s->next = temp;
          s = s->prev;
        }
        
        //if list has more than one node
        if(current != NULL){
          start = temp->prev;
        }
        

        【讨论】:

          【解决方案9】:

          我的反向双向链表代码,

          Node* Reverse(Node* head)
          {
          // Complete this function
          // Do not write the main method. 
          
          
          if(head != NULL) {
          
              Node* curr = head;
              Node* lastsetNode = curr;
              while(curr != NULL) {
          
                  Node* frwdNode = curr->next;
                  Node* prevNode = curr->prev;
          
          
                  if(curr==head) {                
                      curr->next = NULL;
                      curr->prev = frwdNode;
                      lastsetNode = curr;
                  }
                  else {
                      curr->next = lastsetNode;
                      curr->prev = frwdNode;
                      lastsetNode = curr;
                  }
          
          
          
                  curr = frwdNode;
              }
          
              head = lastsetNode;
          }
          
          
          return head;
          }
          

          【讨论】:

            【解决方案10】:

            我想我会在这里添加一个递归解决方案。

            node* reverse_and_get_new_head(node* head) {
                if (head == nullptr) { return nullptr; } 
                  // This can be avoided by ensuring the initial,
                  // outer call is with a non-empty list
                std::swap(head->prev, head->next);
                if (head->prev == nullptr) { return head; }
                return reverse_and_get_new_head(head->prev);
            }
            
            void reverse() {
                start_ptr = reverse_and_get_new_head(start_ptr);
            }
            
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2012-06-25
              • 1970-01-01
              • 1970-01-01
              • 2018-03-05
              • 1970-01-01
              相关资源
              最近更新 更多