数据结构P2.2:队列
队列的基本概念
- 定义:队列(queue)是只允许在
一端
进行插入
操作,而在另一端
进行删除
操作的线性表
。 - 顺序队列特点:会存在
队满
的情况,容量是不可扩展的
线性表:具有相同数据类型的有限个数据元素序列
栈:只允许在一端进行插入和删除的线性表(后进后出)
队列:只允许在一端进行插入(入队),在另一端进行删除(出队)的线性表
- 特点:
先进先出
(First In First Out,简称FIFO
)的线性表(与栈相反)。允许插入
的一端
称为队尾
,允许删除
的一端
称为队头
。 - 队列的
基本操作
–创销、增删改查:
初始化队列:构建一个空队列Q,分配内存空间
销毁操作:销毁队列并释放栈Q所占的内存空间
插入操作:进队,若队列Q未满,则将要插入的元素x加入其队尾使之成为新的队尾
删除操作:出队,若队列Q非空,删除队头元素
查找(GetPop):读队头元素
顺序队列的实现(顺序存储结构)
- 队列的本质也是一个线性表,线性表有两种存储形式,所以队列也分为队列的的顺序存储结构和队列的链式存储结构
- 顺序队列的缺点:顺序存储的不足。队列元素的出队在队头,即下标为0的位置,也就意味着,队列中的所有元素都得向前移动,以保证队列的队头位置不为空。队列的顺序存储结构还会带来
假溢出
等问题。 循环队列
:环形的队列,队列的头尾相接,属于顺序存储结构。- 循环队列特点:
1.队空
的判断条件
:head== tail
;
2.设队列的最大存储空间为MAXSIZE
,入队操作是,tail
需要加1后移一位
,赋值语句为:tail = (tail + 1) % MAXSIZE
,出队操作,head加1后移
的赋值语句:head = (head + 1) % MAXSIZE
取模运算:将无限的整数域映射到有限的整数集合
取模运算将存储空间在逻辑上变成“环形”
多以引入了循环队列
顺序队列的初始化
//顺序队列的定义
typedef struct{
ElemType data[MAXSIZE]; /*静态数组存放队列中元素*/
int head,tail; /*队头和队尾指针,队列数组的下标 */
}SqQueue;
//初始化顺序队列
void InitQueue(SqQueue &Q){
//初始化时,队头,队尾都指向data[0]
Q.head=Q.tail=0;
}
//判断是否空队列
bool EmptyQueue(SqQueue Q){
if(Q.head==Q.tail)
return true; /*队空*/
else
return false; /*队非空*/
}
//获取队列长度
int QueueLength(SqQueue Q){
return (Q.tail - Q.head + MAXSIZE) % MAXSIZE;
}
void testQueue(){
SqQueue Q; /*声明一个顺序队列结构体Q,为其分配内存空间*/
InitQueue (Q);
}
顺序队列的入队操作
//插入,新元素入队
bool EnQueue(SqQueue &Q, ElemType x){
if((Q.tail+1)%MAXSIZE==Q.head) /*队满,报错*/
return false;
Q.data[Q.tail]=x; /*将元素x插入队尾*/
Q.tail=(Q.tail+1)%MAXSIZE; /*队尾指针+1后取模*/
return true;
}
顺序队列的出队操作
//删除,队头元素出队
bool DeQueue(SqStack &S,ElemType &x){
if(Q.tail==Q.head) /*队空,报错*/
return false;
x=Q.data[Q.tail]; /*队头元素先出队,返回元素值x*/
Q.head=(Q.head+1)&MAXSIZE /*队尾指针+1后取模*/
return true;
}
顺序队列的读取队头元素
//查找:队头元素读取操作
bool GetHead(SqStack &S,ElemType &x){
if(Q.tail==Q.head) /*队空,报错*/
return false;
x=Q.data[Q.tail]; /*队头元素先出队,返回元素值x*/
return true;
}
链式队列的实现(链式存储结构)
- 定义:采用链式存储结构的队列实现方式,本质为线性表的单链表,它只能
尾进头出
而已,简称链队列。 - 链式队列的特点:容量可扩展,一般
不会队满
,除非内存不足
链式队列的初始化
//链式队列的定义
//由链式队列的各个结点的结构体定义和链式队列组成
typedef struct LinkNode{ /*链式队列的结点*/
ElemType data; /*数据域*/
struct LinkNode *next; /*指向下一个结点的指针*/
}LinkNode;
typedef struct{ /*链式队列的定义*/
LinkNode *head,*tail; /*队列的队头和队尾指针*/
}LinkQueue;
//带头结点的链式队列初始化
bool InitLinkQueue(&Q){
LinkNode *L=(LinkNode*)malloc(sizeof(LinkNode)); /*声明一个头结点指针L并分配空间*/
Q.head=Q.tail=L; /*初始化时,队头,队尾都指向头结点*/
}
//判断是否空队列(带头结点)
bool IsEmptyQueue(Q){
if(Q.tail==Q.head)
return true; /*队空*/
else
return false; /*队非空*/
}
//不带头结点的链式队列初始化
bool InitLinkQueue(&Q){
Q.head=Q.tail=NULL; /*初始化时,队头,队尾都指向NULL*/
}
//判断是否空队列(不带头结点)
bool IsEmptyQueue(Q){
if(Q.head==NULL)
return true; /*队空*/
else
return false; /*队非空*/
}
void testLinkQueue(){
LinkQueue Q;
InitLinkQueue(Q);
}
链式队列的入队操作
//插入,新元素入队(带头结点)
void EnLinkQueue(LinkQueue &Q,ElemType x){
LinkNode *s=(LinkNode*)malloc(sizeof(LinkNode)); /*声明一个新结点指针s并分配空间*/
s->data=x; /*将要插入的元素赋值给新节点的数据域*/
s->next=NULL; /*新结点s是要插入到队尾的,因此指向NULL*/
Q.tail->next=s; /*新的结点插入到当前队列的Q的队尾,相当于当前Q的队尾指针的下一个结点是s*/
Q.tail=s; /*修改队尾指针,结点s为Q的新队尾*/
}
//插入,新元素入队(不带头结点)
void EnLinkQueue(LinkQueue &Q,ElemType x){
LinkNode *s=(LinkNode*)malloc(sizeof(LinkNode)); /*声明一个新结点指针s并分配空间*/
s->data=x; /*将要插入的元素赋值给新节点的数据域*/
s->next=NULL; /*修改队头指针,新结点s是要插入到队尾的,因此指向NULL*/
//当在一个空队列中插入新元素时,这个元素为队列的第一个元素,既是队头结点也是队尾结点
if(Q.head==NULL)
Q.head=Q.tail=s;
else{
Q.tail->next=s; /*新的结点插入到当前队列的Q的队尾,相当于当前Q的队尾指针的下一个结点是s*/
Q.tail=s; /*修改队尾指针,结点s为Q的新队尾*/
}
}
链式队列的出队操作
//删除,队头元素出队(带头结点)
bool DeLinkQueue(LinkQueue &Q,ElemType &x){
if(Q.tail==Q.head) /*带头结点空队判断条件*/
return false;
LinkNode *p=Q.head->next /*删除的结点p是当前队列的头结点的下一个结点(当前队头head=Q.head->next)*/
x=p->data; /*变量x返回当前结点p(当前队头)数据*/
Q.head->next=p->next; /*修改当前Q的队头head指针为p结点的下一个结点*/
//等价于:Q.head->next=Q.head->next->next;
if(p==Q.tail) /*删除的结点p如果是队尾*/
Q.tail=Q.head; /*修改tail指针*/
free(p); /*释放结点p*/
return true;
}
//删除,队头元素出队(不带头结点)
bool DeLinkQueue(LinkQueue &Q,ElemType &x){
if (Q.head==NULL) /*不带头结点空队判断条件*/
return false;
LinkNode *p=Q.head; /*删除的结点p是当前队列的队头head指针指向的结点*/
x=p->data; /*变量x返回当前结点p(当前队头)数据*/
Q.head=p->next; /*修改当前Q的队头head指针为p结点的下一个结点*/
//等价于:Q.head=Q.head->next;
if(p==Q.tail) /*删除的结点p如果是队尾*/
Q.tail=Q.head=NULL; /*队伍已删空,head和tail都要指向NULL*/
free(p); /*释放结点p*/
return true;
}
双端队列
栈
:只允许一端插入和删除
的线性表队列
:允许一端插入、另一端删除
的线性表双端队列
:只允许从两端插入、两端删除
的线性表输入受限
的双端队列
:只允许从一端插入、两端删除
的线性表输出受限
的双端队列
:只允许从两端插入、一端删除
的线性表