[TOC]

一、循环队列(队列的顺序存储)

如果用户的应用程序中设有循环队列,就必须为它设定一个最大队列长度。

1.定义

1
2
3
4
5
6
7
8
9
10
11
12
13
#define MAXQSIZE 100 //队列可能达到的长度

typedef struct{

int *base; //存储空间的基地址

int front; //头指针,若队列不空,指向队列头元素(实位)

int rear; //尾指针,若队列不空,指向队列尾元素的下一个位置(虚位)

}SqQueue;

SqQueue Q;
顺序队列——非循环队列
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
初始化队列:Q.front=Q.rear=0;

入队:新元素按 rear 指示位置加入,再将队尾指针加一,即
Q.base[Q.rear] = e;
Q.rear = Q.rear+1;

出队:将front指示的元素取出,再将队头指针加一,即
e=Q.base[O.front];
Q.front= Q.front+ 1;

队空:Q.front==Q.rear;

队满:Q.rear-Q.front==MAXQSIZE;

求队长:Q.rear-Q.front;

存在“假上溢”的现象:因数组越界而导致的程序非法操作错误,并且此时队列的实际可用空间并未占满。

循环队列

防假上溢:少用一个元素空间,即队列空间大小为m时,有m-1个元素就认为是队满。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
队列初始化: Q.front = Q.rear =0;

队空:Q.front == Q.rear;

队满:(Q.rear + 1)%MAXQSIZE ==Q.front;

入队:(1)队列不满,新元素e插入Q.rear所指的位置
Q.base[Q.rear] = e;
(2)Q.rear = (Q.rear+1)%MAXQSIZE;
出队:(1)队列不空,删除Q.front所指的元素
e = Q.base[Q.front];
(2)Q.front = (Q.front+1)%MAXQSIZE;
求队长:
(Q.rear - Q.front + MAXQSIZE)%MAXQSIZE;

2.初始化

  • 分配一个最大容量为MAXQSIZE的存储空间Q.base = new int[]
  • 判断分配失败
  • 否则将头指针和尾指针置为0,表示队列为空
1
2
3
4
5
6
7
8
9
10
11
12
int InitQueue(SqQueue &Q){
//构造一个空队列

Q.base = new int[MAXQSIZE]; //分配存储空间

if(!Q.base) return -1; //分配失败

Q.front = Q.rear=0; //头指针、尾指针置为0,表示队列为空

return 1;

}

3.入队

  • 判断队满
  • 否则将新元素插入队尾
  • 队尾指针+1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int EnQueue(SqQueue &Q,int e){
//插入元素e为Q的新队尾元素

if((Q.rear+1)%MAXQSIZE==Q.front)
//尾指针在循环意义上+1后等于头指针,表示队满

return -1;

Q.base[Q.rear] = e; //新元素插入队尾

Q.rear = (Q.rear+1)%MAXQSIZE; //队尾指针+1

return 1;

}

4.出队

  • 判断队空
  • 否则保存队头元素
  • 队头指针+1
1
2
3
4
5
6
7
8
9
10
11
12
int DeQueue(SqQueue &Q,int &e){
//删除Q的队头元素,用e返回其值

if(Q.front == Q.rear) return -1;//队空

e = Q.base[Q.front]; //保存队头元素

Q.front = (Q.front + 1 )%MAXQSIZE; //队头指针+1

return 1;

}

5.取队头元素

1
2
3
4
5
6
7
8
int GetHead(SqQueue Q){
//返回Q的队头元素,不修改队头指针

if(Q.front!=Q.rear) //非空

return Q.base[Q.front];//返回队头

}

二、链栈

采用链式存储结构实现的队列称为链队列

为了使操作更加方便,将队头指针指向链队列的头结点,而队尾指针指向终端结点。

空队列时,front和rear都指向头结点,即front==rear

1.定义

1
2
3
4
5
6
7
8
9
typedef struct QNode{
int data;
struct QNode *next;
}QNode,*QueuePtr;

typedef struct {
QueuePtr front; //队头指针
QueuePtr rear; //队尾指针
}LinkQueue;

微信截图_20240526020235

2.初始化

构造一个只有一个头结点的空队。

  • 生成新结点作为头结点,队头和队尾指针指向此结点
  • 头结点的指针域置空
1
2
3
4
5
6
7
8
9
10
11
int InitQueue(LinkQueue &Q){

//构造一个空队列Q

Q.front = Q.rear =new QNode; //生成新结点作为头结点,队头和队尾指针指向此结点

Q.front->next = NULL; //头结点的指针域置空

return 1;

}

3.入队

链队在入队前不需要判断队满,需要为入队元素分配结点空间。

  • 为入队元素分配结点空间,用指针p指向
  • 将新结点数据域置为e
  • 将新结点插入到队尾
  • 修改队尾指针为p
1
2
3
4
5
6
7
8
9
10
11
12
13
14
int EnQueue(LinkQueue &Q,int e){
//插入元素e为Q的新队尾元素

p = new QNode; //分配新结点

p->data = e; //把p的数据域置为e

p->next = NULL; Q.rear->next = p;//把新结点插到队尾

Q.rear = p; //修改队尾指针

return 1;

}

4.出队

链队在出队前需要判断队列是否为空,不同的是,链队在出队后需要放出队头元素的所占空间。

  • 判断队空
  • 否则临时保存队头元素的空间,等待释放
  • 修改头结点的指针域,指向下一个结点
  • 判断出队元素是否为最后一个元素,若是,则将队尾指针重新赋值,指向头结点
  • 释放原队头元素
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
int DeQueue(LinkQueue &Q,int &e){
//删除Q的队头元素,用e返回其值

if(Q.front==Q.rear) retrun -1; //队空

p = Q.front->next; //p指向队头元素

e = p->data; //e保存队头元素的值

Q.front->next = p->next; //修改头结点的指针域

if(Q.rear == p) Q.rear = Q.front; //最后一个元素被删,队尾指针指向头结点

free(p); //释放原队头元素

return 1;

}

5.求队头元素

1
2
3
4
5
6
7
8
int GetHead(LinkQueue Q){
//返回Q的队头元素,不修改队头指针

if(Q.front!=Q.rear)

return Q.front->next->data;

}