有序单链表的归并算法
要求空间复杂度O(1),因此必须原地修改指针,不额外创建新节点;这句话的意思是:
O (1) 空间复杂度:算法执行过程中,除了输入本身占用的空间外,额外开辟的辅助空间是常数级(不随输入数据量增大而增长),也就是只能用几个固定的指针变量,不能申请新的链表节点、数组等。
原地修改指针:不创建新的节点,只通过修改已有节点的 next 指针指向,把 LA 和 LB 的节点重新串联成一个新的有序链表。
不额外创建新节点:整个合并过程中,不会调用 malloc 去生成新的 LNode,所有节点都是原来 LA 和 LB 里的节点,只是 “搬家” 到新的链表结构里
1、初始化指针:
用 pa 指向 LA 的第一个数据节点(LA->next),pb 指向 LB 的第一个数据节点(LB->next)。
用 pc 作为结果链表的尾指针,初始指向 LA 的头结点(复用 LA 头结点作为结果头结点)。
2、归并遍历:
循环比较 pa->data 和 pb->data:
若 pa->data ≤ pb->data:将 pa 节点链接到 pc 后,pa 和 pc 都向后移动。
若 pa->data > pb->data:将 pb 节点链接到 pc 后,pb 和 pc 都向后移动。
3、处理剩余节点:
当 pa 或 pb 其中一个遍历结束后,将另一个链表的剩余节点直接链接到 pc 之后。
释放 LB 头结点:
由于 LB 节点已全部并入 LA,释放 LB 的头结点以避免内存泄漏,最终 LA 即为合并后的有序链表
#include<stdio.h>
#include<stdlib.h>
// 题目给定的单链表类型定义
typedef int ElemType; // 假设元素类型为int
typedef struct LNode {
ElemType data;
struct LNode* next;
} LinkList;
// 合并两个有序单链表 LA 和 LB,结果存于 LA,空间复杂度 O(1)
void MergeList(LinkList & LA, LinkList & LB) {
LinkList pa = LA->next; // pa 指向 LA 的第一个数据节点
LinkList pb = LB->next; // pb 指向 LB 的第一个数据节点
LinkList* pc = LA; // pc 指向结果链表的尾节点,初始为 LA 头结点
//归并两个有序链表
while (pa != NULL && pb != NULL) {
if (pa->data < pb->data) {
pc->next = pa;
pc = pa;
pa = pa->next;
}
else {
pc->next = pb;
pc = pb;
pb = pb->next;
}
}
//链接剩余节点
if (pa != NULL) {
pc->next = pa; // LA 还有剩余节点
}
else {
pc->next = pb; // LB 还有剩余节点
}
free(LB);//释放LB头节点(空间复用)
LB = NULL;//避免野指针
}
//辅助函数
//创建带头节点的单链表(尾插法)
LinkList* CreateList(int arr[], int n) {
LinkList* head = (LinkList)malloc(sizeof(LinkList));
head->next = NULL;
LinkList p = head; //设置尾指针,初始指向头节点
for (int i = 0; i < n; i++) {
LinkList* newNode = (LinkList*)malloc(sizeof(LinkList));
newNode->data = arr[i];
newNode -> next = NULL;
p->next = newNode;
p = newNode;
}
return head;
}
浙公网安备 33010602011771号