文章目录
1.算法思想
设置三个指针pre,p,q,用于指向A的前驱,A当前结点以及B当前结点,比较A,B当前结点的大小,如果:
- p->data > q->data,则q后移;
- p->data < q->data,释放p,并后移p指针;
- p->data == q->data,修改指针,将p使用头插法插入到最前面。
循环比较链表A与B,直到某链表遍历完成。此时检查p,若不为空则说明A还有未比较结点,释放后面所有的结点。
2.定义结构体
LNode表示结点,Linklist表示链表。这个结构体没什么说的。
typedef struct LNode {
int data;
struct LNode *next;
} LNode, *LinkList;
3.比较函数实现
主要是分析三种不同的情况,分别对这三种情况分析。
3.1 p->data > q->data
当p->data > q->data,说明A链表当前值太大,且B链表中q指针之前的值都小于当前值,因此移动B链表,寻找更大值。
if(p->data > q->data) {
q = q->next;
}
3.2 p->data < q->data
若p->data < q->data,说明A的当前值太小,且B的后面的值都大于当前q指向的值,因此要删除p指向的结点。使用前驱指针进行删除。基本思路为:
- 修改前驱结点pre的指向,让其指向p的后继结点,即pre->next = p->next;
- 释放p指针指向的结点,释放空间;
- 修改p指针,让其指向pre->next,修改后满足pre为p的前驱结点指针。
else if(p->data < q->data) {//删除p结点
pre->next = p->next;
free(p);
p = pre->next;
}
3.3 p->data == q->data
当这两个数相等时,应该将p指向的结点使用头插法变成链表头,然后p,q分别后移。要注意此处p要分为是否为第一个结点。
- p为第一个结点,即A->next = p,那么此时pre = A,p = A-> next,这个时候p已经是链表头结点,不需要更改,因此直接将pre,p,q后移一位即可。
- p不为第一个结点,那么就要进行头插法。基本思路为:
先将pre指向p的后继,即pre->next = p->next。然后修改p,使其作为头结点,即p->next = A->next,然后修改A->next,让其指向p结点。最后修改p结点为pr->next,实现了一次头结点的插入。
else {//头插法将当前结点插入到链表头部,形成降序链表
if(pre != A) {
pre->next = p->next;
p->next = A->next;
A->next = p;
p = pre->next;
q = q->next;
}
else {
p = p->next;
pre = pre->next;
q = q->next;
}
}
3.4检查链表
当p或q任意一个遍历完成时,都会退出上个步骤的循环。此时有两种情况:
- p==NULL,说明A链表已经遍历完成,在A链表上一件找不出比当前q还大的值。
- q==NULL,说明B链表已遍历完成,已经在B链表上找不出比当前p还大的值。因此检查p是否为空,如果不为空,则删除p后所有的结点。
//当p或q遍历完成时,删除p剩余结点
while (p!=NULL) {
pre->next = p->next;
free(p);
p = pre->next;
}
}
4.运行结果
在主函数中初始化A,B链表,然后调用GetCommon函数,将A,B进行倒置合并,得到最终结果。
5.完整代码
#include <iostream>
using namespace std;
//定义链表结构体
typedef struct LNode {
int data;
struct LNode *next;
} LNode, *LinkList;
//求A,B的交集
void GetCommon(LinkList &A, LinkList &B) {
//工作指针pre指向A的前一个结点,p指向A的当前结点,q指向B的当前结点
LinkList pre = A, p = A->next,q = B->next;
while(p && q) { //p,q均不为空,开始判断
if(p->data > q->data) {
q = q->next;
} else if(p->data < q->data) {//删除p结点
pre->next = p->next;
free(p);
p = pre->next;
} else {//头插法将当前结点插入到链表头部,形成降序链表
if(pre != A) {
pre->next = p->next;
p->next = A->next;
A->next = p;
p = pre->next;
q = q->next;
}
else {
p = p->next;
pre = pre->next;
q = q->next;
}
}
}
//当p或q遍历完成时,删除p剩余结点
while (p!=NULL) {
pre->next = p->next;
free(p);
p = pre->next;
}
}
int main() {
//创建数据进行测试。A链表2,3,5,B链表2,3
LinkList A = (LinkList)malloc(sizeof(LNode));
LNode *a1 = (LNode *)malloc(sizeof(LNode));
LNode *a2 = (LNode *)malloc(sizeof(LNode));
LNode *a3 = (LNode *)malloc(sizeof(LNode));
A->next = a1;
a1->next = a2;
a2->next = a3;
a3->next = NULL;
a1->data = 2;
a2->data = 3;
a3->data = 5;
LinkList p = A->next;
printf("A链表的数据为:\n");
while(p) {
printf("%d\t", p->data);
p = p->next;
}
LinkList B = (LinkList)malloc(sizeof(LNode));
LNode *b1 = (LNode *)malloc(sizeof(LNode));
LNode *b2 = (LNode *)malloc(sizeof(LNode));
B->next = b1;
b1->next = b2;
b2->next = NULL;
b1->data = 2;
b2->data = 3;
LinkList q = B->next;
printf("\nB链表的数据为:\n");
while(q) {
printf("%d\t", q->data);
q = q->next;
}
printf("\n合并A,B后的数据为:\n");
GetCommon(A,B);
p = A->next;
while(p) {
printf("%d\t",p->data);
p = p->next;
}
return 0;
}