队列的数据结构
#include <iostream>
#include <cstdlib>
using namespace std;
struct QNode //定义队列结点的数据结构
{
QNode *next; //指针域,指向下一个结点
double data; //数据域,存储队列信息
};
struct LinkQueue //定义队列的数据结构
{
QNode *front; //队首指针,指向QNode类型的指针
QNode *rear; //队尾指针
};
void InitQueue(LinkQueue &Q) //构造一个空的队列
{
QNode *q;
q = new QNode; //申请一个结点的空间
q->next = NULL; //当作头结点
//队首与队尾指针都指向这个结点,指针域为NULL
Q.front = q;
Q.rear = q;
}
int IsEmpty(LinkQueue &Q) //判断队列是否为空
{
if (Q.rear == Q.front)
return 0;
else
return 1;
}
void EnQueue(LinkQueue &Q, double e) //从队列尾部插入元素
{
QNode *p; //新创建一个结点
p = new QNode;
p->next = NULL;
p->data = e; //输入数据信息
//将新结点插入队列尾部
Q.rear->next = p;
Q.rear = p; //设置新的尾结点
}
void DeQueue(LinkQueue &Q, double &e) //从队列首部删除一个结点
{
QNode *p;
p = Q.front->next;
e = p->data; //保存要出队列的数据
Q.front->next = p->next; //将下一个结点当作头结点后面链接的第一个结点
if (Q.rear == p) //如果要删除的元素即为尾结点,则将头指针赋予尾指针,一同指向头结点,表示队列为空
Q.rear = Q.front;
delete p;
}
void DestoryQueue(LinkQueue &Q) //销毁一个队列
{
while (Q.front)
{
Q.rear = Q.front->next; //从头节点开始,一个一个删除队列结点,释放空间
delete Q.front;
Q.front = Q.rear;
}
}
int main()
{
LinkQueue *Q; //定义一个队列Q
Q = new LinkQueue;
InitQueue(*Q);
cout << "开始往队列里输入数据,以-1作为结束符" << endl;
cout << "请输入一个数:" << endl;
double a, x;
cin >> a;
while (a != -1)
{
EnQueue(*Q, a);
cout << "请输入一个数:" << endl;
cin >> a;
}
//输出队列元素,队首->队尾
QNode *p;
p = Q->front->next;
if (p == NULL) //如果为空表,直接退出
{
cout << "队列为空!" << endl;
return 0;
}
cout << "队列数据依次为:" << endl;
while (p != NULL)
{
cout << p->data << " ";
p = p->next;
}
cout << endl;
//删除队列元素
while (!IsEmpty(*Q))
{
DeQueue(*Q, x);
cout << x << " ";
}
//释放内存空间
delete Q->front;
delete Q;
system("pause");
return 0;
}
队列 C++ STL
定义:queue<typename> 队列名字;
直接定义默认空队列,queue<int> q2(q1);
还可以通过此方法复制
引用方法:
#include <queue>
or #include <bits/stdc++.h>
用法:
q.front(); //获取队首
q.back(); //获取队尾
q.push(x); //插入元素,x表示要插入的值,什么都行(但是类型必须和定义的相同)
q.pop(); //将队头弹出,无返回值
q.size(); //返回队列里有多少个元素
q.empty(); //如果队列为空,返回true,否则返回false( 等同于q.size()==0 )
q.swap(q2); //交换q和q2里面的值(q2需要和q是一个类型)
双向队列
双向队列不仅可以在队尾插入,在队头删除,还可以在队头插入,在队尾删除,支持下标访问
缺点:速度慢
deque<typename> 双向队列名字;
引用:
#include <deque>
或
#include <queue>
因为在queue这个头文件里面包含了deque
或
万能头文件
使用:
q.push_front(x); //在队头插入元素,x表示要插入的值,什么都行(但是类型必须和定义的相同)
q.push_back(x); //在队尾插入元素,x表示要插入的值,什么都行(但是类型必须和定义的相同)
q.pop_front(); //将队头弹出,无返回值
q.pop_back(); //将队尾弹出,无返回值
q.front(); //和queue的一样
q.back(); //和queue的一样
q.size(); //和queue的一样
q.empty(); //和queue的一样
q.swap(q2); //和queue的一样
q[i] //获取第i个元素(队头是第0个)
q.at(i); //同上(不同的地方很少)
q.clear(); //清空双向队列
q.begin(); //获取首地址,返回迭代器 (待会说怎么用)
q.end(); //获取位地址+1 注意!还要加1
还有很多......
优先队列
Queue是一个先进先出(FIFO)的队列。
在银行柜台办业务时,我们假设只有一个柜台在办理业务,但是办理业务的人很多,怎么办?
可以每个人先取一个号,例如:A1、A2、A3……然后,按照号码顺序依次办理,实际上这就是一个 Queue。
如果这时来了一个VIP客户,他的号码是V1,虽然当前排队的是A10、A11、A12……但是柜台下一个呼叫的客户号码却是V1。
这个时候,我们发现,要实现“VIP插队”的业务,用 Queue 就不行了,因为 Queue 会严格按 FIFO 的原则取出队首元素。
我们需要的是优先队列:PriorityQueue。
PriorityQueue 和 Queue 的区别在于,它的出队顺序与元素的优先级有关
优先队列保证队头最大(想最小也行)但内部排列随意,每次删除都会把接下来最大or最小的放上来
定义办法:
priority_queue<Type, Container, Functional>
Type 是数据类型;Container 是容器类型,一般使用vector;Functional 是比较的方式。
引用方法同队列
方法:
q.push(x); //插入元素到队尾并排序,x表示要插入的值,什么都行(但是类型必须和定义的相同)
q.pop(); //将队头弹出,无返回值
q.top(); //和queue的一样
q.size(); //和queue的一样
q.empty(); //和queue的一样
接下来介绍如何让优先队列的队头最小或者最大
我们首先要知道这样的概念:
大顶堆:字面意思,根(顶)最大的堆。
小顶堆:根(顶)最小的堆。
//_________________默认为大顶堆_________________
priority_queue<int> q1;
//_________________标准一般写法_________________
//小顶堆,队头最小
priority_queue<int,vector<int>,greater<int> > q2;
//大顶堆
priority_queue<int,vector<int>,less<int> >q3;