給定兩個按元素值遞增有序的單鏈表 A 和 B(帶頭結點),要求將其合併為一個按元素值遞減有序(非遞增)的單鏈表 C,**不允許申請新結點,必須利用原表結點空間**構造 C 表。
常規合併有序鏈表采用尾插法保持遞增。本題要求遞減,只需在合併過程中改用頭插法:每次取出較小的結點,插入到 C 表頭結點之後。由於先取出的較小元素先插入表頭,後取出的較大元素又插在它們前面,最終 C 表自然呈現遞減順序——「合併即逆序,一舉兩得」。
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
#include <stdio.h>
#include <malloc.h>
typedef int ElemType;
typedef int Status;
typedef struct LNode {
ElemType data;
struct LNode *next;
} LNode, *LinkList;
// 尾插法建表(輸入0結束)
void CreateList_TailInsert(LinkList *L) {
LinkList p, r;
int ch;
scanf("%d", &ch);
r = *L; // r 指向尾結點
while (ch != 0) {
p = (LinkList)malloc(sizeof(LNode));
p->data = ch;
r->next = p;
r = p;
scanf("%d", &ch);
}
r->next = NULL;
}
// 初始化帶頭結點的空表
void InitList(LinkList *L) {
*L = (LinkList)malloc(sizeof(LNode));
(*L)->next = NULL;
}
// 核心合併算法:頭插法構造遞減表 C
Status Merger_AandB_toC(LinkList *La, LinkList *Lb, LinkList *Lc) {
LinkList pa, pb, qa, qb;
(*Lc)->next = NULL; // C 表初始為空
qa = *La; qb = *Lb; // qa/qb 保留前驅,便於斷鏈
pa = (*La)->next; // pa/pb 為工作指針
pb = (*Lb)->next;
while (pa && pb) {
if (pa->data < pb->data) { // 取較小者
qa = pa;
pa = pa->next;
qa->next = (*Lc)->next; // 頭插到 C 表
(*Lc)->next = qa;
} else {
qb = pb;
pb = pb->next;
qb->next = (*Lc)->next;
(*Lc)->next = qb;
}
}
// 剩餘結點批量頭插
if (!pa) while (pb) { qb = pb; pb = pb->next; qb->next = (*Lc)->next; (*Lc)->next = qb; }
if (!pb) while (pa) { qa = pa; pa = pa->next; qa->next = (*Lc)->next; (*Lc)->next = qa; }
return OK;
}
int main() {
LinkList La, Lb, Lc, p;
InitList(&La);
printf("請輸入La元素(0結束):\n");
CreateList_TailInsert(&La);
// 打印La...
InitList(&Lb);
printf("請輸入Lb元素(0結束):\n");
CreateList_TailInsert(&Lb);
// 打印Lb...
InitList(&Lc);
Merger_AandB_toC(&La, &Lb, &Lc);
// 打印Lc...
return 0;
}
qa->next = (*Lc)->next; (*Lc)->next = qa; 兩步順序不可顛倒,否則丟失鏈表。