开发者

Reversing Doublely Linked Deque in C

I'm having trouble reversing my double开发者_如何转开发ly 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.


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.


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).


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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