数据结构——队列


前言

队列和栈的定义和操作实在是太相似了,直接把栈那一篇的内容复制过来做个修改,学习的重点应该在后面的循环队列。


一、定义

队列(Queue)是一种只允许在一端进行操作的线性表,不仅如此,队列还是一种先进先出(first in first off,FIFO)的数据结构。
队列可以顺序存储也可以链式存储,顺序队和顺序表的定义几乎没有区别,只是在处理数据时加了一条先进先出的限制,链队也是同样的道理。
在这里插入图片描述

二、顺序队的基本操作

1.定义

#define MaxSize 10	//定义队列中元素的最大个数
typedef struct
{	
	ElemType data[MaxSize];	//静态数组存放栈中元素
	int front, rear;		//队头指针和队尾指针
}SqQueue;

注意:定义栈的时候我们只定义了一个栈顶指针,而定义队列时我们定义了两个,一个指向队头一个指向队尾,这也很好理解,栈中的数据只能在栈顶进行插入和删除等操作,但队列需要在队头出队,队尾入队,所以需要两个指针。

2.初始化

bool InitStack(SqQueue& S)
{	
	Q.rear = 0;
	Q.front = 0;
}

注意:队尾指针指向队尾元素的下一个位置(也就是接下来要插入元素的位置)。

3.入队

bool Push(SqQueue& Q, ElemType x)
{	
	if ((Q.rear + 1) % MaxSize == Q.front)	//队列满,报错
		return false;
	Q.data[Q.rear] = x;	//新元素入队
	Q.rear = (Q.rear + 1) % MaxSize;	//队尾指针加一取模
	return true;
}

注意
①取模运算a%b,如果a<=b的话,结果其实还是a自己;如果a>b的话结果就是a%b后的余数,且不论a与b是什么关系,最后的结果都小于b。这种取模运算保证了队尾指针始终在MaxSize范围内循环变化,也正因此实现了队列在逻辑上的“环状”
②由于此时队列已经成环(循环队列),所以在判断队满的时候需要牺牲一个空间(比如有10个空间,存满9个元素时就认为队满),这样做是为了区别与队空(Q.rear == Q.front)的判断。
③循环队列中元素的个数是(rear+MaxSize-front)%MaxSize(记住即可)在这里插入图片描述在这里插入图片描述

此外,如果不想像上述这样,通过牺牲一个空间的方式来区别队空和队满,也可以咋定义队列的时候在结构体中加上一个size变量,用来表示队列当前有几个元素。

4.出队

bool Pop(SqQueue& Q, ElemType& x)
{	
	if (Q.rear == Q.front)	//队空,报错
		return false;
	x = Q.data[Q.front];	//元素出队
	Q.front = (Q.front + 1) % MaxSize	//队头指针成环性加一
	return true;
}

5.读取队头元素

bool GetHead(SqQueue S, ElemType& x)
{	
	if (Q.rear == Q.front)	//队空,报错
		return false;
	x = Q.data[Q.front];	//读出元素
	return true;
}

6.判空

bool QueueEmpty(SqQueue Q)
{
	if (Q.rear == Q.front)	//队空
		return true;
	else
		return false;
}

三、链式队的基本操作

1.定义

typedef strunct LinkNode
{//队列中结点的定义
	ElemType data;
	struct LinkNode* next;
}LinkNode;

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

注意:因为在定义上,链队和单链表没有什么区别,链队列只是在单链表的使用上加了一些限制(阉割版),所以链队的实现也有带头结点和不带头结点两种方式。

2.初始化

bool InitQueue(LinkQueue& Q)
{//带头结点的链队
	Q.front = Q.rear = new LinkNode;	//创建一个头结点,并使头尾指针都指向它
	Q.front->next = NULL;	//让这个头结点指向NULL
	return true;
}

在这里插入图片描述

3.入队

bool Push(LinkQueue& Q, ElemType x)
{	
	LinkNode* s = new LinkNode;	//创建一个新的结点
	s->data = x;
	s->next = NULL;		
	Q.rear->next = s;	//让队尾指针当前指向的结点(刚开始是头结点)的next指向新结点
	Q.rear = s;		//让队尾指针指向新结点
	return true; 
}

在这里插入图片描述
注意:队列的元素入队操作类似于单链表的尾插法,也就是越晚插入的元素越远离头结点

4.出队

bool Pop(LinkQueue Q, ElemType &x)
{	
	if (Q.)	//此时队空,无法出队
		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;		//释放出队结点的内存
	p = NULL;
	return true; 
}

在这里插入图片描述

注意:队列的出队操作每次都是出队最靠近头结点的那一个元素

5.读出队头元素

bool GetTop(LinkQueue Q, ElemType& x)
{	
	if (Q.rear == Q.front)	//队空,报错
		return false;
	x = Q.rear->data;	//读出元素
	return true;
}

6.判空

bool Empty(LinkQueue Q)
{
	if(Q.front == Q.rear)	//也可以判断头结点的next是否指向NULL
		return true;
	else
		return false;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值