数据结构之队列

导读:本篇文章讲解 数据结构之队列,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

队列的定义:

只允许在一端进行插入(入队),在另一端删除(出队)的线性表。

举例:

在队末进行入队,在对头进行出队。
在这里插入图片描述

队列的特点:

先进入队列的元素先出队(先进先出)

空队列:

在这里插入图片描述对头和队尾元素:
在这里插入图片描述

队列的基本操作:

定义队列:

#define Maxsize 10
typedef struct
{
	ElemType data[Maxsize];//用静态数组存放队列元素
	int front, rear;//队头和队尾指针
}SqQueue;

在这里插入图片描述

InitQueue(&Q):初始化队列,构造一个空队列Q。

void InitQueue(SqQueue&Q)
{
	Q.rear = Q.front = 0;//初始化时,队头,队尾指针指向0
}

DestoryQueue(&Q):销毁队列,销毁并释放队列Q所占用的内存空间。

EnQuquq(&Q,x):入队,若队列Q未满,将x加入,使之成为新的队尾。

bool EnQueue(SqQueue& Q, ElemType x)
{
	if (队列已满)//判断队列是否存满
		return false;
	Q.data[Q.rear] = x;//将x插入队尾
	Q.rear = (Q.rear + 1)%Maxsize;//队尾指针加1取模
	return true;
}

在这里插入图片描述那么队列已满的条件是不是rear==Maxsize?

那当然不是!

举例:

在这里插入图片描述
如果是上述这种情况,虽然此时rear==Maxsize,但是队列中的前几个元素已经出队列了,此时的队列并没有存满。

正确的判断条件是:

方案一:

(Q.rear + 1)%Maxsize//(9+1)%10=0使rear指向0

在这里插入图片描述相当于将线性存储在逻辑结构上变成了环状:

在这里插入图片描述队列已满的条件:

队尾指针的再下一个位置是对头,即(Q.rear+1)%Maxsize==Q.front

注意:这里无法将所有的空间都使用,因为如果当rear和front指向同一个位置,那么这不就恰好成为了空队列的条件吗?因此我们必须牺牲一个存储单元。

方案二:

在这里插入图片描述

方案三:

在这里插入图片描述

当rear指向的是队尾元素时的基本操作:

在这里插入图片描述

在这里插入图片描述

队列元素个数:

(rear+Maxsize-front)%Maxsize

DeQueue(&Q,&x):出队,若队列Q非空,删除对头元素,并用x返回。

bool DeQueue(SqQueue& Q, ElemType& x)
{
	if (Q.rear == Q.front)//空栈则报错
	{
		return false;
	}
	x = Q > data[Q.front];
	Q.front = (Q > front + 1) % Maxsize;//从队头元素开始,使元素依次出队
	return true;
}

GetHead(Q,&x):读对头元素,若队列Q非空,则将对头元素赋值给x。

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

QueueEmpty(Q):判队列空,若队列Q为空返回true,否则返回false.

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

队列的链式实现:

typedef struct LinkNode//链式队列结点
{
	ElemType data;
	struct LinkNode* next;
}LinkNode;
typedef struct//链式队列
{
	LinkNode* front, * rear;//队列的对头和队尾指针
}LinkNode;

链队列:链式存储实现的队列
在这里插入图片描述

链式队列的初始化:

//带头结点
void InitQueue(LinkQueue& Q)
{
	Q.front = Q.rear = (LinkNode*)malloc(sizeof(LinkNode));//使指针都指向头结点
	Q.front->next = NULL;
}
//不带头结点
void InitQueue(LinkQueue& Q)
{
	Q.front = NULL;
	Q.rear = NULL;
}

链式队列的判空操作:

//带头结点
bool IsEmpty(LinkQueue Q)
{
	if (Q.front == Q > rear)
		return true;
	else
		return false;
}
//不带头结点
bool IsEmpty(LinkQueue Q)
{
	if (Q.front == NULL)
		return true;
	else
		return false;
}

链式队列的入队:

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

链式队列的出队操作:

//带头结点
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;//修改rear指针
	}
	free(p);
	return true;
}
//不带头结点
bool DeQueue(LinkQueue& Q, ElemType& x)
{
	if (Q.front == NULL)//空队列
		return false;
	LinkNode* p = Q.front;//p指向此次出队列的节点
	x = p->data;//用变量x返回队头元素
	Q.front = p->next;//修改front指针
	if (Q.rear == p)//最后一个节点出队
	{
		Q.front = NULL;
		Q.rear = NULL;
	}
	free(p);
	return true;
}

上面我们提到如果是顺序存储,那么当预分配的空间耗尽时,就代表此时队列已满,而对于链式存储来说,一般情况下,队列是不会满的,除非内存不足。

双端队列:

前面我们学习过,栈是只允许从一端插入和删除的线性表,队列是只允许从一端插入,另一端删除的线性表,而双端队列是只允许从两端插入,两端删除的线性表。
在这里插入图片描述

判断输出序列的合法性:

若数据元素输入序列为1,2,3,4,则那些输出序列是合法的?那些是非法的?

在这里插入图片描述对数据元素1,2,3,4的输出共有24种:

在栈中:在这里插入图片描述
红色字体代表非法输出,绿色字体代表合法输出!

举例分析:

当为1,2,3,4的顺序时:

数据1,输入再输出,数据2输入再输出,直到数据四完成输出。

当为2,4,1,3的顺序时:

数据2作为第一个元素输出,那么,输入1,2,输出2,接下来要输出数据4,那么,输入3,4,输出4,此时栈中剩余1,3,1是在3之前输入的,要想输出1,就必须先输出3,因此无法完成这组的输出。

其他结果也可按此进行分析。

注:在栈中合法的输出序列,在双端序列中一定合法。

对于计算合法输出序列,我们可以使用卡特兰数:

在这里插入图片描述在输入受限的双端队列中:
在这里插入图片描述红色字体代表非法输出,绿色字体代表合法输出!

在输出受限的双端队列中:
在这里插入图片描述
红色字体代表非法输出,绿色字体代表合法输出!

输出/输入受限的双端队列中判断序列的输出是合法还是非法,和在栈中判断方法基本相同,只需要注意栈只能在一端,而输出/输入受限的双端队列虽然可以在两端,但会有不同的限制!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/81454.html

(0)
小半的头像小半

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!