第二讲 线性结构(下)
2.3 队列及实现
队列是具有一定操作约束的线性表
插入和删除操作,只能在一端插入,另一端输出
Queue CreatQueue(int MaxSize)//生成长度为MaxSize的空队列
int IsFullQ(Queue Q,int MaxSize)//判断队列Q是否已满
void AddQ(Queue Q,int item)//将元素item入队
int IsEmptyQ(Queue Q)//判断队列Q是否为空
int DeleteQ(Queue Q)//将队头元素从队列中删除并返回
队列的顺序存储实现
一个一维数组,一个记录队列头元素位置的变量front以及一个记录队列尾元素位置的变量rear组成。
刚开始空:rear和front都是-1
插入一个元素:rear+1
删除一个元素:front+1
循环队列
放满了,还可以往回放!
用front和rear的差值记录满不满。但实际上flag和rear的差值有n种情况。
队列装载情况有n+1种:没有元素,一个元素,两个元素,…,n个元素。
解决方法:
(1)使用额外标记,Size或Tag(插入一个元素Tag设为1,删除一个元素Tag设为0)域。
(2)仅使用n-1个数组空间
一:入队
void AddQ(Queue PtrQ,int item)
{
if((PtrQ->rear+1)%MaxSize==PtrQ->front)
{
cout<<"队列满";
return;
}
PtrQ->rear = (PtrQ->rear + 1) % MaxSize;
PtrQ->Data[PtrQ->rear] = item;
}
二:出队
返回出队元素,front指向的是队列头元素钱一个位置。所以+1的位置就是头元素位置。
int DeleteQ(Queue PtrQ)
{
if(PtrQ->front==PtrQ->rear)
{
cout << "队列空";
return NULL;
}
else
{
PtrQ->front = (PtrQ->front + 1) % MaxSize;
return PtrQ->Data[PtrQ->front];
}
}
队列的链式存储实现
队列front是要做删除操作,只能在链表头
front在链表头,rear在链表尾
struct Node//结点结构
{
int Data;
struct Node *Next;
};
struct QNode//代表队列
{
struct Node *rear;//指向队尾结点
struct Node *front;//指向队头结点
};
typedef struct QNode *Queue;
Queue PtrQ;
二:出队
不带头结点的链式队列出队操作
int DeleteQ(Queue PtrQ)
{
struct Node *FrontCell;
int FrontElem;
if(PtrQ->front==NULL)
{
cout << "队列空";
return NULL;
}
FrontCell = PtrQ->front;
if(PtrQ->front==PtrQ->rear)//只有一个元素时,要同时修改front和rear的值,否则rear的值不变
PtrQ->front = PtrQ->rear = NULL;
else
PtrQ->front = PtrQ->front->Next;
FrontElem = FrontCell->Data;
free(FrontCell);
return FrontElem;
}
三:两个堆栈实现一个队列
- 1、可以用两个堆栈实现一个队列。队列的容量为较小堆栈n的2n+1。
- 2、已知条件:m>n,栈m和栈n初始为空。
- 3、实现步骤——天龙八部:
- 第一步:检查m>n,栈m和栈n初始化为空;
- 第二步:n个数据入栈m;
- 第三步:n个数据从栈m出栈并入栈n;
- 第四步:n+1个数据入栈m,至此已经有2n+1数据入栈;
- 第五步:栈n的数据全部出栈输出,即为队列输出;
- 第六步:栈m的数据出栈n个并入栈n,此时栈m中剩1个元素;
- 第七步:栈m中的1个元素出栈输出,即为队列输出;
- 第八步:栈n数据全部出栈输出,即为队列输出。
- 按以上步骤即可完成两个堆栈模拟一个队列。队列的容量即2n+1。
如果把两个堆栈规划为同样大小,则队列的容量为两个堆栈容量之和。处理步骤也可以简化去掉第七步。
2.4应用实例:多项式加法运算
主要思路:相同指数的项系数相加,其余部分进行拷贝。
多项式加法运算
采用不带头结点的单项链表,按照指数递减的顺序排列各项。
struct PolyNode
{
int coef;//系数
int expon;//指数
struct PolyNode *link;//指向下一个结点的指针
};
typedef struct PolyNode *Polynomial;
Polynomial P1, P2;
算法思路:
两个指针P1和P2分别指向这两个多项式第一个结点,不断循环。
P1->expon==P2->expon;//系数相加,结果不为0,则结果作为多项式对应项的系数。同时P1,P2指向下一项
P1->expon>P2->expon;//将P1的当前项存入结果多项式,使P1指向下一项
P2->expon<P2->expon;//将P2的当前项存入结果多项式,并使P2指向下一项
当某一多项式处理完之后,将零一个多项式的所有结点一次复制存到结果多项式中去。
Compare()函数对比两个数,第一个数大,返回1,第二个数大,返回-1,两个值相等,返回0;
Compare()函数
int Compare(Polynomial P1,Polynomial P2)
{
if(P1->expon>P2->coef)
return 1;
else if(P1->expon<P2->expon)
return -1;
else
return 0;
}
Attach()函数
void Attach(int c,int e,Polynomial *pRear)
{
Polynomial P;
P = (Polynomial)malloc(sizeof(struct PolyNode));
P->coef = c;
P->expon=e;
P->link = NULL;
(*pRear)->link = P;
*pRear = P;//修改pRear的值
}
求和函数
Polynomial PolyAdd(Polynomial P1,Polynomial P2)
{
Polynomial front, rear, temp;
int sum;
rear = (Polynomial)malloc(sizeof(struct PolyNode));
front = rear;//构造一个临时的空结点front作为表头
while(P1&&P2)//当两个多项式都有非零项待处理时
{
switch(Compare(P1->expon,P2->expon))
{
case 1:
Attach(P1->coef, P1->expon, &rear);
P1 = P1->link;
break;
case -1:
Attach(P2->coef, P2->expon, &rear);
P2 = P2->link;
break;
case 0:
sum = P1->coef + P2->coef;
if(sum)
Attach(sum, P1->expon, &rear);
P1 = P1->link;
P2 = P2->link;
break;
}
}
//将未处理完的另一个多项式的所有结点依次复制到结果多项式中去
for (; P1;P1=P1->link)
Attach(P1->coef, P1->expon, &rear);
for (; P2;P2=P2->coef)
Attach(P2->coef, P2->expon, &rear);
rear->link = NULL;
temp = front;
front = front->link;//令front指向结果多项式
free(temp);//释放临时表头结点
return front;
}
⭐2.5 小白专场:一元多项式的加法与乘法运算
题意理解:
设计函数分别计算两个一元多项式的乘积与和
已知两个多项式:
求解思路
- 1.多项式表示
- 2.程序框架
- 3.读多项式
- 4.加法实现
- 5.乘法实现
- 6.多项式输出
多项式表示
关键:表示关键信息
数组:编程简单,调试容易。事先需要确定数组大小。
链表:动态性小。编程复杂。
此题告诉了数目个数。
链表设计方法:
typedef struct PolyNode *Polynomial;
struct PolyNode
{
int coef;//系数
int expon;//指数
Polynomial link;//指针
};
程序框架搭建
main()
函数
int main()
{
//读入多项式1
//读入多项式2
//乘法运算并输出
//加法运算并输出
return 0;
}
需要设计的函数:
- 读一个多项式
- 两个多项式相乘
- 两个多项式相加
- 多项式输出
int main()
{
//读入多项式1
P1 = ReadPoly();
//读入多项式2
P2 = ReadPoly();
//乘法运算并输出
PP = Mult(P1, P2);
PrintPoly(PP);
//加法运算并输出
PS = Add(P1, P2);
PrintPoly(PS);
return 0;
}
怎么读多项式
先读入一个数目,然后n–,循环,读入系数指数,添加到链表里。
Rear 初值为多少?
两种处理方式
- 1.Rear初值为NULL,需要额外一步if判断处理
- 2.先申请空结点。Rear指向一个空结点。最后空结点删掉。
void Attach(int c,int e,Polynomial *pRear)
{
Polynomial P;
P = (Polynomial)malloc(sizeof(struct PolyNode));
P->coef = c;//对新结点赋值
P->expon = e;
P->link = NULL;
(*pRear)->link = P;
*pRear = P;//修改pRear的值
}
读入多项式
Polynomial ReadPoly()
{
Polynomial P, Rear,t;
int c, e, N;
cin >> N;
//链表头空结点
P = (Polynomial)malloc(sizeof(struct PolyNode));
P->link = NULL;
Rear = P;
while(N--)
{
int c;
int e;
cin >> c;
cin >> e;
//将当前项插入多项式尾部
Attach(c, e, &Rear);//Rear在函数里面值改变,参数值传递
}
//删除临时生成的头节点
t = P;
P = P->link;
free(t);
return P;
}
如何将两个多项式相加
Polynomial Add(Polynomial P1,Polynomial P2)
{
Polynomial t1,t2;
t1 = P1;
t2 = P2;
Polynomial P,Rear;
P = (Polynomial)malloc(sizeof(struct PolyNode));
P->link = NULL;
Rear = P;
while(t1&&t2)
{
if(t1->expon==t2->expon)
{
if(t1->coef+t2->coef)
Attach(t1->coef+t2->coef,t1->expon,&Rear);
t1=t1->link;
t2=t2->link;
}
else if(t1->expon>t2->expon)
{
Attach(t1->coef,t1->expon,&Rear);
t1=t1->link;
}
else
{
Attach(t2->coef,t2->expon,&Rear);
t2=t2->link;
}
}
while(t1)
{
Attach(t1->coef,t1->expon,&Rear);
t1=t1->link;
}
while(t2)
{
Attach(t2->coef,t2->expon,&Rear);
t2=t2->link;
}
//剔除空的头节点
Polynomial t;
t=P;
P=P->link;
free(t);
return P;
}
如何将两个多项式相乘
步骤1:将乘法运算转换为加法运算
将乘法运算转换为加法运算
将P1当前项(ci,ei)乘P2多项式,再加到结果多项式里。
t1 = P1;t2=P2;
P = (Polynomial)malloc(sizeof(struct PolyNode));
P->link = NULL;
Rear = P;
while(t2)
{
Attach(t1->coef * t2->coef, t1->expon * t2->expon, &Rear);
t2 = t2->link;
}
步骤2: 逐项插入
将P1当前项( c l i cl_i cli, e l i el_i eli)乘P2当前项 ( c 2 i c2_i c2i, e 2 i e2_i e2i),并插入到结果多项式中。关键是要找到插入位置。
初始结果多项式可由P1第一项乘P2获得(如上)。
Polynomial Mult(Polynomial P1,Polynomial P2)
{
//...
Polynomial P,Rear,t1,t2,t;
int c, e;
if(!P1||!P2)
return NULL;
t1 = P1;
t2 = P2;
//...
P = (Polynomial)malloc(sizeof(struct PolyNode));
P->link = NULL;
Rear = P;
while(t2)//先用P1的第一项乘以P2,得到P*
{
//....怎么构造初始多项式
Attach(t1->coef * t2->coef, t1->expon + t2->expon, &Rear);
t2 = t2->link;
}
t1 = t1->link;
while(t1)//t1的每一项乘以t2每一项
{
t2 = P2;
Rear = P;
while(t2)
{
e = t1->expon + t2->expon;
c = t1->coef * t2->coef;
//...知道了c和e,怎么找到该插入的位置去插入
while(Rear->link&&Rear->link->expon>e)
Rear = Rear->link;
if(Rear->link&&Rear->link->expon==e)
{
if(Rear->link->coef+c)//系数不等于0
Rear->link->coef += c;
else//系数等于0还要擦除
{
t = Rear->link;
Rear->link = t->link;
free(t);
}
}
else//系数小于了,准备插入了
{
t = (Polynomial)malloc(sizeof(struct PolyNode));
t->coef = c;
t->expon=e;
t->link = Rear->link;
Rear->link=t;
Rear = Rear->link;
}
t2 = t2->link;
}
t1 = t1->link;
}
//....最后结果如何处理
t2 = P;//删除掉空头节点
P = P->link;
return P;
}
如何将多项式输出
void PrintPoly(Polynomial P)
{
int flag = 0;//调整输出格式,第一项之前没有空格,后面的每一项之前都有空格
if(!P)
{
cout <<"0 0"<<endl;
return;
}
while(P)
{
if(!flag)
flag = 1;
else
cout << " ";
cout << P->coef << " " << P->expon;
P = P->link;
}
cout<<endl;
}
⭐题目及完整代码
输入格式:
输入分2行,每行分别先给出多项式非零项的个数,再以指数递降方式输入一个多项式非零项系数和指数(绝对值均为不超过1000的整数)。数字间以空格分隔。
输出格式:
输出分2行,分别以指数递降方式输出乘积多项式以及和多项式非零项的系数和指数。数字间以空格分隔,但结尾不能有多余空格。零多项式应输出0 0。
#include <iostream>
using namespace std;
typedef struct PolyNode *Polynomial;
struct PolyNode
{
int coef;//系数
int expon;//指数
Polynomial link;//指针
};
void Attach(int c,int e,Polynomial *pRear)
{
Polynomial P;
P = (Polynomial)malloc(sizeof(struct PolyNode));
P->coef = c;//对新结点赋值
P->expon = e;
P->link = NULL;
(*pRear)->link = P;
*pRear = P;//修改pRear的值
}
Polynomial ReadPoly()
{
Polynomial P, Rear,t;
int N;
cin >> N;
//链表头空结点
P = (Polynomial)malloc(sizeof(struct PolyNode));
P->link = NULL;
Rear = P;
while(N--)
{
int c;
int e;
cin >> c;
cin >> e;
//将当前项插入多项式尾部
Attach(c, e, &Rear);//Rear在函数里面值改变,参数值传递
}
//删除临时生成的头节点
t = P;
P = P->link;
free(t);
return P;
}
Polynomial Add(Polynomial P1,Polynomial P2)
{
Polynomial t1,t2;
t1 = P1;
t2 = P2;
Polynomial P,Rear;
P = (Polynomial)malloc(sizeof(struct PolyNode));
P->link = NULL;
Rear = P;
while(t1&&t2)
{
if(t1->expon==t2->expon)
{
if(t1->coef+t2->coef)
Attach(t1->coef+t2->coef,t1->expon,&Rear);
t1=t1->link;
t2=t2->link;
}
else if(t1->expon>t2->expon)
{
Attach(t1->coef,t1->expon,&Rear);
t1=t1->link;
}
else
{
Attach(t2->coef,t2->expon,&Rear);
t2=t2->link;
}
}
while(t1)
{
Attach(t1->coef,t1->expon,&Rear);
t1=t1->link;
}
while(t2)
{
Attach(t2->coef,t2->expon,&Rear);
t2=t2->link;
}
Polynomial t;
t=P;
P=P->link;
free(t);
return P;
}
Polynomial Mult(Polynomial P1,Polynomial P2)
{
//...
Polynomial P,Rear,t1,t2,t;
int c, e;
if(!P1||!P2)
return NULL;
t1 = P1;
t2 = P2;
//...
P = (Polynomial)malloc(sizeof(struct PolyNode));
P->link = NULL;
Rear = P;
while(t2)//先用P1的第一项乘以P2,得到P*
{
//....怎么构造初始多项式
Attach(t1->coef * t2->coef, t1->expon + t2->expon, &Rear);
t2 = t2->link;
}
t1 = t1->link;
while(t1)//t1的每一项乘以t2每一项
{
t2 = P2;
Rear = P;
while(t2)
{
e = t1->expon + t2->expon;
c = t1->coef * t2->coef;
//...知道了c和e,怎么找到该插入的位置去插入
while(Rear->link&&Rear->link->expon>e)
Rear = Rear->link;
if(Rear->link&&Rear->link->expon==e)
{
if(Rear->link->coef+c)//系数不等于0
Rear->link->coef += c;
else//系数等于0还要擦除
{
t = Rear->link;
Rear->link = t->link;
free(t);
}
}
else//系数小于了,准备插入了
{
t = (Polynomial)malloc(sizeof(struct PolyNode));
t->coef = c;
t->expon=e;
t->link = Rear->link;
Rear->link=t;
Rear = Rear->link;
}
t2 = t2->link;
}
t1 = t1->link;
}
//....最后结果如何处理
t2 = P;//删除掉空头节点
P = P->link;
return P;
}
void PrintPoly(Polynomial P)
{
int flag = 0;//调整输出格式,第一项之前没有空格,后面的每一项之前都有空格
if(!P)
{
cout <<"0 0"<<endl;
return;
}
while(P)
{
if(!flag)
flag = 1;
else
cout << " ";
cout << P->coef << " " << P->expon;
P = P->link;
}
cout << endl;
}
int main()
{
Polynomial P1,P2,PP,PS;
//读入多项式1
P1 = ReadPoly();
//读入多项式2
P2 = ReadPoly();
//乘法运算并输出
PP = Mult(P1, P2);
PrintPoly(PP);
//加法运算并输出
PS = Add(P1, P2);
PrintPoly(PS);
return 0;
}