在C中扭转双重联系的Deque

时间:2010-07-20 03:21:58

标签: c linked-list deque

我无法在C中反转我的双重链接双端队列表(只有一个后哨),我通过切换指针接近它,这是我到目前为止的代码:

/* Reverse the deque

 param:  q  pointer to the deque
 pre: q is not null and q is not empty
 post:  the deque is reversed
*/
/* reverseCirListDeque */
void reverseCirListDeque(struct cirListDeque *q)
{
 struct DLink *back = q->backSentinel;
 struct DLink *second = q->backSentinel->prev;
 struct DLink *third = q->backSentinel->next;

 while (second != q->backSentinel->next){
  back->next = second;
  third = back->prev;
  back->next->prev = back;
  back = second;
  second = third;
 }
}

但它似乎不起作用,我一直在测试它看起来像这样的deque:1,2,3 输出是:3,这个过程似乎弄乱了数字的实际值。即。 2变为2.90085e-309 ...我认为指针切换搞砸了,但我找不到问题。即使这并不意味着我的代码是正确的;编译得很好。

3 个答案:

答案 0 :(得分:2)

像deques这样的链接结构很容易递归,所以在处理链接结构时,我倾向于使用递归样式。这也允许我们以递增方式编写它,以便我们可以轻松地测试每个函数。循环,因为你的函数确实存在许多缺点:你可以很容易地引入fencepost errors并且它倾向于使大型函数混乱。

首先,你决定通过交换指针来做到这一点,对吗?所以写一个函数来交换指针:

void swapCirListDequePointers(
    struct cirListDeque** left,
    struct cirListDeque** right)
{
    struct cirListDeque* temp = *left;
    *left = *right;
    *right = temp;
}

现在,编写一个反转单个节点中指针的函数:

void swapPointersInCirListDeque(struct cirListDeque* q)
{
    swapCirListDequePointers(&(q->prev),&(q->next));
}

现在,递归地把它放在一起:

void reverseCirListDeque(struct cirListDeque* q)
{
    if(q == q->backSentinel)
        return;

    swapPointersInCirListDeque(q);

    // Leave this call in tail position so that compiler can optimize it
    reverseCirListDeque(q->prev); // Tricky; this used to be q->next
}

我不确定你的结构是如何设计的;我的函数假设你的双端队列是循环的,你将在哨兵上调用它。

编辑:如果您的双端队列不是循环播放,您也需要在哨兵号码上拨打swapPointersInCirListDeque(q),因此请在swapPointersInCirListDeque(q)语句前移动if

如果您计划在此之后使用backSentinel,您也应该更改它,因为它现在是列表的前面。如果您有frontSentinel,则可以将swapCirListDequePointers(&(q->frontSentinel),&(q->backSentinel));添加到swapPointersInCirListDeque。否则,您必须将第一个节点与q一起传入,并将q->backSentinel设置为该值。

答案 1 :(得分:1)

如果它是双向链表,则根本不需要更改任何指针。只需交换有效载荷:

pointer1 = first
pointer2 = last
while pointer1 != pointer2 and pointer2->next != pointer1:
    temp = pointer1->payload
    pointer1->payload = pointer2->payload
    pointer2->payload = temp
    pointer1 = pointer1->next
    pointer2 = pointer2->prev

如果通过后哨兵你的意思是last指针(因为没有第一个指针可用),那么你需要向后退一步来发现它。然而很难相信这种情况会是这样的,因为它会是一个相当低效的双端队列(它应该是一个双端队列)。

答案 2 :(得分:0)

你已经得到了一些建议;这是另一种可能性:

// Assumes a node something like:
typedef struct node { 
    struct node *next, *prev;
    int data;
} node;

并假设一些名为headtail的变量(目前为全局变量)分别指向双端队列的头部和尾部。

void reverse()  {
    node *pos = head;
    node *temp = pos->next;

    head = tail;
    tail = pos;

    while (pos != NULL) {
        node *t = pos->prev;
        pos->prev = pos->next;
        pos->next = t;
        pos = temp;
        if (temp)
            temp = temp->next;
    }   
}

至少目前,假设任何标记 - 只是NULL指针来表示列表的末尾。

如果您只是将int存储在双端队列中,Paxdiablo的建议是一个很好的建议(除了创建一个双重链接的节点只保留int是一个巨大的浪费)。假设实际上你存储的东西足够大,以便双链节点有意义,你也更愿意避免移动那些数据,至少作为一般规则。