CH2-线性表
2.4线性表的顺序表示和实现
随机存取法:
-
利用数据元素的存储位置表示线性表中相邻数据元素之间的前后关系,即线性表的逻辑结构与存储结构一致
-
在访问线性表时,可以快速地计算出任何一个数据元素的存储地址。因此可以粗略地认为,访问每个元素所花时间相等
基本操作
线性表的基本操作:
InitList(&L) //初始化操作,建立一个空的线性表L
DestroyList(&L) //销毁已存在的线性表L
ClearList(&L) //将线性表清空
ListInsert(&L, i, e) //在线性表L中第个位置插入新元素e
ListDelete(&L, i, &e) //删除线性表L中第i个位置元素,用e返回
IsEmpty(L) //若线性表为空,返回true,否则false
ListLength(L) //返回线性表L的元素个数
LocateElem(L, e) //L中查找与给定值e相等的元素,若成功则返回该元素在表中的序号,否则返回0
GetElem(L, i, &e) //将线性表L中的第个位置元素返回给e
算法分析
-
时间复杂度:
查找、插入、删除算法的平均时间复杂度为0(n)
-
空间复杂度:
显然,顺序表操作算法的空间复杂度S(n)=O(1) (没有占用辅助空间)
-
优点:
-
存储密度大(结点本身所占存储量/结点结构所占存储量)
-
可以随机存取表中任一元素
-
-
缺点:(为克服这一缺点,链表这一数据结构顺应而生)
-
在插入、删除某一元素时,需要移动大量元素
-
浪费存储空间
-
·属于静态存储形式,数据元素的个数不能自由扩充
-
算法实现
【算法2.1】线性表L的初始化
Status InitList_Sq(SqList &L){ //构造一个空的顺序表L
L.elem=new ElemType[MAXSIZE]; //为顺序表分配空间
if(!L.elem) exit(OVERFLOW); //存储分配失败
L.length=0; //空表长度为0
return OK;
}
- 销毁线性表L
void DestroyList(SqList &L) {
if (Lelem) delete L.elem; //释放存储空间
}
- 清空线性表L
void ClearList(SqList &L){
L.length=0; //将线性表的长度置为0
}
- 求线性表L的长度
int GetLength(SqList L){
return (L.length);
}
- 判断线性表L是否为空
int IsEmpty(SqList L){
if (L.length==0) return 1;
else return 0;
}
//函数结果状态代码
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
//Status是函数的类型,其值是函数结果状态代码
typedef int Status;
typedef char ElemType;
【算法2.2】顺序表的取值
int GetElem(SqList L, int i, ElemType &e){
if (i<1||i>L.length) return ERROR;
//判断值是否合理,若不合理,返回ERROR
e=L.elem[i-1]; //第i-1的单元存储着第i个数据
return OK;
}
【算法2.3]顺序表的查找
int LocateELem(SqList L, ElemType e){ //在线性表L中查找值为e的数据元素,返回其序号(是第几个元素)
for (i=0; i<L.length; i++)
if (L.elem[i]==e) return i+1; //查找成功,返回序号
return 0; //查找失败,返回0
}
【算法2.4】顺序表的插入
Status ListInsert Sq(SqList &L,int i , ElemType e){
if(i<1||i>L.length+1) return ERROR; //i值不合法
if(L.length==AXSIZE) return ERROR; //当前存储空间已满
for(j=L.length-1; j>=i-1; j--)
L.elem[j+1]=L.elem[j]; //插入位置及之后的元素后移
L.elem[i-1]=e; //将新元素e放入第i个位置
L.length++; //表长增1
return OK;
}
【算法2.5】顺序表的删除
Status ListDelete Sg(SqList &L, int i){
if((i< 1)||(i>L.length)) return ERROR; //i值不合法
for (j=i; j<=L.length-1; j++)
L.elem[j-1] L.elem[j]; //被删除元素之后的元素前移
L.length--; //表长减1
return OK;
}
2.5 线性表的链式表示和实现
基本概念
结点(node): 包括两个域,数据域和指针域。
数据域: 存储数据元素信息的域
指针域: 存储下一数据元素地址的域
指针(链): 指针域中存储的信息
链表:n个结点链结成的一个表
单链表:链表的每个结点中只包含一个指针域,又称为线性链表
头指针: 指示链表中第一个结点的指针。如下图所示L
首元结点: 存储第一个数据元素的结点,如下图所示结点"ZHAO"
头结点:在首元结点之前附设的一个结点,其指针域指向首元结点。存储与数据元素类型相同的其他附加信息。例如,头结点的数据域中可存放该线性表的长度。

