队列的基本概念和相关操作的实现

本文介绍了队列的基本概念,包括队头、队尾、空队列的定义,以及队列的先进先出特点。文章详细阐述了队列已满和空队列的条件,并讨论了循环队列的概念。此外,还探讨了队列的顺序实现和链式实现,包括入队、出队操作,以及如何避免空间浪费和正确判断队列状态的两种方法。

1.基本概念:

队列(Queue):队列和栈一样,也是一种操作受限的线性表,它只允许在一端进行插入,而在另一端进行删除。

重要术语:队头、队尾、空队列

队头:允许删除的一端

队尾:允许插入的一端

队空条件:Q.front==Q.rear

队列已满的条件:队尾指针的下一个位置是队头,即(Q.rear+1)%MaxSize==Q.front,这样会牺牲掉一个存储单元

循环队列:用模运算将存储空间在逻辑上变为环状

提问:为什么队列已满的条件不是Q.rear==MAXSIZE呢?

答:如果通过队头指针释放了一些数据元素,那么队头指针会向后移动,而队尾指针不变,这时,虽然满足Q.rear==MAXSIZE,但队列未满

队列的特点:先进先出(FIFO  --  first in first out)

我们规定让队头指针指向队头元素,让队尾指针指向队尾元素的后一个位置(即接下来要插入数据元素的位置)

2.队列的顺序实现:

(1)定义一个顺序队列:

typedef struct {
	int a;
	double b;
}*ElemType;

typedef struct {
	ElemType data[MAXSIZE];   //用静态数组存放队列元素
	int front, rear;          //队头指针和队尾指针
}SqQueue;          //Sq - sequence 顺序

(2)队列的初始化和判空:

void InitQueue(SqQueue& Q) {  //初始时,根据规定,队头指针和队尾指针都指向0位置
	Q.front = Q.rear = 0;
}

bool Empty(SqQueue Q) {
	if (Q.front == Q.rear)
		return true;
	return false;
}

(3)入队:


bool EnQueue(SqQueue& Q, ElemType e) {
	if ((Q.rear + 1) % MAXSIZE == Q.front)
		return false;               //队列已满则报错
	Q.data[Q.rear] = e;             //将元素e插入队尾
	Q.rear = (Q.rear + 1) % MAXSIZE;       //使队尾指针后移一位
	return true;
}

(4)出队:

bool DeQueue(SqQueue& Q, ElemType& x) {
	if (Q.front == Q.rear)           //空队列
		return false;
	x = Q.data[Q.front];            //将队头元素赋给x
	Q.front = (Q.front + 1) % MAXSIZE;    //队头指针后移一位
	return true;
}

(5)获取队头元素:

bool GetHead(SqQueue& Q, ElemType& x) {   //获取队头元素
	if (Q.front == Q.rear)
		return false;             //队空则报错
	x = Q.data[Q.front];          //将队头元素赋给x
	return true;
}

附:

注意:这样的实现方式会造成一个ElemType空间的浪费,但是要想不浪费这个空间,又要达到能够正确给出队列已满和空队列的条件,我们应该如何做到呢?

这个问题的解题思路一共有两种:

a.在原来的队列定义中增加一个int 类型的size变量并赋初值为0,用来记录链表的长度;

每插入一个元素,就让size++;每删除一个元素,就让size--;

这样,我们就可以根据size的大小来判断链表是否已满。此时队列已满的条件是size==MAXSIZE,队列为空的条件是size==0。

定义如下:

typedef struct {
	ElemType data[MAXSIZE];
	int front, rear;          //队头指针和队尾指针
	int size;                 //用来记录队列的长度
}SqQueue;

void InitQueue(SqQueue& Q) {
	Q.front = Q.rear = 0;
	Q.size = 0;
}

b.在原来的队列定义中增加一个int类型的tag变量,用来记录最近的一次操作是插入元素还是删除元素;

规定若最近的一次操作是插入,则tag=1;若最近的一次操作是删除,则tag=0;

由于只有插入操作才能使得队列变满,而只有删除操作才能使队列变空;

这样,我们就可以根据tag以及rear和front指针来判断队列是否已满:若rear和front相等,且tag==1,即最近的一次操作是插入,那么队列已满;反之,若tag==0,那么最近的一次操作是删除,那么队列为空;

即此时队列已满的条件是:Q.rear==Q.front&&tag==1 

此时队列为空的条件是:Q.rear==Q.front&&tag==0

定义如下:

typedef struct {
	ElemType data[MAXSIZE];
	int front, rear;          //队头指针和队尾指针
	int tag;               //用来记录最近的一次操作是插入还是删除
}SqQueue;

3.队列的链式实现:

(1)链式队列的定义:

typedef struct LinkNode {     //链式队列的结点
	ElemType data;
	struct LinkNode* next;
}LinkNode;

typedef struct {              //链式队列
	LinkNode* front, * rear;    //队头指针和队尾指针
}LinkQueue;

(2)链式队列的初始化:

//带头结点
void InitQueue(LinkQueue& Q) {
	Q.front = Q.rear = new LinkNode;      //开辟一个动态空间用于存放头结点
	Q.front->next = NULL;                 //头结点的下一个结点为空
}

//不带头结点
void InitQueue(LinkQueue& Q){
   Q.front = Q.rear = NULL;     //将队头指针和队尾指针都置空
}

(3)链式队列的判空:

bool Empty(LinkQueue Q) {
	if (Q.front == Q.rear)          //队列为空的条件,也可改为Q.front->next==NULL
		return true;
	return false;
}

(4)队尾元素的入队:

//带头结点
void  EnQueue(LinkQueue& Q, ElemType e) {
	LinkNode* s = new LinkNode;
	s->data = e;         //将数据元素e放入结点s中
	s->next = NULL;      //因为插入的结点e是最后一个结点,因此其下一个结点为NULL
	Q.rear->next = s;    //新结点插入Q.rear之后
	Q.rear = s;          //队尾指针指向最后一个结点
}

//不带头结点
void EnQueue(LinkQueue& Q, ElemType e) {
	LinkNode* s = new LinkNode;
	s->data = e;
	s->next = NULL; 
	if (Q.front == NULL) {     //在空队列中插入第一个元素
		Q.front = s;          
		Q.rear = s;            //让队头指针和队尾指针都指向第一个结点
	}
	else {
		Q.rear->next = s;      //新结点插入到rear结点之后
		Q.rear = s;            //修改队尾指针
	} 
}

(5)队头元素出队:

//带头结点
bool DeQueue(LinkQueue& Q, ElemType& x) {
	if (Q.front == Q.rear)       //队列为空,报错
		return false;
	LinkNode* p = Q.front->next;
	x = p->data;                 //用变量x返回队头元素
	Q.front->next = p->next;     //修改头结点的next指针
	if (Q.rear == p)             //最后一个元素出队
		Q.rear = Q.front;
	delete p;        //释放结点空间
	return true; 
}

//不带头结点
bool DeQueue(LinkQueue& Q, ElemType& x) {
	if (Q.front == NULL)
		return false;            //空队列
	LinkNode* p = Q.front;       //p指向第一个结点
	x = p->data;
	Q.rear = p->next;
	if (Q.rear == p)        //最后一个元素出队
		Q.front = Q.rear = NULL;
	delete p;
	return true;
}

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值