双向链表中指针的反向

时间:2016-04-15 22:00:18

标签: c linked-list

我有一个循环的双向链表,我想改变所有nextprev指针的方向。我无法弄清楚错误的来源是什么。当我打印反转列表时,它会使前两个数字正确,但在此之后链接列表将停止打印。

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

如果我运行以下命令来测试它,我得到输出5 4 1 2 2 1,然后终止,没有错误。

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

1 个答案:

答案 0 :(得分:1)

circularListAddFront函数中存在一个错误,circularListAddBack中可能也存在错误(尽管未显示):

假设列表的这种状态:

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

现在,我们假设您在前面添加42。首先分配一个新节点并设置其值和指针。您还设置了sentinel下一个指针:

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;

这导致以下状态:

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

哪个不好,因为哨兵的prev指针仍然指向自己。你在那之后直接解决了这个问题:

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

这给出了期望的结果:

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

这很好。现在,让我们将21添加到光荣的列表中:

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

那个状态就在if之前,并且它有与以前相同的问题:有一个prev指针错误,这次它没有但是节点42之一的标记:它应指向其上一个节点,现在是21,而不是指向标记。

由于未采用if,因此状态仍然存在。在撤消列表之前你不会注意到它,因为在此之前你不会使用prev指针。

要解决这个问题,请摆脱if并无条件地纠正逻辑:

当你在前面插入一个新节点时("在哨兵"之后),你需要更改前面节点的prev指针并将其指向新节点:

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

但是,反转列表的代码似乎很好。而就目前而言,我已经完成了"线条艺术ASCII图形" :d