队列(循环队列,链队)的基本操作

文章目录

  • 一 . 队列的抽象数据类型定义
  • 二 . 循环队列
    • 假溢出问题
    • 1 . 队列的顺序存储结构表示
    • 2 . 初始化
    • 3 . 求队列长度
    • 4 . 入队
    • 5 . 出队
    • 6 . 取队头元素
  • 三 . 链队
    • 1 . 队列的链式存储结构表示
    • 2 . 初始化
    • 3 . 入队
    • 4 . 出队
    • 5 . 取出队头元素
    • 6 . 循环队列基本操作的实现
    • 7 . 链队基本操作的实现

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

只能在队尾添加队头删除的顺序表
队列(循环队列,链队)的基本操作_第1张图片

ADT Queue
{
	Data
		同线性表。元素具有相同的类型,相邻元素具有前驱和后继关系。
	Operation
		InitQueue(&Q)		队列初始化
		DestroyQueue(&Q)	若队列存在,销毁队列
		ClearQueue(&Q)		将队列清空
		QueueEmpty(Q)		若队列为空返回true,否则返回false
		GetHead(Q,&e)		若队列存在,则用e返回队头
		EnQueue(&Q,e)		入队,插入新元素e到队尾
		DeQueue(&Q,*e)		出队,用e返回其值
		QueueLength(Q)		返回队列的个数		
}ADT Queue

二 . 循环队列

队列的顺序存储结构表示称为循环队列

假溢出问题

队列的简单的顺序存储方式会造成假溢出问题,如下图:
队列(循环队列,链队)的基本操作_第2张图片

明明还有存储空间,算法却得到已经满了的结果。
为解决假溢出,可以使用循环队列的方式:把队列(数组)设想成头尾相连的循环表,使得数组前部由于删除操作而导致的无用空间尽可能得到重复利用,这样的队列称为循环队列
通过“模”运算,Q.rear = (Q.rear+1)%n,不会出现“假溢出”问题
如下图:
队列(循环队列,链队)的基本操作_第3张图片
由此可见,对于循环队列不能以头尾指针的值是否相同来判别队列空间是“满”还是“空”在这种情况下区别队满还是队空的条件如下:

  1. 少用一个空间元素
  2. 另设一个标志位区别队是“满”还是“空”。

队空的条件: Q.front == Q.rear
队满的条件:(Q.rear +1)%MAXQSIZE == Q.front

1 . 队列的顺序存储结构表示

#define MAXQSIZE 10	//队列可能达到的最大长度
    typedef struct {
	QElemType *base;//存储空间的基地址
	int front;		//头指针
	int rear;		//尾指针
}SqQueue;

2 . 初始化

循环队列初始化操作就是动态分配一个预定义大小为MAXQSIZE的数组空间。

【算法步骤】

  • 为队列分配一个最大容量为MAXQSIZE的数组空间,base指向数组空间的首地址。
  • 头和尾指针置为零,表示队列为空。

【算法描述】

Status InitQueue(SqQueue &Q) {			//构造一个空队列
	Q.base = new QElemType[MAXQSIZE];	//为队列分配一个最大容量为MAXQSIZE的数组空间
	if (!Q.base) exit(-2);				//存储分配失败
	Q.front = Q.rear = 0;				//头尾指针置为零,队列为空
	return OK;
}

3 . 求队列长度

直接返回直接返回(Q.rear-Q.front+MAXQSIZE)% MAXQSIZE

int QueueLength(SqQueue Q){//返回Q的元素个数,即队列长度
	return (Q.rear-Q.front+MAXQSIZE)%MAXQSIZE;
}

4 . 入队

在队尾新插入一个元素
队列(循环队列,链队)的基本操作_第4张图片
【算法步骤】

  • 判断队列是否已满,若满则返回ERROR
  • 将新元素插入到队尾
  • 队尾指针加1

【算法描述】

