第三章 栈和队列(3.5.1-3.5.2)

3.5.队列的表示和操作的实现

3.5.1队列的类型定义

1.队列的抽象数据类型定义

ADT 队列 (Queue)
Data
    同线性表。元素具有相同的类型,相邻元素具有前驱和后继关系 。
Operation
    InitQueue(*Q) :初始化操作,建立一个空队列Q。
    DestroyQueue(*Q) :若队列Q存在,则销毁它。
    ClearQueue(*Q) :将队列Q清空。
    QueueEmpty(Q) :若队列Q为空,返回true,否则返回false。
    GetHead(Q,*e) :若队列Q存在且非空,用e返回队列Q的队头元素。
    EnQueue(*Q,e) :若队列Q存在,插入新元素e到队列Q中并成为对尾元素 。
    DeQueue(*Q,*e) :删除队列Q中队头元素,并用e返回其值。
    QueueLength(Q) :返回队列Q的元素个数
endADT

2.操作

#include<iostream>
using namespace std;
#define MAXQSIZE 100  //队列可能达到的最大长度
typedef int QElemType;
typedef int SElemType;
typedef struct{
	QElemType *base;  //存储空间的基地址
	int front;        //头指针
	int rear;          //尾指针
}SqQueue;

//初始化
void InitQueue(SqQueue &Q){
	//构造一个空队列Q
	Q.base=new QElemType[MAXQSIZE];  //分配最大容量的数组空间
	if(!Q.base)
		perror("分配失败");
	Q.front=0;
	Q.rear=0;  //头指针和尾指针置为0.队列为空
}
//求队列长度
int QueueLength(SqQueue Q){
	//返回Q的元素个数,即队列的长度
	return (Q.rear-Q.front+MAXQSIZE)%MAXQSIZE;
}
//入队 在队尾插入一个新的元素
void EnQueue(SqQueue &Q,QElemType e){
	//少用一个元素 即队列空间大小为m时,有m-1个元素就认为是队满
	if((Q.rear+1)%MAXQSIZE==Q.front){
		perror("队列满了");
	}
	Q.base[Q.rear]=e;//新元素插入队尾
	Q.rear=(Q.rear+1)%MAXQSIZE;//队尾指针加1
}
//出队
void Dequeue(SqQueue &Q,QElemType &e){
	//删除Q的队头元素,用e返回其值
	if(Q.front==Q.rear)
		perror("队空");
	e=Q.base[Q.front];  //保存队头元素
	Q.front=(Q.front+1)%MAXQSIZE; //队头指针加1
}
//取队头元素
SElemType GetHead(SqQueue Q){
	//返回Q的队头元素,不修改队头指针
	if(Q.front!=Q.rear){   //非空
		return Q.base[Q.front]; //返回队头元素的值,队头指针不变
	}else{
		return -1;
	}
}
//遍历整个队列
void Traverse(SqQueue Q){
	int len=QueueLength(Q);
	for(int i=0;i<len;i++){
		printf("%d ",Q.base[i]);
	}
}
int main(){
	int item,top;
	SqQueue Q;
	InitQueue(Q);
	while(scanf("%d",&item)!=EOF){
		EnQueue(Q,item);
	}
	EnQueue(Q,1);
	Dequeue(Q,top);
	printf("%d\n",top);
	Traverse(Q);
	return 0;
}

3.5.2循环队列-队列的顺序表示和实现

队列有两种存储表示,顺序表示和链式表示

和顺序栈相类似,在队列的顺序存储结构中,除了用一组地址连续的存储单元依次存放从队列头到队列尾的元素之外,尚需附设两个指针front和rear分别指示队列头元素和队列尾元素的位置。为了在C语言中描述方便起见,在此我们约定:初始化建空队列时,令front=rear=0,每当插入新的队列尾元素时,“头指针增1”。因此,在非空队列中,头指针始终指向队列尾元素,而尾指针始终指向队列尾元素的下一个位置。如图所示

假设当前为队列分配的最大空间为6,则当队列不可再插入新的队尾元素否则会因数组越界遭致程序代码被破坏,然而此时又不宜如顺序栈那样,进行存储再分配扩大存储空间,因为队列的实际可用空间并未占满,一个较巧妙的办法是将顺序队列臆造为一个环状的空间,称之为循环队列。如图所示

img

1.初始化

//初始化 
Status InitQueue(SqQueue *Q)
{
	Q->base = (int *)malloc(MAXQSIZE);    //动态开辟长度为MAXQSIZE的数组,首元素地址赋给base指针 
	if(Q->base == NULL) return ERROR;     //开辟失败则返回ERROR 
	Q->front=Q->rear=0;                    //头下标和尾下标设置为0 
	return OK; 
}

2.求队列长度

//求长度
int QueueLength(SqQueue Q)
{
	return (Q.rear-Q.front+MAXQSIZE)%MAXQSIZE;       //头减尾再加最大长度取模 
}

3.入队

//入队
Status EnQueue(SqQueue *Q,int e)
{
	if((*Q).rear+1 == (*Q).front) return ERROR;        //“少用一个元素空间”作为队满的标志,队满返回ERROR 
	Q->base[(*Q).rear] = e;         //元素插入数组尾下标的位置 
	(*Q).rear = ((*Q).rear+1)%MAXQSIZE;           //重新设置尾下标数值,构成意识上的循环队列 
}

4.出队

//出队 
Status DeQueue(SqQueue *Q,int *e)
{
	if((*Q).rear == (*Q).front) return ERROR;   //空队 
	*e = (*Q).base[(*Q).front];          //头下标指向的位置的元素出队 
	(*Q).front = ((*Q).front+1)%MAXQSIZE;      //头下标重新设置 
}

5.获取头元素

//取循环队列队头元素
SElemType GetHead(SqQueue Q)
{
	if(Q.front != Q.rear) return Q.base[Q.front];    //非空就取出头元素 
}
posted @ 2022-02-10 16:37    阅读(45)  评论(0)    收藏  举报