單向鏈表是動態資料結構,由節點組成,每個節點包含資料域與指標域(指向下一節點)。特點:
typedef struct Node {
int data; // 資料域,可擴展為任意型別
struct Node *next; // 指標域,指向下一節點
} Node, *LinkList;
LinkList InitList() {
LinkList L = (LinkList)malloc(sizeof(Node));
if (!L) exit(OVERFLOW);
L->next = NULL;
return L;
}
void CreateList_Tail(LinkList L, int n) {
LinkList r = L, p;
for (int i = 0; i < n; i++) {
p = (LinkList)malloc(sizeof(Node));
scanf("%d", &p->data);
p->next = NULL;
r->next = p;
r = p;
}
}
bool ListInsert(LinkList L, int i, int e) {
LinkList p = L;
int j = 0;
while (p && j < i - 1) { p = p->next; j++; }
if (!p || j > i - 1) return false;
LinkList s = (LinkList)malloc(sizeof(Node));
s->data = e;
s->next = p->next;
p->next = s;
return true;
}
bool ListDelete(LinkList L, int i, int *e) {
LinkList p = L;
int j = 0;
while (p->next && j < i - 1) { p = p->next; j++; }
if (!p->next || j > i - 1) return false;
LinkList q = p->next;
p->next = q->next;
*e = q->data;
free(q);
return true;
}
LinkList LocateElem(LinkList L, int e) {
LinkList p = L->next;
while (p && p->data != e) p = p->next;
return p; // 找到返回節點指標,否則 NULL
}
void PrintList(LinkList L) {
LinkList p = L->next;
while (p) {
printf("%d ", p->data);
p = p->next;
}
printf("\n");
}
void DestroyList(LinkList L) {
LinkList p = L, q;
while (p) {
q = p->next;
free(p);
p = q;
}
}
void ReverseList(LinkList L) {
LinkList p = L->next, q;
L->next = NULL;
while (p) {
q = p->next;
p->next = L->next;
L->next = p;
p = q;
}
}
LinkList MergeList(LinkList La, LinkList Lb) {
LinkList Lc = InitList(), pc = Lc;
LinkList pa = La->next, pb = Lb->next;
while (pa && pb) {
if (pa->data <= pb->data) {
pc->next = pa; pa = pa->next;
} else {
pc->next = pb; pb = pb->next;
}
pc = pc->next;
}
pc->next = pa ? pa : pb;
free(Lb);
return Lc;
}
| 操作 | 單向鏈表 | 陣列 |
|---|---|---|
| 存取第 i 個 | O(i) | O(1) |
| 插入/刪除(已知位置) | O(1) | O(n) |
| 記憶體利用 | 動態、無碎片 | 靜態、可能浪費/不足 |
| 空間開銷 | 額外指標域 | 無額外開銷 |
單向鏈表是理解指標、動態記憶體、遞歸/迭代遍歷的最佳練習題。掌握「頭節點統一邏輯」、「雙指標遍歷(前驅/當前)」、「就地修改指標」三大核心技巧,即可靈活應對各類鏈表問題。