数据结构基本内容(第四篇:队列)
# 队列 Queue
FIFO
操作集:长度为MaxSize的队列Q Queue,队列元素item ElementType
1. Queue CreatQueue( int MaxSize ):生成长度为MaxSize的空队列;
2. int IsFullQ( Queue Q, int MaxSize ):判断队列Q是否已满;
3. void AddQ( Queue Q, ElementType item ): 将数据元素item插入队列Q中;
4. int IsEmptyQ( Queue Q ): 判断队列Q是否为空;
5. ElementType DeleteQ( Queue Q ):将队头数据元素从队列中删除并返回。
## 队列的顺序存储实现
一个一维数组,队列头元素位置的变量front, 队列为元素位置的变量rear, 而堆栈由一个一位数组加上一个top.
队列的结构
```c
#define MaxSize <储存数据元素的最大个数>
struct QNode {
ElementType Data[ MaxSize ];
int rear;
int front;
};
typedef struct QNode *Queue;
```
循环队列
当front == rear时候, 空
rear指向这个队列实际的最后一个元素的位置,front是第一个元素的前一个. 加入一个元素的时候rear + 1, 删除一个元素的时候front + 1
使用额外标记 size或者tag
仅使用n-1个数组空间
* 创建队列
```c
Queue CreateQueue(int Maxsize)
{
Queue Q = (Queue)malloc(sizeof(struct QNode));
Q->Data = (ElementType)malloc(Maxsize * sizeof(ElementType));
Q->front = Q->rear = 0;
Q->Maxsize = Maxsize;
return Q;
}
```
* 入队列
用求余数函数,实现循环队列 例如 (5+1)%6 = 0, 放在第0位
```c
void AddQ( Queue PtrQ, ElementType item) {
if ( (PtrQ->rear+1) % MaxSize == PtrQ->front ) // front rear相邻
{
printf(“队列满”);
return;
}
PtrQ->rear = (PtrQ->rear+1)% MaxSize;
PtrQ->Data[PtrQ->rear] = item;
}
```
* 出队
```c
ElementType DeleteQ ( Queue PtrQ ) // front和rear相同
{
if ( PtrQ->front == PtrQ->rear )
{
printf(“队列空”);
return ERROR;
}
else
{
PtrQ->front = (PtrQ->front+1)% MaxSize; // front往后移一位指向第一个元素
return PtrQ->Data[PtrQ->front];
}
}
```
## 队列的链式存储实现
链表结点结构
```c
struct Node{
ElementType Data;
struct Node *Next;
};
```
链表队列结构
```c
struct QNode
{
struct Node *rear; /* 指向队尾结点 */
struct Node *front; /* 指向队头结点 */
};
typedef struct QNode *Queue;
Queue PtrQ; // 包含front和rear的这个结构的指针PtrQ
```
* 出队
```c
ElementType DeleteQ ( Queue PtrQ )
{
struct Node *FrontCell;
ElementType FrontElem;
if ( PtrQ->front == NULL)
{
printf(“队列空”);
return ERROR;
}
FrontCell = PtrQ->front; // 找到队列的头个元素
if ( PtrQ->front == PtrQ->rear) /* 若队列只有一个元素 */
PtrQ->front = PtrQ->rear = NULL; /* 删除后队列置为空 */
else
PtrQ->front = PtrQ->front->Next;
FrontElem = FrontCell->Data;
free( FrontCell ); /* 释放被删除结点空间 */
return FrontElem;
}
```
## 应用: 多项式加法运算
算法思路:
两个指针P1和P2分别指向这两个多项式第一个结点,不断循环:
* P1->expon==P2->expon相同: 系数相加,若结果不为0,则作为结果多项式对应项
的系数。同时,P1和P2都分别指向下一项;
* P1->expon>P2->expon 这时p1大: 将P1的当前项存入结果多项式,并使P1指向下一项;
* P1->expon<P2->expon 这时p2大: 将P2的当前项存入结果多项式,并使P2指向下一项;
* 当某一多项式处理完时,将另一个多项式的所有结点依次复制到结果多项式中去。
```c
struct PolyNode //结构类型
{
int coef; // 系数
int expon; // 指数
struct PolyNode *link; // 指向下一个节点的指针
}
typedef struct PolyNode *Polynomial;
Polynomial P1, P2; // p1 p2都是这种结构的指针
```
实现
```c
Polynomial PolyAdd (Polynomial P1, Polynomial P2)
{
Polynomial front, rear, temp; // 结构多项式的头 尾.
int sum;
// 临时空结点点作为结果多项式的表头, front rear都指向这个空间点
rear = (Polynomial) malloc(sizeof(struct PolyNode));
front = rear; /* 由front 记录结果多项式链表头结点 */
while ( P1 && P2 ) /* 当两个多项式都有非零项(都不空)待处理时 */
switch ( Compare(P1->expon, P2->expon) ) // 比较两个指数
{
case 1: // p1大
// 系数和指素接到rear的后面
Attach( P1->coef, P1->expon, &rear);
P1 = P1->link;
break;
case -1: // p2大
Attach(P2->coef, P2->expon, &rear);
P2 = P2->link;
break;
case 0: //p1 = p2
sum = P1->coef + P2->coef;
// 判断sum不等于0
if ( sum ) Attach(sum, P1->expon, &rear);
P1 = P1->link;
P2 = P2->link;
break;
}
/* 将未处理完的另一个多项式的所有节点依次复制到结果多项式中去 */
// p1不空
for ( ; P1; P1 = P1->link )
Attach(P1->coef, P1->expon, &rear);
// p2 不空
for ( ; P2; P2 = P2->link )
Attach(P2->coef, P2->expon, &rear);
// rear 指向结果多项式的最后一项,现在结束了,把link设为NULL
rear->link = NULL;
// 释放临时结点
temp = front;
front = front->link; /*令front指向结果多项式第一个非零项 */
free(temp); /* 释放临时空表头结点 */
return front;
}
```
其中attach函数
```c
//传入系数和指数,以及最后一个结点的指针位置(指针的指针),于在本函数中需要改变当前结果表达式尾项指针的值,所以函数传递进来的是结点指针的地址,*pRear指向尾项
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;
/* 将P指向的新结点插入到当前结果表达式尾项的后面 */
(*pRear)->link = P;
*pRear = P; /* 修改pRear值 */
}
```