Status EnQueue(SqQueue &Q,QElemType e){//插入元素e为Q的新的队尾元素
	if((Q.rear+1)%MAXQSIZE==Q.front)	//尾指针在循环意义上加1后等于头指针,表明队满
		return ERROER;
	Q.base[Q.rear]=e;					//新元素插入队尾
	Q.rear=(Q.rear+1)%MAXQSIZE;			//队尾指针加1
	return OK; 
}

5 . 出队

队列(循环队列,链队)的基本操作_第5张图片
【算法步骤】

  • 判断队列是否为空,若为空,返回ERROR
  • 保存队头元素
  • 队头指针加1
    【算法描述】
Status DeQueue(SqQueue &Q,QElemType &e){//删除Q的队头元素
	if(Q.front==Q.rear)	return ERROR;	//队空
	e=Q.base[Q.front];					//保存队头元素
	Q.front=(Q.front+1)%MAXQSIZE;		//队头指针加1
	return OK;
}

6 . 取队头元素

判断队列是否为空,不为空返回队头元素

【算法描述】

SElemType GetHead(SqQueue Q){	//返回Q的队头元素,不修改队头指针
	if(Q.front!=Q.rear)		 	//队列非空
		return Q.base[Q.front];	//返回队头元素的值,队头指针不变
}

三 . 链队

采用链式存储结构实现的队列,称为链队

1 . 队列的链式存储结构表示

typedef struct QNode {
	QelemType data;
	struct QNode *next;
}QNode,*QueuePtr;
typedef struct {
	QueuePtr fornt;		//队头指针
	QueuePrt rear;		//队尾指针
}LinkQueue;

2 . 初始化

链队的初始化操作就是构造一个只有头结点的空队。

【算法步骤】

  • 生成新的结点作为头结点,队头和队尾指针指向此节点。
  • 头结点的指针域置空

【算法描述】

Status IntitQueue(LinkQueue &Q){	//构造一个空队列Q
	Q.front = Q.rear = new QNode;	//生成新的结点作为头结点,队头和队尾指针指向此结点
	Q.front->next = NULL;			//头结点指针域置空
	return OK;
}

3 . 入队

【算法步骤】

  • 为入队元素分配节点空间,用指针p指向。
  • 将新结点数据域置为e。
  • 将新结点插入到对尾
  • 修改队尾指针为p

【算法描述】

Status EnQueue(LinkQueue &Q, QElemType e){//插入元素e为Q的新的队尾元素
	p = new QNode;						  //为入队元素分配结点空间,用指针p指向
	p->data = e;						  //将新结点数据域置为e
	p->next = NULL; Q.rear->next = p;	  //将新结点插入到队尾
	Q.rear = p;							  //修改队尾指针
	return OK;
}

4 . 出队

需要判断队是否为空,出队后需要把空间释放。

【算法步骤】

  • 判断队是否为空,若空则返回ERROR。
  • 临时保存队头元素的空间,以备释放。
  • 修改头结点的指针域,指向下一个结点。
  • 判断出队元素是否为最后一个元素,若是,则将队尾指针重新赋值,指向头结点。
  • 释放原队头元素的空间。

【算法描述】

Status DeQueue(LinkQueue &Q, QElemType &e) {//删除Q的队头元素,用e返回其值
	if (Q.front == Q.rear) return ERROR;	//若队列空,则返回ERROR
	p = Q.front->next;						//p指向队头元素
	e = p->data;							//e保存队头元素的值
	Q.front->next = p->next;				//修改头结点的指针域
	if (Q.rear == p)	Q.rear = Q.front;	//最后一个元素被删,队尾指针指向头结点
	delete p;								//释放原队头元素的空间
	return OK;
}

5 . 取出队头元素

判断是否为空,非空时返回队头元素,不改变指针

【算法描述】

SElemType GetHead(LinkQueue Q) {	//返回Q的队头元素,不修改队头指针
	if (Q.front != Q.rear)			//队列非空
		return Q.front->next->data; //返回队头元素的值,队头指针不变。
}

