鏈表由離散節點透過指標串聯。所有操作核心都是「修改指標指向」。假設節點結構:
typedef struct Node {
int data;
struct Node *pNext;
} NODE, *PNODE;
p 後插入節點 q方法一:用臨時變量
PNODE r = p->pNext; // 保存 p 原後繼
p->pNext = q; // p 指向 q
q->pNext = r; // q 指向原後繼
方法二:無臨時變量(兩步走)
q->pNext = p->pNext; // q 指向 p 的後繼
p->pNext = q; // p 指向 q
方法二更簡潔,但需注意順序不可逆。
p 之後的節點
PNODE r = p->pNext; // 保存待刪節點
p->pNext = p->pNext->pNext; // 跳過待刪節點
free(r); // 釋放記憶體
r = NULL; // 避免野指標
bool IsEmpty(PNODE pHead) {
return pHead->pNext == NULL; // 僅有頭節點視為空
}
以下代碼實現:創建、遍歷、求長、插入、刪除、查找、修改、排序。
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <malloc.h>
typedef struct Node {
int data;
struct Node *pNext;
} NODE, *PNODE;
// --- 函數聲明 ---
PNODE CreateList();
void TraverseList(PNODE);
bool IsEmpty(PNODE);
int Length(PNODE);
bool InsertNode(PNODE, int, int);
bool DeleteNode(PNODE, int, int *);
bool QueryNode(PNODE, int);
bool ModifyNode(PNODE, int, int);
void SortList(PNODE);
int main() {
PNODE pHead = CreateList();
if (Length(pHead) == 0) {
printf("鏈表無有效節點,退出程序!\n");
return -1;
}
TraverseList(pHead);
if (InsertNode(pHead, 2, 100)) {
printf("插入後:");
TraverseList(pHead);
}
SortList(pHead);
printf("排序後:");
TraverseList(pHead);
return 0;
}
// --- 實作 ---
PNODE CreateList() {
int len, i, val;
PNODE pHead = (PNODE)malloc(sizeof(NODE));
if (!pHead) exit(-1);
pHead->pNext = NULL;
PNODE pTail = pHead;
printf("請輸入節點個數:");
scanf("%d", &len);
for (i = 0; i < len; i++) {
printf("第 %d 個節點值:", i+1);
scanf("%d", &val);
PNODE pNew = (PNODE)malloc(sizeof(NODE));
if (!pNew) exit(-1);
pNew->data = val;
pNew->pNext = NULL;
pTail->pNext = pNew;
pTail = pNew;
}
return pHead;
}
void TraverseList(PNODE pHead) {
PNODE p = pHead->pNext;
printf("遍歷整個鏈表:");
while (p) {
printf("%d ", p->data);
p = p->pNext;
}
printf("\n");
}
bool IsEmpty(PNODE pHead) {
return pHead->pNext == NULL;
}
int Length(PNODE pHead) {
int len = 0;
PNODE p = pHead->pNext;
while (p) { len++; p = p->pNext; }
return len;
}
bool InsertNode(PNODE pHead, int pos, int val) {
int i = 0;
PNODE p = pHead;
// 找到第 pos-1 個節點
while (p && i < pos - 1) { p = p->pNext; i++; }
if (!p || i > pos - 1) return false; // 位置非法
PNODE pNew = (PNODE)malloc(sizeof(NODE));
if (!pNew) exit(-1);
pNew->data = val;
pNew->pNext = p->pNext;
p->pNext = pNew;
return true;
}
bool DeleteNode(PNODE pHead, int pos, int *pVal) {
int i = 0;
PNODE p = pHead;
while (p->pNext && i < pos - 1) { p = p->pNext; i++; }
if (!p->pNext || i > pos - 1) return false;
PNODE q = p->pNext;
*pVal = q->data;
p->pNext = q->pNext;
free(q);
return true;
}
void SortList(PNODE pHead) {
int len = Length(pHead);
for (int i = 0, p = pHead->pNext; i < len - 1; p = p->pNext, i++) {
for (int j = i + 1, q = p->pNext; j < len; q = q->pNext, j++) {
if (p->data > q->data) {
int t = p->data; p->data = q->data; q->data = t;
}
}
}
}
bool QueryNode(PNODE pHead, int pos) {
int i = 0;
PNODE p = pHead;
while (p->pNext && i < pos - 1) { p = p->pNext; i++; }
if (!p->pNext || i > pos - 1) return false;
printf("第 %d 號節點值:%d\n", pos, p->pNext->data);
return true;
}
bool ModifyNode(PNODE pHead, int pos, int val) {
int i = 0;
PNODE p = pHead;
while (p->pNext && i < pos - 1) { p = p->pNext; i++; }
if (!p->pNext || i > pos - 1) return false;
p->pNext->data = val;
printf("修改第 %d 號節點值為:%d\n", pos, val);
return true;
}
| 特性 | 陣列 (連續存儲) | 鏈表 (離散存儲) |
|---|---|---|
| 存取速度 | 快 O(1) 隨機存取 | 慢 O(n) 順序存取 |
| 插入/刪除 | 慢 O(n) 需搬移 | 快 O(1) 僅改指標 |
| 空間 | 固定,需預分配大塊連續記憶體 | 動態,無上限,不需連續記憶體 |
| 記憶體碎片 | 無 | 有 |
bool 型別:C 編譯器不支援,需用 C++ 編譯器(副檔名 .cpp 或設定 /TP)。illegal use of this type as an expression 常因混用 C 編譯器編譯 C++ 風格代碼。