目录
一、定义
只允许在一端进行插入,另一端进行删除的线性表,也是操作受限的线性表。
重要术语:队头、队尾、空队列
特点:先进先出(FIFO——first in first out)
二、基本操作——顺序实现
InitQueue(&Q) 初始化
DestoryQueue(&Q) 销毁
EnQueue(&Q,x) 入队
DeQueue(&Q,&x) 出队(删除元素)
GetHead(Q,&x) 读队头元素(不删除元素)
QueueEmpty(Q) 判空
由于直接使用顺序存储容易出现“假溢出”的现象(队尾指针已经移到最后的位置,但队列并未满,此时造成假溢出问题),所以我们在进行入队和出队操作时可以使用循环队列。
先介绍下循环队列的概念: 就是在逻辑上将队列元素的表视为一个环
1.定义
#define Maxsize 10
typedef struct {
ElemType data[Maxsize]; //数据域
int front,rear; //指针域(队头,队尾)
}SqQueue;
规定: 让队头指针指向队头元素,让队尾指针指向队尾元素的下一个位置
2.初始化
void InitQueue(SqQueue &Q) {
Q.rear = Q.front = 0;
}
3.判空
bool QueueEmpty(SqQueue Q) {
if (Q.rear == Q.front)
return true;
else
return false;
}
4.入队
队列元素 (rear+Maxsize-front) %Maxsize
bool EnQueue(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;
}
5.出队
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;
}
6.读对头元素
bool GetHead(SqQueue Q, ElemType &x) {
if (Q.rear == Q.front) //队空
return false;
x = Q.data[Q.front];
return true;
}
7.打印
void printQueue(SqQueue S) {
int i = Q.front; //队头指针
while ( Q.front != Q.rear && (i+Maxsize) % Maxsize != Q.rear) {
//队头指针和队尾指针不一致
cout << Q.data[i] <<" ";
i++;//队头指针加一
}
}
8.额外的判空/判满方法
因为上述方法是以牺牲了一片存储空间为代价(队无法实现真正意义上的满,因为当front和rear指向同一个位置时会判空),有些时候会要求不允许浪费存储空间
法一:加入一个属性size表示队长
typedef struct {
ElemType data[Maxsize];
int front,rear;
int size;
}SqQueue;
初始化 size = 0
入队 size++
出队 size--
队满 size = Maxsize
队空 size = 0
法二:加入一个属性tag表示此时进行的是插入还是删除操纵
typedef struct {
ElemType data[Maxsize];
int front,rear;
int tag;
}SqQueue;
初始化 tag = 0
入队 tag = 1
出队 tag = 0
队满 front==rear && tag==1
队空 front==rear && tag==0
三、具体实现代码
这里使用的是加入一个属性size表示队长的循环队列
#define Maxsize 20
typedef struct
{
int data[Maxsize]; //数据域
int front,rear; //队头和队尾指针
int size; //队长
}SqQueue;
//初始化
void InitQueue(SqQueue &Q)
{
Q.rear = Q.front = 0; //队头队尾指针指向同一个位置
Q.size = 0; //队长
}
//判空
bool Empty(SqQueue Q)
{
if(Q.size == 0) //若没有队长属性,则两个指针指向同一个位置即为空
return true;
else
return false;
}
//入队
void EnQueue(SqQueue &Q, int x)
{
if (Q.size == Maxsize)
{
cout << "队满" <<endl;
return;
}
Q.data[Q.rear] = x; //存元素
Q.rear = (Q.rear + 1) % Maxsize; //队尾指针后移
Q.size++; //队长加一
}
//出队
int DeQueue(SqQueue &Q, int &x)
{
while (Q.size == 0)
{
cout << "队空,无法进行此操作"<<endl;
return false;
}
x = Q.data[Q.front];
Q.front = (Q.front + 1 ) % Maxsize; //队头指针后移
Q.size--;
return x;
}
//获取队头元素
int GetHead(SqQueue Q)
{
if (Q.size == 0)
{
cout << "队空,不存在队头元素"<<endl;
return -1;
}
return Q.data[Q.front];
}
//打印
void PrintQueue(SqQueue Q)
{
int i = Q.front; //队头
while( Q.front != Q.rear && (i+Maxsize) % Maxsize != Q.rear) //队头指针和队尾指针不指向头一个位置
{
cout<< Q.data[i]<< " ";
i++; //队头指针加一
}
}
int main()
{
SqQueue Q;
InitQueue(Q);
cout << ".............................."<<endl;
cout << ".......输入1进行入队操作......"<<endl;
cout << ".......输入2进行出队操作......"<<endl;
cout << ".......输入3进行打印操作......"<<endl;
cout << "..输入4进行获取队头元素操作..."<<endl;
cout << ".......输入5进行判空操作......"<<endl;
cout << ".......输入0退出程序......"<<endl;
cout << ".............................."<<endl;
cout <<endl;
int n,x;
while (1)
{
cout << "请输入要执行的操作:";
cin >> n;
switch(n)
{
case 1:
cout << "此时进行入队操作:..."<<endl;
EnQueue(Q,1);
EnQueue(Q,2);
EnQueue(Q,3);
EnQueue(Q,4);
EnQueue(Q,5);
cout << "入队操作结束,请执行后续操作..."<<endl;
break;
case 2:
cout << "此时进行出队操作:..."<<endl;
DeQueue(Q,x);
cout << "出队操作结束,请执行后续操作..."<<endl;
break;
case 3:
cout << "正在打印上述操作结果:..."<<endl;
cout << "此时队列内容为:";
PrintQueue(Q);
cout<<endl;
cout << "打印操作结束,请执行后续操作..."<<endl;
break;
case 4:
cout<<"此时的队头元素为:"<<GetHead(Q)<<endl;
cout << "获取队头元素操作结束,请执行后续操作..."<<endl;
break;
case 5:
cout<<"此时进行判空操作..."<<endl;
cout << "判空结果为:";
if(!Empty(Q))
{
cout<<"队不为空"<<endl;
}
break;
case 0:
cout<<"已退出程序"<<endl;
exit(0);
}
}
return 0;
}
运行结果