6 . 循环队列基本操作的实现

#include
using namespace std;
#define MAXQSIZE 10
typedef struct SqQueue {
	int *base;
	int front;
	int rear;
}SqQueue;
//初始化
void InitQueue(SqQueue &Q) {
	Q.base = new int[MAXQSIZE];
	if (!Q.base) {
		cout << "初始化失败" << endl;
		exit(-2);
	}
	else {
		Q.front = Q.rear = 0;
		cout << "初始化成功" << endl;
	}
}
//入队
void EnQueue(SqQueue &Q, int e)
{
	if ((Q.rear + 1) % MAXQSIZE == Q.front) {
		cout << "队满,入队失败!" << endl;
	}
	else {
		Q.base[Q.rear] = e;
		Q.rear = (Q.rear+ 1) % MAXQSIZE;
	}
}
//出队
void DeQueue(SqQueue &Q) {
	if (Q.front == Q.rear) {
		cout << "队空,无法出队!" << endl;
	}
	else {
		cout << "出队元素是:" << Q.base[Q.front] << endl;
		Q.front = (Q.front + 1) % MAXQSIZE;
		cout << "入队成功" << endl;
	}
}
//取出队头元素
void  GetHead(SqQueue Q)
{
	if (Q.front != Q.rear)
		cout << Q.base[Q.front] << endl;
}
int main() {
	SqQueue Q;
	int e;
	cout << "初始化" << endl;
	InitQueue(Q);
	cout << "1 . 入队" << endl;
	for (int i = 0; i < 9; i++) {
		cin >> e;
		EnQueue(Q, e);
	}
	cout << "2 . 出队" << endl;
	DeQueue(Q); 
		cout << "取出队头元素" << endl;
	GetHead(Q);
	cout << "剩余元素出队" << endl;
	for (int i = 0; i < 8; i++) {
		DeQueue(Q);
	}
	cout << " 出队" << endl;
	DeQueue(Q);
	return 0;
}

7 . 链队基本操作的实现

#include
using namespace std;
typedef  int  QElemType;
typedef struct QNode {
	QElemType data;
	struct QNode *next;
}QNode,*QueuePtr;
typedef struct {
	QueuePtr front;
	QueuePtr rear;
}LinkQueue;
//初始化
void  IntitQueue(LinkQueue &Q){
	Q.front = Q.rear = new QNode;
	Q.front->next = NULL;
	cout << "初始化成功" << endl;
}
//入队
void EnQueue(LinkQueue &Q, QElemType e) {
	struct QNode *p;
	p = new QNode;
	p->data = e;
	p->next = NULL; Q.rear->next = p;
	Q.rear = p;
}
//出队
void DeQueue(LinkQueue &Q, QElemType &e) {
	if (Q.front == Q.rear) {
		cout << "队空" << endl;
		return;
	}
	struct QNode *p;
	p = Q.front->next;
	e = p->data;
	Q.front->next = p->next;
	if (Q.rear == p)	Q.rear = Q.front;
	delete p;
	cout << e << " ";
}
//取出队头元素
void  GetHead(LinkQueue Q) {
	if (Q.front != Q.rear)
		cout << Q.front->next->data << endl;
}
int main() {
	LinkQueue Q;
	int e;
	cout << "初始化队列" << endl;
	IntitQueue(Q);
	cout << "1 . 入队" << endl;
	for (int i = 0; i < 10; i++) {
		cin >> e;
		EnQueue(Q, e);
	}
	cout << "2 .出队" << endl;
	DeQueue(Q, e);
	cout << endl;
	cout << "3 . 取出队头元素" << endl;
	GetHead(Q);
	cout << "取出剩余元素" << endl;
	for (int i = 0; i < 9; i++) {
		DeQueue(Q, e);
	}
	cout << endl;
	cout << "出队" << endl;
	DeQueue(Q, e);
	return 0;
}

你可能感兴趣的:(笔记,数据结构)