C 中的反转双链双端队列

发布于 2024-09-10 06:10:34 字数 751 浏览 10 评论 0原文

我在 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;
 }
}

但它似乎不起作用,我已经使用如下所示的双端队列对其进行了测试:1,2,3 输出是:3,这个过程似乎弄乱了数字的实际值。 IE。 2 变成 2.90085e-309...我认为指针切换混乱,但我找不到问题。即使这并不意味着我的代码是正确的;它编译得很好。

I'm having trouble reversing my doublely linked deque list (with only a back sentinel) in C, I'm approaching it by switching the pointers and here is the code I have so far:

/* 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;
 }
}

But it doesn't seem to work, I've been testing it with a deque that looks like this: 1, 2, 3
The output is: 3 and this process seems to mess up the actual value of the numbers. ie. 2 becomes 2.90085e-309... I think the pointer switching is messed up but I cannot find the problem. And even though it doesn't mean my code is correct; it compiles fine.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

野心澎湃 2024-09-17 06:10:34

像双端队列这样的链接结构很容易进行递归,因此在处理链接结构时我倾向于采用递归风格。这也允许我们增量地编写它,以便我们可以轻松地测试每个函数。像你的函数一样循环有很多缺点:你可以很容易地引入 fencepost 错误 并且它倾向于令人困惑的大函数。

首先,您决定通过交换指针来做到这一点,对吗?因此,编写一个函数来交换指针:

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 设置为该节点。

Linked structures like deques lend themselves readily to recursion, so I tend to favor a recursive style when dealing with linked structures. This also allows us to write it incrementally so that we can test each function easily. Looping as your function does has many downsides: you can easily introduce fencepost errors and it tends toward large functions that are confusing.

First, you've decided to do this by swapping the pointers, right? So write a function to swap pointers:

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

Now, write a function that reverses the pointers in a single node:

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

Now, put it together recursively:

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
}

I'm not sure exactly how your struct is designed; my function assumes that your deque is circular and that you'll be calling this on the sentinel.

EDIT: If your deque isn't circular, you'll want to call swapPointersInCirListDeque(q) on the sentinel as well, so move swapPointersInCirListDeque(q) before the if statement.

If you plan to use the backSentinel after this, you should change that also, since it's now the front of the list. If you have a frontSentinel, you can just add swapCirListDequePointers(&(q->frontSentinel),&(q->backSentinel)); to swapPointersInCirListDeque. Otherwise, you'll have to pass in the first node along with q and set q->backSentinel to that.

内心旳酸楚 2024-09-17 06:10:34

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

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 指针(因为没有第一个指针可用),那么您需要向后退一步抛出双端队列才能找到它。然而,很难相信会出现这种情况,因为这将是一个相当低效的双端队列(它应该是一个双端队列)。

If it's a doubly linked list, you shouldn't need to change any pointers at all. Just swap over the payloads:

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

If by back sentinel you mean the last pointer (as in no first pointer is available), then you need to step backwards throw the deque to find it. It's hard to believe however that this would be the case since it would be a fairly inefficient deque (which is supposed to be a double ended queue).

┊风居住的梦幻卍 2024-09-17 06:10:34

已经向您提供了一些建议;还有另一种可能性:

// 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 是一种巨大的浪费)。假设实际上您存储的数据足够大,以使双链接节点有意义,那么您还希望避免不必要地移动该数据,至少作为一般规则。

You've been given a couple of suggestions already; here's another possibility:

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

and also assumes a couple of variables (globals for the moment) named head and tail that point to the head and tail of the deque, respectively.

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;
    }   
}

At least for the moment, this does not assume any sentinels -- just NULL pointers to signal the ends of the list.

If you're just storing ints in the deque, Paxdiablo's suggestion is a good one (except that creating a doubly-linked node to hold only an int is a massive waste). Assuming that in reality you were storing something large enough for doubly-linked nodes to make sense, you'd also prefer to avoid moving that data around any more than necessary, at least as a general rule.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文