首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C 語言實現雙向非循環鏈表逆序打印:原生 prior 指針 O(1) 空間

     編輯:關於C語言

雙向鏈表逆序:原生優勢,無需額外空間

單鏈表逆序打印需 O(n) 額外空間 (構建新鏈表/棧/數組) 或修改指針。而雙向鏈表憑藉 prior 指針,可直接從尾部向前遍歷,實現真正的 O(1) 空間、O(n) 時間逆序輸出。這是雙向鏈表相比單向鏈表最直觀的優勢體現。

核心算法:兩階段遍歷

  1. 正向找尾:從頭遍歷 next 直到 pMove->next == NULL,定位尾節點。
  2. 逆向打印:從尾節點出發,沿 prior 向前遍歷打印,直到 pMove == NULL (越過頭節點)。

完整代碼實現

#include 
#include 
#include 

typedef struct Node {
    int element;
    struct Node *prior;
    struct Node *next;
} Node;

// 尾插構建 (同上篇)
Node* createList(Node *head) {
    Node *pInsert, *pMove = head;
    pInsert = (Node*)malloc(sizeof(Node));
    memset(pInsert, 0, sizeof(Node));
    pInsert->next = pInsert->prior = NULL;
    scanf("%d", &pInsert->element);
    if (pInsert->element <= 0) { free(pInsert); return NULL; }
    while (pInsert->element > 0) {
        if (!head) { head = pInsert; pMove = head; }
        else { pMove->next = pInsert; pInsert->prior = pMove; pMove = pInsert; }
        pInsert = (Node*)malloc(sizeof(Node));
        memset(pInsert, 0, sizeof(Node));
        pInsert->next = pInsert->prior = NULL;
        scanf("%d", &pInsert->element);
    }
    free(pInsert);
    return head;
}

// 正向打印
void printList(Node *head) {
    if (!head) { printf("空\n"); return; }
    while (head) { printf("%d ", head->element); head = head->next; }
    printf("\n");
}

// 核心:逆序打印
void ReversePrintList(Node *head) {
    if (!head) { printf("鏈表為空\n"); return; }
    
    Node *pMove = head;
    // 1. 正向遍歷到尾節點
    while (pMove->next) pMove = pMove->next;
    
    // 2. 逆向遍歷打印
    printf("逆序輸出: ");
    while (pMove) {
        printf("%d ", pMove->element);
        pMove = pMove->prior;
    }
    printf("\n");
}

int main() {
    Node *list = NULL;
    printf("輸入數據: ");
    list = createList(list); // 1 2 3 4 5 0
    
    printf("正向: ");
    printList(list); // 1 2 3 4 5
    
    ReversePrintList(list); // 逆序輸出: 5 4 3 2 1
    
    return 0;
}

運行示例

輸入數據: 10 20 30 40 50 0
正向: 10 20 30 40 50
逆序輸出: 50 40 30 20 10

複雜度對比:單向 vs 雙向逆序

指標單向鏈表 (構建新鏈表法)雙向鏈表 (原生 prior)
時間O(n)O(n)
額外空間O(n) (新節點/棧/數組)O(1) (僅指針變量)
代碼複雜度中 (分配/鏈接/釋放)極低 (兩輪遍歷)
修改原結構否 (構建新表)否

進階:帶頭結點雙向循環鏈表 (Linux list_head 風格)

若使用帶頭結點的循環雙向鏈表:

// 逆序遍歷宏 (Linux kernel 風格)
#define list_for_each_prev(pos, head) \
    for (pos = (head)->prev; pos != (head); pos = pos->prev)

// 使用:
struct list_head *pos;
list_for_each_prev(pos, &head) {
    MyNode *node = list_entry(pos, MyNode, list);
    printf("%d ", node->data);
}
// 無需「找尾」階段,頭結點 prev 直接指向尾節點,代碼更優雅。

總結

雙向鏈表逆序打印完美展示了「空間換時間」的反面:**用優勢結構特性 (prior 指針) 換取算法極致簡潔**。無頭結點版本只需兩輪遍歷 (找尾 + 逆向打印),帶頭結點循環版本更是一輪宏搞定。這也是為什麼 Linux 內核、C++ STL list、數據庫雙向鏈表索引都選擇雙向結構的核心原因:對稱性帶來的操作統一性與效率。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved