以相反的顺序打印双向链表?

Print a doubly linked list in reverse order?

我的最小可重现示例:

#include <stdio.h>
#include <stdlib.h>

typedef struct NodeStruct Node;

//struct for each office item
struct NodeStruct {
    int id;
    struct NodeStruct *next;
    struct NodeStruct *prev; //Create doubly linked list node
};

/** Structure for the whole list, including head and tail pointers. */
typedef struct {
    /** Pointer to the first node on the list (or NULL ). */
    Node *head;
    Node *last;
} List;

List *list;

List *makeList();
static void *addRecord(List *list, int newID);
static void printReverse(List *list);

int main(int argc, char **argv) {
    //Create an empty list for you to start.
    list = (List *)makeList();

    addRecord(list, 1);
    addRecord(list, 2);
    addRecord(list, 3);
    addRecord(list, 4);
    addRecord(list, 15);
    printReverse(list);
    return 0;
}

List *makeList() {
    List *list = (List *)malloc(sizeof(List));
    list->head = NULL;
    return list;
}

static void *addRecord(List *list, int newID) {
    //Allocate memory for the node
    Node *new = (Node *)malloc(sizeof(Node)); 

    //Add in data
    new->id = newID; 

    //New node has no next, yet
    new->next = NULL;

    Node **next_p = &list->head;
    while (*next_p) {
        next_p = &(*next_p)->next;
    }
    *next_p = new;

    return EXIT_SUCCESS;
}

static void printReverse(List *list) {
    Node **tail = &list->last;
    printf("LIST IN REVERSE ORDER:\n");

    //Traversing until tail end of linked list
    while (*tail) {
        printf("Item ID: %d\n", (*tail)->id);
        tail = &(*tail)->prev;
    }
}

输入:

1 -> 2 -> 3 -> 4 -> 15

预期输出:

15 -> 4 -> 3 -> 2 -> 1

实际输出:

segmentation fault


编辑:在链表中设置 prev 节点:

#include <stdio.h>
#include <stdlib.h>

typedef struct NodeStruct Node;

//struct for each office item
struct NodeStruct {
    int id;
    struct NodeStruct *next;
    struct NodeStruct *prev; //Create doubly linked list node
};

/** Structure for the whole list, including head and tail pointers. */
typedef struct {
    /** Pointer to the first node on the list (or NULL ). */
    Node *head;
    Node *last;
} List;

List *list;

List *makeList();
static void *addRecord(List *list, int newID);
static void printReverse(List *list);

int main(int argc, char **argv) {
    // Create an empty list for you to start.
    list = (List *)makeList();

    addRecord(list, 1);
    addRecord(list, 2);
    addRecord(list, 3);
    addRecord(list, 4);
    addRecord(list, 15);
    printReverse(list);
    return 0;
}

List *makeList() {
    List *list = (List *)malloc(sizeof(List));
    list->head = NULL;
    return list;
}

static void *addRecord(List *list, int newID) {
    //Allocate memory for the node
    Node *new = (Node *)malloc(sizeof(Node)); 

    //Add in data
    new->id = newID; 
    new->prev = NULL;

    //New node has no next, yet
    new->next = NULL;

    Node **next_p = &list->head;
    while (*next_p) {
        next_p = &(*next_p)->next;
    }
    *next_p = new;
    list->last = new;
    new->prev = *next_p;

    return EXIT_SUCCESS;
}

static void printReverse(List *list) {
    Node **tail = &list->last;
    printf("LIST IN REVERSE ORDER:\n");

    //Traversing until tail end of linked list
    while (*tail) {
        printf("Item ID: %d\n", (*tail)->id);
        tail = &(*tail)->prev;
    }
}

addRecord 进行此编辑后,我不断得到一个无限循环,一遍又一遍地打印 Item ID: 15

1) 您添加(准确地说是追加,将其添加到末尾)您的第一个节点,值为 1,然后为其设置 head。但是 last 呢?最后一个节点不是列表中的第一个节点吗?是的!此外,您将 next 指针设置为 NULL,正确...但是 prev 指针呢?它不应该也设置为 NULL 吗,因为他们没有以前的节点?又是。

2) list 不需要是全局的,老实说,也不应该是。

3) 当你这样做时:

