- 友情提示:
- 本博客所有代码均有使用链表、顺序表预编译的函数,有了算法,后续写程序自主调用就可以了。
- 友情链接:
- 顺序表的基本操作函数:https://blog.csdn.net/lesileqin/article/details/88075259
- 单链表的基本操作函数:https://blog.csdn.net/lesileqin/article/details/88088051
线性表的合并
求解一般集合的并集问题。
【问题描述】已知两个集合A和B,现要求一个新的集合A=A∪B。例如:设A={1,2,5,9};B={2,6,7};合并后为A={1,2,5,9,6,7} 。
【算法步骤】 O(m * n)
①分别获取LA,LB的表长m,n。
②从LB的第一个元素开始,循环n次执行以下操作:
- 从LB中取第i个值,然后赋给e;
- 在LA中查找e,如果LA中没有该值,就插入到LA最后,表长++。
void MergeList(List &LA,List &LB)
{
//将所有在线性表LB中但不在LA中的数据元素插入到LA中
int m=ListLength(LA),n=ListLength(LB); //获取LA,LB的长度
for(int i=1;i<=n;i++) //遍历LB中的每个元素
{
ElemType e; //定义数据类型e
GetElem(LB,i,e); //在LB中取第i个位置的值
if(!LocateElem(LA,e)) //如果LA中没有这个元素,
ListInsert(LA,++m,e); //插入到LA的最后面
}
}
注:具体实现可以采用顺序模式,也可以采用链表形式。
有序表的合并
求解有序集合(递增或者递减)的并集,得出的线性表也应该为有序表。
【问题描述】已知两个集合A和B,数据元素按值递增有序排列,现要求一个新的集合C=A∪B。使C中的数据元素仍按值递增有序排列。例如:A={1,5,7,9,11}; B={1,2,5,6,8,10}。则C={1,1,2,5,5,6,7,8,9,10,11}。
【问题分析】可以用两个线性表LA和LB分别表示集合A和集合B,不同的是,此例子LA和LB有序,这样就没必要从LB中取元素,然后遍历LA了,只需要比较第一个元素的大小就可以了。具体步骤如下:
顺序有序表的合并 O(m+n)
注:因为需要新开辟空间、所有空间复杂度较高
【算法步骤】
- 计算LC的表长(LA、LB的表长相加)
- 为合并后的新表分配一个数组空间
- 初始化a、b、c,分别代表LA、LB、LC的下标
- 当下标均未达到表长的时候,比较LA[a]、LB[b]元素值,谁大谁插入到LC中,下标相应++
- 若LA的下标没有达到LA末尾,则依次插入后续元素
- 若LB的下标没有达到LB末尾,则依次插入后续元素
void MergeList_Sq(Sqlist LA,Sqlist LB,Sqlist &LC)
{
//已知顺序有序表LA、LB按值递增
//归并LA、LB得到新表LC,LC也递增
LC.length=LA.length+LB.length; //得到LC表长
LC.data=new ElemType[LC.length]; //为LC开辟一个新的空间
int c=0,a=0,b=0; //初始化三个数分别是三个表的下表
while(a<LA.length&&b<LB.length) //LA与LB均不到末尾
{
if(LA.data[a]<=LB.data[b])
LC.data[c++]=LA.data[a++];
else
LC.data[c++]=LB.data[b++];
}
while(a<LA.length) //当LA的下标不到末尾
LC.data[c++]=LA.data[a++]; //依次插入LA后面的数
while(b<LB.length)
LC.data[c++]=LB.data[b++];
}
链式有序表的合并 O(m+n)
注:归并LA和LB得到单链表LC。因为链表结点之间的关系是通过指针指向建立起来的,所以用链表进行归并并不需要开辟新的存储空间,可以直接利用原来两个表的存储空间,合并过程只需把LA和LB的结点重新链接即可。空间复杂度较低,O(1)。
【算法步骤】
如上图所示, 结点的重新链接过程已经很明确了(图是本人用flash做的……小声bb)。详细步骤如下:
- 指针pa、pb和pc初始化,分别指向LA、LB首元结点、LC头结点(LC的结点取值为LA的头结点)
- 当pa、pb均没达到表尾时,则比较pa、pb所指元素值,从LA或LB中摘取元素较小的结点插入到LC最后
- 将非空表的剩余段插入到pc所指结点之后
- 释放LB头结点
void MergeList_L(LinkList &LA,LinkList &LB,LinkList &LC)
{
//已知顺序有序表LA、LB按值递增
//归并LA、LB得到新表LC,LC也递增
LNode *pa,*pb,*pc;
pa=LA->next;
pb=LB->next;
LC=LA;
pc=LC;
//以上步骤为三个指针的指向赋值
while(pa&&pb)
{
//当pa和pb均为达到表尾时继续执行
if(pa->data<=pb->data) //摘取pa所指 结点
{
pc->next=pa; //将pa所值结点链接到pc所指结点之后
pc=pa; //pc指向pa
pa=pa->next; //pa指向下一个结点
}
else
{
pc->next=pb;
pc=pb;
pb=pb->next;
}
}
pc->next=pa?pa:pb; //将非空表的剩余段链接到pc所指结点之后
/*
同理
if(pa) pc->next=pa;
else pc->next=pb;
*/
delete LB; //释放LB头结点
}
稀疏多项式运算
【问题描述】多项式的简单相加,对应指数相同的系数相加即可。例如多项式 与多项式 相加可得:。
【问题分析】
稀疏多项式的相加主要有两个相关数值,系数与指数,所以该问题可以抽象成一个线性表,和顺序存储结构相比,链式存储结构更加灵活,空间复杂度也较低,所以我们将采用单链表的基本操作来实现稀疏多项式的运算。
根据多项式相加的运算规则:对于两个多项式中所有的指数相同的项,对应系数相加,若其和不为0,则作为“和多项式”中的一项插入到“和多项式”链表中去;对于两个多项式中指数不相同的项,则将指数值较小的项插入到“和多项式”链表中去。“和多项式”链表中的结点无需生成,而应该从两个多项式链表中摘取。
【案例实现】
用链表表示多项式,其中包括系数(coef)和指数(expn)两个数据域以及一个指针域(next)。
typedef struct PNode{
float coef; //系数
int expn; //指数
struct PNode *next;
}PNode,*Polynomial;
多项式的创建 O(n^2)
【问题分析】类似于链表的创建方法(尾插法),区别在于该链表是一个有序表,每项的位置要经过比较才能确定。通过比较,找到第一个大于该输入项指数的项,将输入项插到此项前面,保证有序。
【算法步骤】
①创建一个只有头结点的空链表
②循环n次执行以下操作:
- 生成一个新结点*s,并输入多项式当前项的系数和指数赋给新结点*s的数据域;
- 设置一个前驱指针pre,用于指向待找元素(第一个大于输入项指数的结点)的前驱,pre的初值指向头结点;
- 指针q初始化,指向首元结点;
- 从头开始遍历链表,比较当前结点与输入项指数,找到第一个大于输入项指数结点*q;
- 将输入项结点*s插入到*q之前,*pre之后。
void CreatPolyn(Polynomial &P,int n)
{
P=new PNode;
P->next=NULL; //创建一个带头结点的单链表
for(int i=1;i<=n;i++)
{
PNode *s=new PNode;
cin >> s->coef >> s->expn;
PNode *pre=P; //pre用于保存q的前驱,初值为头结点
PNode *q=P->next; //q初始化 用于指向首元结点
while(q&&q->coef<s->coef)
{
pre=q;
q=q->next;
}
s->next=q; //将s插入到pre与q之间
pre->next=s;
}
}
多项式相加 O(m+n)
【问题分析】对于两个多项式中所有的指数相同的项,对应系数相加,若其和不为0,则作为“和多项式”中的一项插入到“和多项式”链表中去;对于两个多项式中指数不相同的项,则将指数值较小的项插入到“和多项式”链表中去。“和多项式”链表中的结点无需生成,而应该从两个多项式链表中摘取。
【算法步骤】
①指针p123初始化,分别指向pa和pb首元结点,pa的头结点
②当p1和p2均未到达相应表尾时,则循环比较p1和p2所指结点对应的指数,有下列三种情况
- 当指数相等时,对应系数相加,若和不为0,则修改p1所指结点的系数值,同时删除p2所指结点,若和为0,则删除p1和p2所指结点
- 当p1->expn < p2->expn时,则应把p1插入到“和多项式”链表中去
- 当p1->expn > p2->expn时,则应把p2插入到“和多项式”链表中去
void AddPolyn(Polynomial &Pa,Polynomial &Pb)
{
//多项式加法
PNode *p1,*p2,*p3;
p1=Pa->next;
p2=Pb->next;
p3=pa;
//分别指向pa pb首元结点 与pa头结点
while(p1&&p2)
{
if(p1->expn==p2->expn)
{
int sum=p1->coef+p2->coef;
if(sum!=0)
{
p1->coef=sum; //修改pa当前结点的系数值为两项系数的和
p3->next=p1;
p3=p1; //将修改后的pa当前结点连在p3之后,p3指向p1
p1=p1->next; //指向后一项
//释放p2
PNode *r=p2;
p2=p2->next; //指向后一项
delete r; //释放p2
}
else //若sum==0 释放p1 p2
{
PNode *r;
r=p1; p1=p1->next; delete r;
r=p2; p2=p2->next; delete r;
}
}
else if(p1->expn<p2->coef) //若p1指的指数小于p2的指数
{
p3->next=p1; //将p1连在p3之后;
p3=p1; //p3指向p1
p1=p1->next;
}
else
{
p3->next=p2;
p3=p2;
p2->next=p2;
}
}
p3->next=p1?p1:p2; //插入非空多项式的剩余段
delete Pb;
}
具体实现代码请访问:https://blog.csdn.net/lesileqin/article/details/88379112
本博客内容借鉴于:
《数据结构》 作者:严蔚敏