概念
队列也是操作受限的线性表
队尾:允许插入的一端
队头:允许删除的一端
队列的特点:First In First Out(先进先出)(FIFO)
基本操作:
初始化、销毁、入队、出队、读队头元素、判空
用顺序存储实现队列
代码:用静态数组存放队列元素
#define MaxSize 10
typedef struct
{
ElemType data[MaxSize];
int front;//定义队头指针
int rear;//定义队尾指针
}SqQueue
定义一个函数声明队列
void testQueue()
{
SqQueue Q;//声明一个队列
}
队头指针指向队头元素
队尾指针指向队尾元素的后一个元素
初始化队列
void InitQueue(SqQueue Q)
{
Q.rear = Q.head = 0;
}
判断是否为空
bool QueueEmpty(SqQueue Q)
{
if(Q.rear == Q.head)
return true;
else
return false;
}
入队
入队要先判队满
bool EnQueue(SqQueue &Q,ElemType x)
{
if(队列满)
return false;
Q.data[Q.rear]=x;//将数据放到队尾
Q.rear=(Q.rear+1)%MaxSize;//队尾指针后移一位 即+1取模
return true;
}
队尾指针后一移位不是简单的加1,是加1取模
循环队列
将线性的存储空间,在逻辑上变成了环状。
判断队列已满的条件
队尾指针的再下一个位置是队头
(Q.rear+1)%MaxSize==Q.front
出队(删)
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;
}
求队列的元素个数
n=(rear+MaxSize-front)%MaxSize
判断队满和队空的三种方式
第一种
队尾指针的再下一个位置是队头->队满
(Q.rear+1)%MaxSize==Q.front
第二种
在队列的结构中定义一个变量size,来记录队列中此时有多少个元素。
插入成功size++,删除成功size–
#define MaxSize 10
typedef struct
{
ElemType data[MaxSize];
int front,rear;
int size;//队列当前长度
}SqQueue;
第三种
#define MaxSize 10
typedef struct
{
ElemType data[MaxSize];
int front,rear;
int tag;
}SqQueue;
tag=0;最近进行删除操作
tag=1;最近进行插入操作
只有删除操作会导致队空,插入操作会导致队满
队满的条件:(插入导致队满 所以tag=1)
front==rear && tag==1
队空的条件
front==rear && tag==0
当队尾指针指向的就是队尾元素
队列的链式实现
不同于单链表,队列的链式实现需要一个带头结点和尾结点的单链表。
当在只带头结点的单链表的尾部插入数据时,需要一直遍历到尾部,时间复杂度是O(n)
在给队列进行出队操作时,只需要找到头结点
初始化(带头结点)
初始化(不带头结点)
入队操作队尾,出队操作队头
入队(带头结点)
一开始时:
s->data=x;
s->next=NULL;
Q.rear->next=s;
//不要忘了修改表尾指针
Q.rear=s;
不要忘了最后一步修改表尾指针
入队(不带头结点)
首先申请一个新结点,给新结点写入数据x。s->data=x
因为每次入队的结点都是队列中的新结点,所以
s->next=NULL
出队(带头结点)
第一步:判空
if(Q.front==Q.rear)
return false;
第二步:将p指针指向此次要删除的结点
对于带头结点的队列来说,此次要删除的就是虚拟头指针指向的下一个结点(真正的头结点)
LinkNode* p = Q.front->next;
x=p->data;
Q.front->next = p->next;//将p删掉
//如果是最后一个结点出队
if(Q.rear==p)
{
Q.rear=Q.front;//删完队列空了
}
free(p);
出队(不带头结点)
队列满的条件
双端队列
双端队列:只允许从两端插入、两端删除的线性表
例子
选择题
1.(C)
数组A[n]的下标范围0~n-1。即MaxSize=n
则队列长度 (rear-front+MaxSize)%MaxSize=(3-8+21)%21=16
队列:入队在队尾,出队在队头。而队尾在链表的表头,队头在链表的表尾。
队列需要在双端操作,所以对于单链表必须要带头指针和尾指针。改成循环链表是画蛇添足,没这个必要
只带队首指针的非循环双链表,只能在队头操作,不适合在队尾操作
3.(A)
进队是在队尾,题目中链表只有头指针,没说有头结点或是尾指针,进队后在链表头插,又因为题目是循环单链表,所以需要找到尾结点,需要一直遍历到尾结点,时间复杂度为O(n)。
4.(A)
第一个进入队列的元素存储在A[0]处,对于元素进队的操作为:Q.rear=(Q.rear+1)%MaxSize
MaxSize=n
则Q.rear=n-1
5.n至少是4
入队顺序8,4,2,5,3,9,1,6,7
出队顺序1,2,3,4,5,6,7,8,9
分组
A组:8,9
B组:4,5,6,7
C组:2,3
D组:1,