*next_p = new;
new->prev = *next_p;

那你说新追加节点的前一个节点就是新节点。它应该是最后一个,这是我们先验知道的,所以我们可以这样做:

new->prev = list->last;

刚刚构建完节点。

4) 此外,创建空列表时,状态应该是头指针和尾指针都设置为NULL。

5) 最后,您可以简化打印函数,不使用双指针,而只使用指针。

将所有内容放在一起,我们得到:

#include <stdio.h>
#include <stdlib.h>

typedef struct NodeStruct Node;

//struct for each office item
struct NodeStruct {
    int id;
    struct NodeStruct *next;
    struct NodeStruct *prev; //Create doubly linked list node
};

/** Structure for the whole list, including head and tail pointers. */
typedef struct {
  /** Pointer to the first node on the list (or NULL ). */
  Node *head;
  Node *last;
} List;

List *makeList();
static void *addRecordAtEnd(List *list, int newID);
void print(List *list);
void printReverse(List *list);

int main() 
{
  // Create an empty list for you to start.
  List* list = makeList();

  addRecordAtEnd(list, 1);
  addRecordAtEnd(list, 2);
  addRecordAtEnd(list, 3);
  addRecordAtEnd(list, 4);
  addRecordAtEnd(list, 15);
  print(list);
  printReverse(list);
  return 0;
}

List *makeList()
{
  List *list = malloc( sizeof( List ) );
  if(list != NULL)
  {
    list->head = NULL;
    list->last = NULL;
  }
  return list;
}

static void *addRecordAtEnd(List *list, int newID) 
{
  //Allocate memory for the node
  Node *new = malloc(sizeof(Node)); 

  //Add in data
  new->id = newID; 

  new->prev = list->last;
  new->next = NULL;

  list->last = new;

  // if list is empty
  if(!list->head)
  {
    list->head = new;
    return EXIT_SUCCESS;
  }

  Node **next_p = &list->head;
  while (*next_p) {
    next_p = &(*next_p)->next;
  }
  *next_p = new;

  return EXIT_SUCCESS;
}


void print(List *list)
{
  Node *current_node = list->head;
  while (current_node) {
    printf("Item ID: %d\n", current_node->id);
    current_node = current_node->next;
  }
}

void printReverse(List *list)
{
  Node *current_node = list->last;
  printf("LIST IN REVERSE ORDER:\n");

  //Traversing until tail end of linked list
  while (current_node) {
    printf("Item ID: %d\n", current_node->id);
    current_node = current_node->prev;
  }
}

输出(同时检查下一个指针是否正确设置):

Item ID: 1
Item ID: 2
Item ID: 3
Item ID: 4
Item ID: 15
LIST IN REVERSE ORDER:
Item ID: 15
Item ID: 4
Item ID: 3
Item ID: 2
Item ID: 1

PS: Do I cast the result of malloc? 没有!

问题出在函数 addRecord(): new->prev = *next_p;

next_p不是指向最后一个节点的指针,它是指向最后一个节点的next成员的指针。在这种特殊情况下,*next_p 之前已设置为 new

对于双向链表不使用双指针技巧更简单,只对空列表进行特殊处理:

static void *addRecord(List *list, int newID) {
    //Allocate memory for the node
    Node *new_node = (Node *)malloc(sizeof(Node)); 

    if (new_node == NULL)
        return EXIT_FAILURE;

    //Add in data
    new_node->id = newID; 
    new_node->next = NULL;
    if (list->head == NULL) {
        new_node->prev = NULL;
        list->head = new_node;
    } else {
        new_node->prev = list->last;
        list->last->next = new_node;
    }
    list->last = new_node;
    return EXIT_SUCCESS;
}

同样,print函数也可以不用双指针来写:

static void printReverse(List *list) {
    // Traversing until tail end of linked list
    printf("LIST IN REVERSE ORDER:\n");
    for (Node *node = list->last; node; node = node->prev) {
        printf("Item ID: %d\n", node->id);
    }
}

请注意,初始化函数也必须初始化 last,以便 printReverse 正确处理空列表:

List *makeList() {
    List *list = (List *)malloc(sizeof(List));
    if (list != NULL) {
        list->head = list->last = NULL;
    }
    return list;
}