队列的定义:
队列说白了,就是一种**“先进先出”**的储存结构,这跟我们日常生活中的排队现象相类似,如果忘记了,就想想你是怎么排队的,(但是前提是,你不插队)
分类:
链式队列 ----用链式存储实现
静态队列 ----用顺序存储实现
静态队列一般都用循环队列
在队列的顺序存储结构中,除了用一组地址连续的存储单元依次存放从队列头到队列尾的元素之外,还需要有front(头指针)和rear(尾指针)两个分别指示队列头元素和队列尾元素的位置。
规定:初始化创建空队列时,令front=rear=0,每当插入新的队尾元素时,rear+1,每当删除队头元素时,front+1。因此,在非空队列,头指针始终指向队列头元素,而尾指针始终指向队列尾元素的下一个位置
那为什么队尾指针始终指向的是队尾元素的下一个位置呢,而不是直接指向队尾元素?
这个原理跟链表很相似,在链表中,我们始终让头指针指向头节点而不是首元节点,这是因为这样可以方便后面的操作,插入,删除,查询等等
上面为什么说:静态队列一般都使用循环队列呢?那什么是循环队列,循环队列有什么优点呢?
“假溢出”:
假设当前队列分配的最大空间是6,则当前队列处于不可以再添加新元素,否则会产生溢出的时候,也就是因数组越界而导致程序的非法操作的错误。但是事实上,此时队列实际可用的空间并未占满,所以这种现象称为“假溢出”。
这是由于“队尾入队,队头出队”这种限制的操作造成的。
循环队列:
怎么解决这一个问题呢?有一个很巧妙的方法就是将顺序队列变成一个环状的空间,我们称之为“循环队列”
具体操作:
头,尾指针以及队列的元素之间的关系不变,只是在循环队列中,头,尾指针“依次环状+1”的操作可以用“模”运算来实现。
通过取模,头指针和尾指针就可以在顺序表空间中以头尾衔接的方式“循环”移动
但是,在这种情况下,会产生一个新的问题:不管是队列为空还是满,头指针和尾指针的值都是相同的,那么我们应该怎么区分队空还是队满呢?
有两种解决方法:
(1)少用一个元素空间,即队列的大小为m,当队列有m-1个元素的时,我们就认为队满。
这样,判断队空的条件不变,即当头,尾指针的值相同的时候,就认为队空
当尾指针在循环意义上+1后等于头指针,就认为队满
队空的条件:Q.front=Q.rear
队满的条件:(Q.rear+1)%MAXQSIZE=Q.front
(2)第2种方法感兴趣的可以自行百度,这里主要讲解第一种方法
1.初始化
循环队列的初始化就是动态分配一个预定义大小为MAXQSIZE的数组空间
a.为队列分配一个最大容量为MAXQSIZE的数组空间,base指针指向数组空间的首地址
b.头尾指针置为0,表示队列为空
2.求队列长度
对于非循环队列,尾指针和头指针的差值就是队列的长度。但是对于循环队列,差值可能为负值,所以需要将差值加上MAXQSIZE,然后与MAXQSIZE求余
3.入队
表示在队尾插入一个新的元素
a.判断队列是否满,若满则返回ERROR
b.将新元素插入队尾
c.队尾指针+1
4.出队
将对头元素删除
a.判断队列是否满,若满则返回ERROR
b.保存队头元素
c.队头指针+1
5.取队头元素
当队列为空时,此操作返回当前队头元素的值,队头指针保持不变
由上述分析:如果我们不知道所需队列的最大长度,我们需要用到链式队列
一个链队显然需要两个分别表示队头和队尾的指针(分别是头指针和尾指针)才能唯一确定。这里和线性表的单链表一样,为了方便操作,给链队添加一个头节点,并令头指针始终指向头节点。
链队的插入和删除是单链表插入和删除的特殊操作,只是需进一步修改尾指针或头指针
1.初始化
链队的初始化操作就是构造一个只有一个头节点的空队
a.生成新节点作为头节点,队头和队尾指针指向此节点
b.头节点的指针域置空
2.入队
和循环队列的入队操作不同的是,链队在入队前不需要判断队是否已满,需要为入队元素分配一个节点空间
a.为入队元素分配节点空间,用指针p指向
b.将新节点的数据域置e
c.将新节点插入队尾
d.修改队尾指针为p
3.出队
和循环队列一样,链队在出队前也需要判断队列是否为空,不同的是,链队在出队后需要释放出队头元素所占的空间
a.判断队列是否为空,若为空则返回ERROR
b.临时保存队头元素的空间,以备释放
c.修改队头指针,指向下一个节点
d.判断出队元素是否是最后一个元素,若是,则将队尾指针重新赋值,指向头节点
e.释放原队头元素的空间
需要注意的是,在链队出队操作的时候还需要考虑当队伍中最后一个元素被删除之后,队列尾指针也丢失了,因此需要对队尾指针重新赋值(指向头指针)
4.取队头元素
与循环队列一样,当队列非空时,此操作返回当前队头元素的值,队头指针保持不变
顺序队列(非循环队列):
#include<iostream>
using namespace std;
#define MAXSIZE 100
#define ElemType int
//顺序队列的数据结构
typedef struct queue
{
ElemType *front; //队头指针
ElemType *rear; //队尾指针
int queueSize; //该顺序队列的最大长度
}Queue;
//初始化顺序队列
void initQueue(Queue &q)
{
q.front = new ElemType[MAXSIZE];
if (q.front == NULL)
{
cout << "分配内存失败!" << endl;
exit(0);
}
q.queueSize = MAXSIZE;
q.rear = q.front;
}
//入队
void addQueue(Queue &q,ElemType e)
{
//队满
if (q.rear - q.front == q.queueSize)
{
cout << "队满!" << endl;
exit(0);
}
//从队尾入队
*(q.rear) = e;
q.rear++;
}
//出队,并用e返回其值
void outQueue(Queue &q,ElemType &e)
{
//判断是否为空
if (q.front == q.rear)
{
cout << "队空!" << endl;
exit(0);
}
//出队,从队头出队
e = *(q.front); //保存队头元素
q.front++;
}
//获取队头元素
void getTop(Queue q,ElemType &a)
{
//判断是否为空
if (q.front == q.rear)
{
cout << "队空!" << endl;
exit(0);
}
a = *(q.front);
}
//获取队尾元素
void getTail(Queue q, ElemType &a)
{
//判断是否为空
if (q.front == q.rear)
{
cout << "队空!" << endl;
exit(0);
}
a = *(--q.rear);
}
void display(Queue q)
{
//判断是否为空
if (q.front == q.rear)
{
cout << "队空!" << endl;
exit(0);
}
ElemType *p = q.front;
while (p != q.rear)
{
cout << *p<<"\t";
p++;
}
//cout << q.rear;
cout << endl;
}
//创建一个操作菜单
void menu()
{
cout << "*****************顺序队列的操作***************" << endl;
cout << "**********************************************" << endl;
cout << "* 1.入队 2.出队 *" << endl;
cout << "* 3.取队头 4.取队尾 *" << endl;
cout << "* 5.显示 6.退出 *" << endl;
cout << "**********************************************" << endl;
Queue q;
initQueue(q);
int choice;
ElemType b; //临时保存
ElemType a; //获取队头元素
ElemType c; //获取队尾元素
ElemType e; //返回出队元素
while (1)
{
cout << "请输入你的操作:";
cin >> choice;
if (choice == 6)
break;
switch (choice)
{
case 1:
cout << "请输入需要入队的元素:";
cin >> b;
addQueue(q, b);
break;
case 2:
outQueue(q,e);
cout << "出队的元素是:" << e << endl;
break;
case 3:
getTop(q, a);
cout << "队头元素是:" << a << endl;
break;
case 4:
getTail(q,c);
cout << "队尾元素是:" << c << endl;
break;
case 5:
display(q);
break;
default:cout << "输入有误!" << endl;
}
}
}
int main()
{
menu();
system("pause");
return 0;
}
但是,我们会发现,上面这种存储会十分浪费空间,所以有了下面的这种解决方法:
循环队列
#include<iostream>
using namespace std;
#define MAXSIZE 100
#define ElemType int
typedef struct queue
{
ElemType *queue;
int front;
int rear;
}Queue;
//初始化
void initQueue(Queue &q)
{
q.queue = new ElemType[MAXSIZE];
if (q.queue == NULL)
{
cout << "分配内存失败!" << endl;
exit(0);
}
q.front = q.rear = 0;
}
//入队
void addQueue(Queue &q,ElemType e)
{
if ((q.rear + 1) % MAXSIZE == q.front)
{
cout << "队满!" << endl;
exit(0);
}
//入队,从队尾入
q.queue[q.rear] = e;
q.rear = (q.rear + 1) % MAXSIZE;
}
//出队,并返回队头元素
void outQueue(Queue &q,ElemType &a)
{
//判断是否为空
if (q.rear == q.front)
{
cout << "队空!" << endl;
exit(0);
}
//出队:从队头出
a = q.queue[q.front];
q.front = (q.front + 1) % MAXSIZE;
}
//取出队头元素
void getTop(Queue &q,ElemType &b)
{
if (q.rear == q.front)
{
cout << "队空!" << endl;
exit(0);
}
b = q.queue[q.front];
}
//取出队尾元素
void getTail(Queue &q,ElemType &c)
{
if (q.rear == q.front)
{
cout << "队空!" << endl;
exit(0);
}
c = q.queue[q.rear];
}
//判断队列是否为空
void empty(Queue q)
{
if (q.front == q.rear)
{
cout << "队列为空!" << endl;
}
else
{
cout << "队列不为空!" << endl;
}
}
//判断队列是否已满
void full(Queue q)
{
if ((q.rear + 1) % MAXSIZE == q.front)
cout << "队列已满!" << endl;
cout << "队列未满!" << endl;
}
//求队列长度
void getLength(Queue &q, int &Length)
{
Length = (q.rear - q.front + MAXSIZE) % MAXSIZE;
}
void display(Queue q)
{
if (q.rear == q.front)
{
cout << "队空!" << endl;
exit(0);
}
int i = q.front;
while (i != q.rear)
{
cout << q.queue[i] << "\t";
i = (i + 1) % MAXSIZE;
}
cout << endl;
}
//创建一个操作菜单
void menu()
{
cout << "****************循环队列的操作****************" << endl;
cout << "**********************************************" << endl;
cout << "* 1.入队 2.出队 *" << endl;
cout << "* 3.取队头 4.取队尾 *" << endl;
cout << "* 5.取长度 6.判断空? *" << endl;
cout << "* 7.判断满? 8.显示 *" << endl;
cout << "* 9.退出 *" << endl;
cout << "**********************************************" << endl;
Queue q;
initQueue(q);
int choice;
ElemType e; //入队元素
ElemType a; //出队
ElemType b; //队头
ElemType c; //队尾
int Length; //存储长度
while (1)
{
cout << "请输入你的操作:";
cin >> choice;
if (choice == 9)
break;
switch (choice)
{
case 1:
cout << "请输入需要入队的元素:";
cin >> e;
addQueue(q, e);
break;
case 2:
outQueue(q,a);
cout << "出队的元素是:" << a << endl;
break;
case 3:
getTop(q, b);
cout << "队头元素是:" << b << endl;
break;
case 4:
getTail(q,c);
cout << "队尾元素是:" << b << endl;
break;
case 5:
getLength(q, Length);
cout << "队列长度是:" << Length << endl;
break;
case 6:
empty(q);
break;
case 7:
full(q);
break;
case 8:
display(q);
break;
default:cout << "输入有误!" << endl;
}
}
}
int main()
{
menu();
system("pause");
return 0;
}
链队
#include<iostream>
using namespace std;
#define ElemType int
struct Node
{
ElemType data;
struct Node *next;
};
//创建新的节点,为入队做准备
struct Node* creatNode(ElemType data)
{
struct Node *newNode = new struct Node;
newNode->next = NULL;
newNode->data = data;
return newNode;
}
struct Queue
{
Node *front;
Node *rear;
int size;
};
//初始化操作,创建一个空队列
void initQueue(struct Queue *myqueue)
{
myqueue->front = new struct Node;
if (!myqueue->front)
{
cout << "内存分配失败!" << endl;
exit(0);
}
myqueue->rear = myqueue->front;
myqueue->front->next = NULL;
myqueue->size = 0;
}
//入队
void addQueue(struct Queue *&myqueue, ElemType data)
{
struct Node * newNode = creatNode(data);
//入队 尾入队
myqueue->rear->next = newNode;
myqueue->rear = newNode;
myqueue->size++;
}
//出队
void outQueue(struct Queue *&myqueue,ElemType &a)
{
//判断队列是否为空
if (myqueue->size == 0)
{
cout << "队列为空!" << endl;
exit(0);
}
//出队
//保存要删除的节点
struct Node*nTemp = myqueue->front->next;
//保存要删除的节点的值
a = myqueue->front->next->data;
//将头指针移动
//头指针指向要删除的节点的下一个
myqueue->front->next = nTemp->next;
delete nTemp;
myqueue->size--;
}
void getHead(struct Queue *myqueue, ElemType &a)
{
a = myqueue->front->next->data;
}
void getTail(struct Queue *myqueue, ElemType &a)
{
a = myqueue->rear->data;
}
void getLength(struct Queue *myqueue, ElemType &a)
{
a = myqueue->size;
}
//判断是否为空
void empty(struct Queue *myqueue)
{
if (myqueue->size == 0)
cout << "链队为空!" << endl;
cout << "链队不为空!" << endl;
}
void display(struct Queue myqueue)
{
if (myqueue.size == 0)
{
cout << "链队为空!" << endl;
exit(0);
}
struct Node *node = myqueue.front->next;
while (node->next)
{
cout << node->data << "\t";
node = node->next;
}
cout << node->data;
cout << endl;
}
//创建一个操作菜单
void menu()
{
cout << "******************链队的操作******************" << endl;
cout << "**********************************************" << endl;
cout << "* 1.入队 2.出队 *" << endl;
cout << "* 3.取队头 4.取队尾 *" << endl;
cout << "* 5.取长度 6.判断空? *" << endl;
cout << "* 7.显示 8.退出 *" << endl;
cout << "**********************************************" << endl;
struct Queue *q = new struct Queue;
initQueue(q);
int choice;
ElemType e; //入队元素
ElemType a; //出队
ElemType b; //队头
ElemType c; //队尾
int Length; //存储长度
while (1)
{
cout << "请输入你的操作:";
cin >> choice;
if (choice == 8)
break;
switch (choice)
{
case 1:
cout << "请输入需要入队的元素:";
cin >> e;
addQueue(q, e);
break;
case 2:
outQueue(q, a);
cout << "出队的元素是:" << a << endl;
break;
case 3:
getHead(q, b);
cout << "队头元素是:" << b << endl;
break;
case 4:
getTail(q, c);
cout << "队尾元素是:" << c << endl;
break;
case 5:
getLength(q, Length);
cout << "队列长度是:" << Length << endl;
break;
case 6:
empty(q);
break;
case 7:
display(*q);
break;
default:cout << "输入有误!" << endl;
}
}
}
int main()
{
menu();
system("pause");
return 0;
}