头结点的作用
-
便于首元结点的处理
增加了头结点后,首元结点的地址保存在头结点(即其 “前驱” 结点)的指针域中,则对链表
的第一个数据元素的操作与其他数据元素相同,无需进行特殊处理。 -
便于空表和非空表的统一处理
当链表不设头结点时,假设 L 为单链表的头指针,它应该指向首元结点,则当单链表为长度
n 为 0 的空表时, L 指针为空(判定空表的条件可记为:L== NULL)。 增加头结点后,无论链表是否为空,头指针都是指向头结点的非空指针。如图2.10 (a)所示 的非空单链表,头指针指向头结点。若为空表,则头结点的指针域为空(判定空表的条件可记为: L ->next== NULL), 如图2.10 (b)所示。

单链表的存储结构
//----- 单链表的存储结构-----
typedef struct LNode
{
ElemType data; //结点的数据域
struct LNode *next; //结点的指针域
}LNode,*LinkList; //LinkList 为指向结构体 LNode 的指针类型
(1) 数据域 data, 其类型用通用类型标识符 ElemType 表示;存储后继结点位置的指针域 next, 其类型为指向结点的指针类型 LNode 。
(2) 为了提高程序的可读性,在此对同一结构体指针类型起了两个名称,LinkList 与LNode* , 两者本质上是等价的。通常习惯上用 LinkList 定义单链表,强调定义的是某个单链表的头指针;用 LNode *定义指向单链表中任意结点的指针变量。例如,若定义 LinkList L,则L为单链表的头指针,若定义 LNode *p,则p为指向单链表中某个结点的指针,p 代表该结点。当然也可以使用定义 LinkListp, 这种定义形式完全等价于 LNodep。
(3) 单链表是由表头指针唯一确定,因此 单链表可以用头指针的名宇来命名。若头
指针名是L, 则简称该链表为表L。
(4) 注意区分指针变量和结点变量两个 不同的概念,若定义 LinkListp 或 LNodep,
则p 为指向某结点的指针变量,表示该结点的地址;而p 为对应的结点变量,表示该结
点的名称。
二、基本操作
算法 2.6 初始化
-
【算法步骤】
- 生成新结点作为头结点,用头指针L 指向头结点。
- 头结点的指针域置空。
-
【算法描述】
Status InitList(LinkList &L) {//构造一个空的单链表L L=new LNode; //生成新结点作为头结点, 用头指针L指向头结点 L->next=NULL; //头结点的指针域置空 return OK; }
算法 2.7 取值
-
取单链表中第i个元素的内容
-
【算法步骤]
- 从第1个结点(L->next)顺链扫描,用指针p指向当前扫描到的结点,p初值p = L->next。
- j做计数器,累计当前扫描过的结点数,j初值为1。
- 当p指向扫描到的下一结点时,计数器j加1。
- 当j ==i时,p所指的结点就是要找的第i个结点。
-
[算法描述】
Status GetElem(LinkList L,int i,ElemType &e) {//在带头结点的单链表L中根据序号i获取元素的值,用e返回L中第i个数据元素的值 p=L->next; j=1; //初始化,p指向首元结点,计数器初值赋为1 while(p&&j<i) //顺链域向后扫描,直到p为空或p指向第i个元素 p=p->next; //p指向下一个结点 ++j; //计数器j相应加1 if(!p||j>i)return ERROR; //第i个元素不存在 e=p->data; //取第i个结点的数据域 return OK; } -
算法分析
最坏时间复杂度为O(n)
平均时间复杂度为O(n)
算法2.8 按值查找
- 根据指定数据获取该数据所在的位置(地址)
- 【算法步骤】
- 用指针p指向首元结点 。
- 从首元结点开始依次顺着链域next向下查找, 只要指向当前结点的指针p不为空, 并且p所指结点的数据域不等于给定值e, 则循环执行以下操作: p指向下一个结点 。
- 返回p。若查找成功,p此时即为结点的地址值,若查找失败,p的值即为NULL。
- 【算法描述】
LNode *LocateELem(LinkList L, Elemtype e)
{//在带头结点的单链表L中查找值为e的元素
p=L->next; //初始化,p指向首元结点
while(p && p->data!=e) //顺链域向后扫描,直到p为空或p所指结点的数据域等于e
p=p->next; //p指向下一个结点
return p; //查找成功返回值为e的结点地址p, 查找失败p为NULL
}
- 算法分析
最坏时间复杂度为O(n)
平均时间复杂度为O(n)
【算法2.8变化】按值查找——根据指定数据获取该数据位置序号
//在线性表L中查找值为e的数据元素的位置序号
int LocateELem_L (LinkList L,Elemtype e) {
//返回L中值为e的数据元素的位置序号,查找失败返回0
p=L->next; j=1;
while(p &&p->data!=e)
{p=p->next; j++}
if(p) return j;
else return 0;
}
算法2.9 插入
-
【算法步骤]
将值为 e 的新结点插人到表的第 i 个结点的位置上-
生成一个新结点*s。
-
将新结点*s 的数据域置为 e。
-
将新结点*s 的指针域指向结点
-
将结点
*p的指针域指向新结点*s![20220109094449]()
-
-
【算法描述】
Status Listinsert(LinkList &L,int i,ElemType e)
{//在带头结点的单链表L中第i个位置插入值为e的新结点
p=L;j=O;
while (p && (j<i-1))
{p=p->next;++j;} //查找第i-1个结点,p指向该结点
if (!p||j>i-1) return ERROR; //i>n+l或者区1
s=new LNode; //生成新结点*s
s->data= e; //将结点*s的数据域置为e
s->next=p->next; //将结点 *s的指针域指向结点 a,
p->next=s; //将结点*p的指针域指向结点*s
return OK;
}
- 算法分析
最坏时间复杂度为O(n)
平均时间复杂度为O(n)
算法2.10 删除
-
[算法步骤】
删除单链表的 i 个结点 ai-
查找结点 ai-1 并由指针p指向该 结点。
-
临时保存待删除结点 ai 的地址在q中 ,以备释放。
-
将结点*p的指针域指向 ai+1
-
释放结点 ai 的空间。
![20220109100851]()
-
-
【算法描述】
Status ListDelete(LinkList &L,int i)
{//在带头结点的单链表L中,删除第l个元素
p=L;j=O;
while ((p->next) && (j<i-1)) //查找第i-1个结点,p指向该结点
{p=p->next; ++j;}
if (!(p->next) || (j>i-1)) return ERROR; //当i>n或i<1时,删除位置不合理
q=p->next; //临时保存被删结点的地址以备释放
p->next=q->next; //改变删除结点前驱结点的指针域
delete q; //释放删除结点的空间
return OK;
}
- 算法分析
最坏时间复杂度为O(n)
平均时间复杂度为O(n)
算法2.11 创建单链表
头插法
-
【算法步骤】
-
创建一个只有头结点的空链表。
-
根据待创建链表包括的元素个数n, 循环n次执行以下操作:
-
生成一个新结点p;
-
输入元素值赋给新结点p的数据域;
-
将新结点*p插入到头结点之后。
![20220109103627]()
-
![20220109103804]()
-
-
【算法描述】
void CreateList_H(LinkList &L,int n)
{//逆位序输入n个元素的值,建立带表头结点的单链表1
L=new LNode;
L->next=NULL; //先建立一个带头结点的空链表
for(i=O;i<n;++i)
{
p=new LNode; //生成新结点*p
cin>>p->data; //输入元素值赋给新结点*p的数据域
p->next=L->next;
L->next=p; //将新结点*p插人到头结点之后
}
}
- 算法分析
最坏时间复杂度为O(n)
平均时间复杂度为O(n)
尾插法
-
[算法步骤】
-
创建一个只有头结点的空链表。
-
尾指针r初始化, 指向头结点。
-
根据创建链表包括的元素个数n, 循环n次执行以下操作:
-
生成一个新结点p;
-
输入元素值赋给新结点*p 的数据域;
-
将新结点p 插入到尾结点r之后;
-
尾指针r指向新的尾结点*p。
![20220109104040]()
-
-
-
【算法描述】
void CreateList_R(LinkList &L,int n)
{//正位序输人n个元素的值, 建立带表头结点的单链表L
L=new LNode;
L->next=NULL; //先建立一个带头结点的空链表
r=L; //尾指针r指向头结点
for(i=O;i<n;++i)
{
p=new LNode; //生成新结点
cin>>p->data; //输人元素值赋给新结点*p的数据域
p->next=NULL; r->next=p; //将新结点*p插人尾结点*r之后
r=p; //指向新的尾结点*p
}
}
- 算法分析
最坏时间复杂度为O(n)
平均时间复杂度为O(n)
三、算法补充
单链表的销毁
-
【算法思路】从头指针开始,依次释放所有结点
![20220109085547]()
-
【算法】销毁单链表L
Status DestroyList_L(LinkList &L){ //销毁单链表L Lnode *p; //或LinkList p; while(L){ p=L; L->next; delete p; } return OK; }
清空单链表
链表仍存在,但链表中无元素,成为空链表(头指针和头结点仍然在)
-
【算法思路】 依次释放所有结点,并将头结点指针域设置为空
![20220109090201]()
Status ClearList(LinkList & L){ //将L重置为空表 Lnode *p,*q; //或LinkList p,q; p=L->next; while(p) { //没到表尾 q=p->next; delete p; p=q; } L->next=NULL; //头结点指针域为空 return OK; }
求单链表的表长
-
【算法思路】从首元结点开始,依次计数所有结点
![20220109091421]()
int ListLength_L(LinkList L){ //返回L中数据元素个数
LinkList p;
p=L->next; //p指向第一个结点
i=O;
while(p){ //遍历单链表,统计结点数
i++;
p=p->next;
}
return i;
}
判断单链表是否为空
- 空表: 链表中无元素,称为空链表(头指针和头结点仍然在)
- 【算法思路】判断头结点指针域是否为空若L是空表L一int
int ListEmpty(LinkList L){ //若L为空表,则返回1,否则返回O
if(L->next) //非空
return O;
else
return 1;
}
四、算法分析

五、总结


大二:2.5.3循环链表,2.5.4双向链表,2.6顺序表和链表的比较,完成教材中相关算法
2.5 线性表的链式表示和实现
2.5.3循环链表
- 循环链表: 是一种头尾相接的链表(即:表中最后一个结点的指计肴指向头结点,整个链表形成一个环)。
- 优点: 从表中任一结点出发均可找到表中其他结点。

- 注意:
由于循环链表中没有NULL指针,故涉及遍历操作时,其终止条件就不再像非循环链表那样判断p或p->next是否为空,而是判断它们是否等于头指针。

- 尾指针表示法

- 带尾指针循环链表的合并(将Tb合并在Ta之后)

- 带尾指针循环链表的合并
【算法描述】
LinkList Connect(LinkList Ta, LinkList Tb){
//假设Ta、Tb都是非空的单循环链表
p=Ta->next; // p存表头结点
Ta->next=Tb->next->next; // Tb表头连结Ta表尾
delete Tb->next; // 释放Tb表头结点
Tb->next=p; // 修改指针
return Tb;
}
2.5.4双向链表
-
单链表的结点→有指示后继的指针域→找后继结点方便;
- 即:查找某结点的后继结点的执行时间为(O1)。
-
→无指示前驱的指针域→找前驱结点难:从表头出发查找。
- 即:查找某结点的前驱结点的执行时间为On。
-
可用双向链表来克服单链表的这种缺点
-
双向链表: 在单链表的每个结点里再增加一个指向其直接前驱的指针域prior,这样链表中就形成了有两个方向不同的链,故称为双向链表。
-
双向链表的结构可定义如下:
![20220110101521]()
typedef struct DuLNode{
Elemtype data;
struct DuLNode *prior,*next;
} DuLNode, *DuLinkList;

- 双向循环链表
和单链的循环表类似,双向链表也可以有循环表- ·让头结点的前驱指针指向链表的最后一个结点·
- 让最后一个结点的后继指针指向头结点.

- 双向链表结构的对称性(设指针p指向某一结点)∶
p -> prior -> next = p =p -> next -> prior
在双向链表中有些操作(如:ListLength、GetElem等),因仅涉及一个方向的指针,故它们的算法与线性链表的相同。
但在插入、删除时,则需同时修改两个方向上的指针,两者的操作的时间复杂度均为O(n)。

算法
【算法2.13】双向链表的插入

void Listlnsert_DuL( &L, Int i, ElemType e){
//在带头结点的双向循环链表L中第i个位置之前插入元素e
if(!(p=GetElemP_DuL(L,i))) return ERROR;
s=new DuLNode; s ->date = e;
s ->prior = p ->prior; p ->prior->next = s;
s ->next = p; p ->prior = s;
return OK;
} // ListInsert_DuL
【算法2.14】双向链表的删除

void ListDelete_DuL(DuLink &L,Int i, ElemType &e){
//删除带头结点的双向循环链表L的第i个元素,并用e返回。
if(!(p=GetElemP_DuL(L,i))) return ERROR;
e = p -> data;
p-> prior -> next = p -> next;
p -> next -> prior = p -> prior;
free(p);
return OK;
}// ListDelete_DuL

2.6顺序表和链表的比较
-
链式存储结构的优点:
-
结点空间可以动态申请和释放;
-
数据元素的逻辑次序靠结点的指针来指示,插入和删除时不需要移动数据元素。
-
-
链式存储结构的缺点:
- 存储密度小,每个结点的指针域需额外占用存储空间,当每个结点的数据域所占字节不多时,指针域所占存储空间的比重显得很大。
- 链式存储结构是非随机存取结构。对任一结点的操作都要从头指针依指针链查找到该结点,这增加了算法的复杂度。
![20220110112925]()
-
顺序表和链表的比较

2.7线性表的应用

【算法2.15】线性表的合并
- 算法步骤
依次取出Lb中的每个元素,执行以下操作:- 1.在La中查找该元素
- 2.如果找不到,则将其插入La的最后
void union(List &La, List Lb){
La_len=ListLength(La);
Lb_len=ListLength(Lb);
for(i=1;i<=Lb_len;i++){
GetElem(Lb,i,e);
if(!LocateElem(La,e)) Listlnsert(&La,++La_len,e);
}
}
【算法2.16】有序表的合并——顺序表实现
- 算法步骤
- (1)创建一个空表Lc
- (2)依次从La或Lb中“摘取”元素值较小的结点插入到Lc表的最后,直至其中一个表变空为止
- (3)继续将La或Lb其中一个表的剩余结点插入在Lc表的最后

void MergeList_Sq(SqList LA,SqList LB,SqList &LC){
pa=LA.elem;
pb=LB.elem; //指针pa和pb的初值分别指向两个表的第一个元素
LC.length=LA.length+LB.length; //新表长度为待合并两表的长度之和
LC.elem=new ElemType[LC.length]; //为合并后的新表分配一个数组空间
pc=LC.elem; //指针pc指向新表的第一个元素
pa_last=LA.elem+LA.length-1; //指针pa_last指向LA表的最后一个元素
pb_last=LB.elem+LB.length-1; //指针pb_last指向LB表的最后一个元素
while(pa<=pa_last && pb<=pb_last){ //两个表都非空
if(*pa<=*pb) *pc++=*pa++; //依次“摘取”两表中值较小的结点
else *pc++=*pb++;
}
while(pa<=pa_last) *pc++=*pa++; //LB表已到达表尾,将LA中剩余元素加入LC
while(pb<=pb_last) *pc++=*pb++; //LA表已到达表尾,将LB中剩余元素加LC
}//MergeList_Sq

【算法2.17】有序表的合并——链表实现






void MergeList_L(LinkList &La,LinkList &Lb,LinkList &Lc){
pa=La->next; pb=Lb->next;
pc=Lc=La; //用La的头结点作为Lc的头结点
while( pa && pb){
if(pa->data<=pb->data) {
pc->next=pa;
pc=pa;
pa=pa->next;
}
else {
pc->next=pb;
pc=pb;
pb=pb->nexit;
}
}
pc->next=pa?pa:pb; //插入剩余段
delete Lb; //释放Lb的头结点
}
2.8案例分析与实现
【案例2.1】一元多项式的运算
- 实现两个多项式加、减、乘运算


【案例2.2】稀疏多项式的运算



typedef struct PNode
{
float coef; //系数
int expn; //指数
struct PNode *next; //指针域
}PNode,*Polynomial;
【算法 2.18】多项式创建
【算法步骤】
- 创建一个只有头结点的空链表。
- 根据多项式的项的个数n,循环n次执行以下操作:
- ·生成一个新结点*s;
- 输入多项式当前项的系数和指数赋给新结点*s的数据域;
- ·设置一前驱指针pre,用于指向待找到的第一个大于输入项指数的结点的前驱,pre初值指向头结点;
- ·指针q初始化,指向首元结点;
- 循链向下逐个比较链表中当前结点与输入项指数,找到第一个大于输入项指数的结点*q;
- 将输入项结点s插入到结点*q之前。
void CreatePolyn(Polynomial &P, int n){
//输入m项的系数和指数,建立表示多项式的有序链表P
P=new PNode;
P->next=NULL; //先建立一个带头结点的单链表
for(i=1;i<=n;++i){ //依次输入n个非零项
s=new PNode; //生成新结点
cin >>s->coef >>s->expn; //输入系数和指数
pre=P; //pre用于保存q的前驱,初值为头结点
q=P->next; //q初始化,指向首元结点
while(q && q->expn < s->expn) { //找到第一个大于输入项指数的项*q
pre=q; q=q->next;
}
s->next=q; //将输入项s插入到q和其前驱结点pre之间
pre->next=s;
}
}
【算法 2.19】 多项式的相加



void AddPolyn(Polynomial &Pa,Polynomial &Pb)
{//多项式加法: Pa=Pa+Pb, 利用两个多项式的结点构成 “和多项式”
p1=Pa->next; p2=Pb->next; //p1 和 p2 初值分别指向 Pa 和 Pb 的首元结点
p3=Pa; //p3 指向和多项式的当前结点, 初值为 Pa
while (p1&&p2) //p1 和 p2 均非空
{
if(p1->expn==p2->expn) //指数相等
sum=p1->coef+p2->coef; //sum 保存两项的系数和
if(sum!=O) //系数和不为 0
{
p1->coef=sum; //修改 Pa 当前结点的系数值为两项系数的和
p3->next=p1; p3=p1; //将修改后的 Pa 当前结点链在 p3 之后, p3 指向 p1
p1=p1->next; //p1 指向后一项
r=p2; p2=p2->next; delete r; //删除 Pb 当前结点, p2 指向后一项
}
else //系数和为 0
{
r=p1; p1=p1->next; delete r; //删除Pa当前结点,p1指向后一项
r=p2; p2=p2->next; delete r; //删除Pb当前结点,p2指向后一项
}
else if (p1->expn<p2->expn) //Pa当前结点的指数值小
{
p3->next=p1; //将p1链在p3之后
p3=p1; //p3指向p1
p1=p1->next; //p1指向后一项
}
else //Pb当前结点的指数值小
{
p3->next=p2; //将p2链在p3之后
p3=p2; //p3指向p2
p2=p2->next; //p2指向后一项
}
}
p3->next=p1?p1:p2; //插入非空多项式的剩余段
delete Pb; //释放Pb的头结点
}
【案例2.3】图书信息管理系统


struct Book {
char id[20]; //ISBN
char name[50]; //书名
int price; //定价
};
typedef struct {//顺序表
Book *elem;
int length;
} SqList;
typedef struct LNode{//链表
Book data;
struct LNode *next;
}LNode,*LinkList;
2.9算法实现
1.一元多项式的加法
#include <iostream>
using namespace std;
#define MAXSIZE 100
typedef int Status;
typedef int ElemType;
typedef struct //构建一元多项式结构体
{
float *coef;//系数
int length;
}PLinkList;
Status InitList(PLinkList& L)
{ //顺序表初始化
L.coef = new float[MAXSIZE];
if (!L.coef)exit(OVERFLOW);
L.length = 0;
return 1;
}
void CreateList(PLinkList& L, int n)
{
int i; //一元多项式的创建
L.coef = new float[MAXSIZE];
L.length = n;
for (i = 0; i < n; i++)
{
cin >> L.coef[i];
}
}
void AddLinkList(PLinkList LA, PLinkList LB, PLinkList LC, int n)
{
for (int i = 0; i < n; i++)
{ //一元多项式加法函数
LC.coef[i] = LA.coef[i] + LB.coef[i];
}
LC.length = LA.length;
}
void Display(PLinkList L, int n)
{
for (int i = 0; i < n; i++)
cout << L.coef[i] << " "; //显示函数
cout << endl;
}
int main()
{
PLinkList LA, LB, LC;
int n;
n = 3;
InitList(LA);
InitList(LB);
InitList(LC);
cout << "请输入多项式A各项的系数:" << endl;
CreateList(LA, n);
cout << "请输入多项式B各项的系数:" << endl;
CreateList(LB, n);
AddLinkList(LA, LB, LC, n);
cout << "输出和多项式各项的系数:" << endl;
Display(LC, n);
return 0;
}
2.稀疏多项式的加法
#include <iostream>
using namespace std;
typedef struct PNode { //创建结构体
float a; //系数
int e; //指数
struct PNode* next;
}PNode,*PNodenomial;
void CreatePNode(PNodenomial& P,int n) //创建链表
{
P = new PNode;
P->next = NULL;
PNode* r = P;
for (int i = 1; i <= n; ++i)
{
PNodenomial s = new PNode;
cin >> s->a>>s->e;
s->next = NULL;
r->next = s;
r = s;
}
}
PNode* AddPNode(PNodenomial Pa, PNodenomial Pb) //多项式相加函数
{
PNode* pa, * pb, * pc;
PNode* Pc = new PNode;
Pc->next =NULL;
pa = Pa->next;
pb = Pb->next;
pc = Pc;
while (pa && pb)
{
if (pa->e == pb->e)
{
float a= pa->a + pb->a;
if (a)
{
pa->a = a;
pc->next = pa;
pc = pa;
pa = pa->next;
pb = pb->next;
}
else
{
PNode* p1 = pa, * p2 = pb;
pa = pa->next;
pb = pb->next;
delete p1;
delete p2;
}
}
if (pa->e < pb->e)
{
pc->next = pa;
pc = pa;
pa = pa->next;
}
if (pa->e > pb->e)
{
pc->next = pb;
pc = pb;
pb = pb->next;
}
}
while (pa)
{
pc->next = pa; pa = pa->next;
}
while (pb)
{
pc->next = pb; pb = pb->next;
}
return Pc;
}
void Display(PNode* P) //显示函数
{
PNode* p = P->next;
while (p)
{
cout << p->a <<" "<< p->e<<" ";
p = p->next;
}
}
int main()
{
PNode *Pa,*Pb,*Pc;
int m,n ;
cout << "输入第一个多项式的个数:";
cin >> m;
CreatePNode(Pa, m);
cout << "输入第二个多项式的个数:";
cin >> n;
CreatePNode(Pb, n);
Pc=AddPNode(Pa, Pb);
cout << "两个多项式相加后为:";
Display(Pc);
return 0;
}
3.图书管理系统
#define MAXSIZE 100
typedef int Status;
typedef int ElemType;
typedef struct
{
int* id; //定义结构体
char* name;
int* price;
int length;
}SqList;
Status InitList(SqList& L)
{ //初始化
L.id = new int[MAXSIZE];
if (!L.id)exit(OVERFLOW);
L.length = 0;
return 1;
};
void CreateList(SqList& L, int n)
{
int i; //顺序表的创建
L.id = new int[MAXSIZE];
L.name = new char[MAXSIZE];
L.price = new int[MAXSIZE];
L.length = n;
cout << "输入书籍的ISBN,书名,定价:\n";
for (i = 0; i < n; i++)
{
cin >> L.id[i] >> L.name[i] >> L.price[i];
}
}
Status LocateElem(SqList L, ElemType e, char a)
{
int i;
for (i = 0; i < L.length; i++)
if (L.id[i] == e) return i + 1;
a = L.name[i];
} //按ID查找
void CompareList(SqList& L, int n)
{
int max, i, p;
for (i = 0; i < n; i++) //按价格排序
{
max = L.price[i];
if (max < L.price[i])
{
p = L.price[i];
max = p;
L.price[i] = max;
}
L.price[i] = max;
}
}
Status ListInsert(SqList& L, int i, ElemType e) // 插入
{
int j;
if (i < 1 || (i > L.length + 1))return 0;
if (L.length == MAXSIZE)return 0;
for (j = L.length - 1; j >= i - 1; j--)
L.id[j + 1] = L.id[j];
L.id[i - 1] = e;
++L.length;
return 1;
}
Status ListDelete(SqList& L, int i, ElemType e, char a) //删除
{
i = LocateElem(L, e, a);
int j;
if (i<1 || i>L.length)return 0;
for (j = i; j <= L.length - 1; j++)
L.id[j - 1] = L.id[j];
--L.length;
return 1;
}
Status NumList(SqList L)
{ //计数函数
return L.length;
}
void ChangeList(SqList& L, ElemType e1, ElemType e2, char n)
{
int i;
i = LocateElem(L, e1, n);
L.price[i] = e2; //修改函数
}
void Display(SqList L, int n)
{
for (int i = 0; i < n; i++)
cout << L.id[i] << " " << L.name[i] << " " << L.price[i] << " "; //显示函数
cout << endl;
}
int main()
{
SqList L;
int m,a,b,c,d,e,i=0;
char name = {};
cout << "输入图书数量:";
cin >> m;
CreateList(L, m); //创建图书系统
Display(L, m); //显示图书系统
cout << "请输入查询书籍的ID" << endl; //ID查询
cin >> m;
LocateElem(L, m, name);
cout << "输出书籍的名字" << name << endl;
cout << "请输入插入书籍的ID" << endl; //插入书籍
cin >> b;
ListInsert(L, i, b);
cout << "输出插入后的所有书籍信息" << endl;
Display(L, m + 1);
cout << "请输入删除书籍的编号" << endl; //删除书籍
cin >> c;
ListDelete(L, i, c, name);
cout << "输入删除后的所有书籍信息" << endl;
Display(L, m);
cout << "请输入需要修改的书籍ID以及修改后的ID" << endl; //修改书籍
cin >> d >> e;
ChangeList(L, d, e, name);
cout << "输出修改后的所有书籍信息" << endl;
Display(L, m);
cout << "输出排序后的所有书籍信息" << endl; //排序
CompareList(L, m);
Display(L, m);
cout << "输出所有书籍数目" << endl; //书籍总数量
cout << NumList(L);
return 0;
}










浙公网安备 33010602011771号