简体   繁体   中英

Reverse direction of pointers in doubly linked list

I have a circular doubly linked list and I want to change the direction of all the next and prev pointers. I can't really figure out what the source of the error is. When I print the reversed list, it gets the first two numbers correct but past that point the links list stops printing.

struct Link
{
    TYPE value;
    struct Link * next;
    struct Link * prev;
};

struct CircularList
{
    int size;
    struct Link* sentinel;
};

static void init(struct CircularList* list)
{
    list->sentinel = (struct Link *) malloc(sizeof(struct Link));
    list->sentinel->next = list->sentinel;
    list->sentinel->prev = list->sentinel;
    list->size = 0;
}

struct CircularList* circularListCreate()
{
    struct CircularList* list = malloc(sizeof(struct CircularList));
    init(list);
    return list;
}

void circularListAddFront(struct CircularList* list, TYPE value)
{
    struct Link *newLink = (struct Link *) malloc(sizeof(struct Link));
    newLink->value = value;
    newLink->next = list->sentinel->next;
    newLink->prev = list->sentinel;
    list->sentinel->next = newLink;
    if(circularListIsEmpty(list)) {
        list->sentinel->prev = newLink;
    }
    list->size++;
}

void circularListRemoveFront(struct CircularList* list)
{
    struct Link *temp = list->sentinel->next;
    temp->next->prev = list->sentinel;
    list->sentinel->next = temp->next;
    free(temp);
    list->size--;
}

void circularListRemoveBack(struct CircularList* list)
{
    struct Link *temp = list->sentinel->prev;
    temp->prev->next = list->sentinel;
    list->sentinel->prev = temp->prev;
    free(temp);
    list->size--;
}

void circularListReverse(struct CircularList* list)
{
    struct Link *link = list->sentinel->next;
    while(link != list->sentinel) {
        struct Link *nextTemp = link->next;
        struct Link *prevTemp = link->prev;
        link->prev = link->next;
        link->next = prevTemp;
        link = nextTemp;
    }
    struct Link *temp = list->sentinel->next;
    list->sentinel->next = list->sentinel->prev;
    list->sentinel->prev = temp;
}

If I run the following to test this I get the output 5 4 1 2 2 1 and then terminates with no errors.

struct CircularList *deque = circularListCreate();
circularListAddBack(deque, 1);
circularListAddBack(deque, 2);
circularListAddBack(deque, 3);
circularListAddFront(deque, 4);
circularListAddFront(deque, 5);
circularListAddFront(deque, 6);
circularListRemoveFront(deque);
circularListRemoveBack(deque);
circularListPrint(deque);
circularListReverse(deque);
circularListPrint(deque);

There's a bug in your circularListAddFront function, and (though not shown) probably also in circularListAddBack :

Assume this state of the list:

p+SENTINEL+n
|    A     |
-----|------

Now, let's say you add 42 to the front. You first allocate a new node and set its value and pointers. Also you set the sentinel next pointer:

struct Link *newLink = (struct Link *) malloc(sizeof(struct Link));
newLink->value = value;
newLink->next = list->sentinel->next;
newLink->prev = list->sentinel;
list->sentinel->next = newLink;

This leads to the following state:

p+SENTINEL+n
|    A     |
-----|     |
     |     |
------     |
|    |     |
p+42+n     |
   A       |
   |       |
   ---------

Which is not fine, because the prev pointer of the sentinel still points to itself. You fix that directly after that:

if(circularListIsEmpty(list)) {
    list->sentinel->prev = newLink;
}
list->size++;

This gives the desired result:

  p+SENTINEL+n
--|    A     |
|      |     |
| ------     |
| |    |     |
| p+42+n     |
|    A       |
|    |       |
--------------

This is fine. Now let's add a 21 to the glorious list:

----------
|        |
|        V
|   p+SENTINEL+n
| --|    A     |
| |      |     |
| | ------     |
| | |    |     |
| | p+42+n     |
| |    A       |
| |    |       |
| -----|       |
|      |       |
| p+21+n       |
--|  A         |
     |         |
     -----------

That's the state right before that if , and it has the same issue as before: There's one prev pointer wrong, this time it's not sentinels but the one of node 42 : It should point to its previous node, which is now 21 , and not to the sentinel.

Since the if is not taken, the sate remains. You don't notice it until reversing the list because you don't use the prev pointers until then.

To fix that, get rid of the if and correct the logic unconditionally:

When you insert a new node to the front ("after the sentinel"), then you need to change the prev pointer of the node that was at the front before and point it to the new node:

newLink->next = list->sentinel->next;
newLink->prev = list->sentinel;
list->sentinel->next->prev = newLink; // ADDITION
list->sentinel->next = newLink;

The code for reversing the list seems fine, though. And for now, I'm done with "line art ASCII graphics" :D

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM