1.算法思路
- 将两单链表合并,常用的方法是归并排序。每次比较两个链表的当前结点值,选择较大的结点值进行插入操作。
- 由于是将递减有序的链表变为递增有序的链表,那么可以考虑使用头插法,每次归并排序比较完成后将更大值的结点插入到已排序链表中,然后移动排序链表的头指针指向该结点。
2.定义结构体
typedef struct LNode {
int data;
struct LNode *next;
} LNode, *LinkList;
3.定义函数
3.1 创建单链表
编写函数创建单链表。输入参数为:
- LinkList A: 单链表的头结点
- int a[]: 该单链表的元素值
- length: 元素值的长度
当i < length时,循环创建结点,并使用尾插法将结点插入到当前链表的最后面,然后将链表尾指针移动至尾部,即当前结点。
void CreateList(LinkList A, int a[], int length) {
LNode *s = (LNode *)malloc(sizeof(LNode));
LNode *tail = A;
s->next = NULL;
for(int i=0; i < length; i++) {
s = (LNode *)malloc(sizeof(LNode));//创建新结点
s->data = a[i];
s->next = NULL;
tail->next = s;
tail = tail->next;
}
}
3.2 合并单链表
- 首先创建链表头结点C,它将指向已排好序的链表头结点,每次使用头插法插入新结点后都将指向此时的头结点,即新结点。
- 创建工作指针p,q分别指向A和B的首个数据结点。判断p,q是否为空。如果有链表为空,则返回NULL。这里假定两个链表都不为空时才进行排序,否则结束程序。
- 当p,q都不为空时,遍历A,B链表,比较结点值,进行如下判断:
- p->data == q->data: 说明两结点值重复,因此选择删除一个结点,头插另一个结点。这里选择插入p结点而删除q结点。首先使用指针s只想当前结点p,然后将p结点向后移动,之后修改相应指针实现p的头插。然后将s指向q,并让q向后移动,再释放s。
- p->data > q->data: 此时选择更大的结点即p将其插入到排序链表中,然后p后移,比较新的p和q。
- p->data < q->data: 此时选择更大的结点即q将其插入到排序链表中,然后q后移,比较新的p和q。
- 当A或B遍历完成时,上述循环退出。此时判断p,q哪个指针为空。使用头插法将未空指针后面的剩余结点插入到排序链表。
LinkList MergeList(LinkList A, LinkList B) {
//C用于指向以合并链表的头结点
LinkList C = (LinkList)malloc(sizeof(LNode));
C->next = NULL;
//p,q用于遍历两个链表,s用于指向当前结点更大的结点
LNode *p = A->next, *q = B->next, *s = NULL;
if(!p || !q) {
printf("链表为空!\n");
return NULL;
}
while(p && q) {//p,q都不为空,开始比较
if(p->data == q->data) {//p,q相等,删除一个结点
//首先将一个结点头插到当前链表中
s = p;
p = p->next;
s->next = C->next;
C->next = s;
//删除另一个结点
s = q;
q = q->next;
free(s);
}
else {
if(p->data > q->data) {//p的结点值更大,将s移到p
s = p;
p = p->next;
} else{//q的结点值更大,将s移到q
s = q;
q = q->next;
}
s->next = C->next;
C->next = s;
}
}
while(p) {//当q为空时,将q剩下的进行头插法
s = p;
p = p->next;
s->next = C->next;
C->next = s;
}
while(q) {//当p为空时,将p剩下的进行头插法
s = q;
q = q->next;
s->next = C->next;
C->next = s;
}
return C->next;
}
4.测试结果
给出两组测试结果:
LinkList A = (LinkList)malloc(sizeof(LNode));
LinkList B = (LinkList)malloc(sizeof(LNode));
int a[] = {7,6,5,4,3,2,1};
int b[] = {9,5,3,1};
CreateList(A, a, sizeof(a) / sizeof(a[0]));
CreateList(B, b, sizeof(b) / sizeof(b[0]));
LinkList A = (LinkList)malloc(sizeof(LNode));
LinkList B = (LinkList)malloc(sizeof(LNode));
int a[] = {7,5,3,1};
int b[] = {7,5,3,1};
CreateList(A, a, sizeof(a) / sizeof(a[0]));
CreateList(B, b, sizeof(b) / sizeof(b[0]));
5.完整代码
#include <iostream>
using namespace std;
//定义结构体
typedef struct LNode {
int data;
struct LNode *next;
} LNode, *LinkList;
//合并两个递减链表并实现递增有序
LinkList MergeList(LinkList A, LinkList B) {
//C用于指向以合并链表的头结点
LinkList C = (LinkList)malloc(sizeof(LNode));
C->next = NULL;
//p,q用于遍历两个链表,s用于指向当前结点更大的结点
LNode *p = A->next, *q = B->next, *s = NULL;
if(!p || !q) {
printf("链表为空!\n");
return NULL;
}
while(p && q) {//p,q都不为空,开始比较
if(p->data == q->data) {//p,q相等,删除一个结点
//首先将一个结点头插到当前链表中
s = p;
p = p->next;
s->next = C->next;
C->next = s;
//删除另一个结点
s = q;
q = q->next;
free(s);
}
else {
if(p->data > q->data) {//p的结点值更大,将s移到p
s = p;
p = p->next;
} else{//q的结点值更大,将s移到q
s = q;
q = q->next;
}
s->next = C->next;
C->next = s;
}
}
while(p) {//当q为空时,将q剩下的进行头插法
s = p;
p = p->next;
s->next = C->next;
C->next = s;
}
while(q) {//当p为空时,将p剩下的进行头插法
s = q;
q = q->next;
s->next = C->next;
C->next = s;
}
return C->next;
}
//创建单链表
void CreateList(LinkList A, int a[], int length) {
LNode *s = (LNode *)malloc(sizeof(LNode));
LNode *tail = A;
s->next = NULL;
for(int i=0; i < length; i++) {
s = (LNode *)malloc(sizeof(LNode));//创建新结点
s->data = a[i];
s->next = NULL;
tail->next = s;
tail = tail->next;
}
}
int main() {
//创建单链表
LinkList A = (LinkList)malloc(sizeof(LNode));
LinkList B = (LinkList)malloc(sizeof(LNode));
int a[] = {7,6,5,4,3,2,1};
int b[] = {9,5,3,1};
CreateList(A, a, sizeof(a) / sizeof(a[0]));
CreateList(B, b, sizeof(b) / sizeof(b[0]));
LinkList p = A->next;
//打印查看原始数据
printf("A链表的数据为:\n");
while(p) {
printf("%d\t", p->data);
p = p->next;
}
printf("\n");
p = B->next;
printf("B链表的数据为:\n");
while(p) {
printf("%d\t", p->data);
p = p->next;
}
printf("\n");
//获取合并后的链表
LinkList q = MergeList(A, B);
//打印输出
printf("修改后链表的数据为:\n");
while(q) {
printf("%d\t", q->data);
q = q->next;
}
return 0;
}