基本描述
排队,做核酸这些大家都有吧, 学校打饭是不是按照队伍的形式来 打饭?
队列原理精讲
队列:是一个先进先出 的一种数据结构,
队列:受限线性结构;
队列::只允许前面出队后面入队
出队的时候有两种方法:
物理删除,逻辑删除
所谓的物理删除 该怎么删除就这么删除
逻辑删除:不去直接删除 而是直接访问下一个元素 所谓的:忽略 不去直接删除 好处 避免了大量的移动 效率高
队列的算法实现:
顺序队列
顺序队列:用顺序结构来做的队列 效果如上
初始化队列
尾部添加元素(往后添加)
头部删除元素(逻辑删除)
访问队头
访问队尾
获取队列元素个数
顺序队列:
//元素类型
using ElementType = user-defined;
//顺序队列辅助
struct _SeqQueueAuxiliary {
ElementType* front;
ElementType* back;
};
//顺序队列辅助
using SeqQueueAuxiliary = struct _SeqQueueAuxiliary;
//顺序队列
struct _SeqQueue{
ElementType* element;
size_t Size;
SeqQueueAuxiliary Auxiliary;
};
//顺序队列
using SeqQueue = struct _SeqQueue;
//元素类型
using ElementType = Hero;
//顺序队列辅助
struct _SeqQueueAuxiliary {
ElementType* front;
ElementType* back;
};
//顺序队列辅助
using SeqQueueAuxiliary = struct _SeqQueueAuxiliary;
//顺序队列
struct _SeqQueue{
ElementType* element;
size_t Size;
SeqQueueAuxiliary Auxiliary;
};
//顺序队列
using SeqQueue = struct _SeqQueue;
//最大的顺序队列元素大小
const size_t SeqQueueMaxSize = 1000;
顺序队列 操作算法声明:
//初始化顺序队列
void initQueue(SeqQueue& Queue);
//入队
void push_Queue(SeqQueue& Queue, const ElementType& e);
//访问队头元素
ElementType& Queue_front(SeqQueue& Queue);
//访问队尾元素
ElementType& Queue_back(SeqQueue& Queue);
//顺序队列已满
bool fullQueue(const SeqQueue& Queue);
//顺序队列已空
bool emptyQueue(const SeqQueue& Queue);
//出队
void pop_Queue(SeqQueue& Queue);
//队列元素大小
const size_t& QueueSize(const SeqQueue& Queue);
//销毁顺序队列
void destroyQueue(SeqQueue& Queue);
//顺序队列辅助
SeqQueueAuxiliary 这个好像没有见过 全网的文章都没有 那是要不然怎么做原创嘛,
从定义来看
ElementType* front;//方便访问 并且不用平凡的删除元素
ElementType* back;//方便添加元素 方便访问 back-1的元素 才是最后一个元素
顺序队列 操作算法实现
#include"SeqQueue.h"
#include<stdexcept>
using namespace std;
const size_t zero = 0u;
void initQueue(SeqQueue& Queue){
Queue.element = new ElementType[SeqQueueMaxSize];
Queue.Auxiliary = { Queue.element,Queue.element};
Queue.Size = zero;
}
void push_Queue(SeqQueue& Queue, const ElementType& e) {
const bool FullQueue = fullQueue(Queue);
size_t& size = Queue.Size;
if (!FullQueue){
*Queue.Auxiliary.back = e;
++Queue.Auxiliary.back;
++size;
}
}
ElementType& Queue_front(SeqQueue& Queue) {
const bool EmptyQueue = emptyQueue(Queue);
if (EmptyQueue) {
terminate();
}
return*Queue.Auxiliary.front;
}
ElementType& Queue_back(SeqQueue& Queue) {
const bool EmptyQueue = emptyQueue(Queue);
ElementType* Back = Queue.Auxiliary.back - 1;
if (EmptyQueue) {
terminate();
}
return*Back;
}
bool emptyQueue(const SeqQueue& Queue) {
return Queue.Size == zero;
}
bool fullQueue(const SeqQueue& Queue){
return Queue.Size == SeqQueueMaxSize;;
}
inline static void move_froot(ElementType *first, ElementType* last , ElementType* Target) {
while (first!= last){
*(Target) = static_cast<ElementType&&>(*first);
++first;
++Target;
}
}
void pop_Queue(SeqQueue& Queue){
const bool EmptyQueue = emptyQueue(Queue);
size_t& size = Queue.Size;
const ElementType* full = Queue.element + SeqQueueMaxSize;
if (!EmptyQueue){
if (Queue.Auxiliary.front == full) {
destroyQueue(Queue);
terminate();
}
++Queue.Auxiliary.front;
--size;
return;
}
destroyQueue(Queue);
terminate();
}
const size_t& QueueSize(const SeqQueue& Queue){
return Queue.Size;
}
void destroyQueue(SeqQueue& Queue){
delete[] Queue.element;
Queue.element = nullptr;
Queue.Size = zero;
Queue.Auxiliary = {};
}
如果不明白这些操作 请看:数据结构算法-顺序表技术点
链式队列
链式队列以链表基础之上维护一个队列统称为:“链式队列”
如图:
初始化队列
尾部添加元素: 入队 (队尾结点的下一个结点永远为null)
头部删除元素(物理删除)
访问队头
访问队尾
获取队列元素个数
链式队列声明
//元素类型
using ElementType = user-defined;
//链式队列节点
using ListQueueNode = struct _ListQueueNode;
struct _ListQueueNode {
ElementType value;
ListQueueNode* next;
};
//链式队列辅助
struct _ListQueueAuxiliary {
ListQueueNode* front;
ListQueueNode* back;
};
//链式队列辅助
using ListQueueAuxiliary = struct _ListQueueAuxiliary;
//链式队列
struct _ListQueue {
ListQueueNode* List;
size_t size;
ListQueueAuxiliary Auxiliary;
};
//链式队列
using ListQueue = struct _ListQueue;
链式队列 操作算法声明
//最大的链式队列元素大小
const size_t ListQueueMaxSize = 1000;
//初始化链式队列
void initQueue(ListQueue& Queue);
//入队
void push_Queue(ListQueue& Queue, const ElementType& e);
//访问队头元素
ElementType& Queue_front(ListQueue& Queue);
//访问队尾元素
ElementType& Queue_back(ListQueue& Queue);
//链式队列已满
bool fullQueue(const ListQueue& Queue);
//链式队列已空
bool emptyQueue(const ListQueue& Queue);
//出队
void pop_Queue(ListQueue& Queue);
//队列元素大小
const size_t& QueueSize(const ListQueue& Queue);
//销毁链式队列
void destroyQueue(ListQueue& Queue);
链式队列 操作算法实现:
#include"ListQueue.h"
#include<stdexcept>
using namespace std;
const size_t zero = 0u;
ListQueueNode* createNode(ListQueueNode* nullNode = nullptr) {
ListQueueNode* Node = new ListQueueNode;
Node->next = nullNode;
return Node;
}
ListQueueNode* createNode(const ElementType &value , ListQueueNode* nullNode = nullptr) {
ListQueueNode* Node = new ListQueueNode{ value,nullNode };
return Node;
}
void Link(ListQueueNode*& Node, ListQueueNode* NewNode) {
if (Node) {
Node->next = NewNode;
}
Node = NewNode;
}
void unLink(ListQueueNode*& Node, ListQueueNode* DeleteNode) {
if (Node) {
Node->next = DeleteNode->next;
}
}
void initQueue(ListQueue& Queue){
Queue.List = createNode();
Queue.size = 0;
Queue.Auxiliary = { Queue.List,Queue.List };
}
void push_Queue(ListQueue& Queue, const ElementType& e){
const bool FullQueue = fullQueue(Queue);
if (FullQueue){
while (true) {
terminate();
}
}
bool iSfront = Queue.size == zero;
Link(Queue.Auxiliary.back, createNode(e));
++Queue.size;
if (iSfront){
Queue.Auxiliary.front = Queue.List->next;
}
}
ElementType& Queue_front(ListQueue& Queue){
if (emptyQueue(Queue)){
terminate();
}
return Queue.Auxiliary.front->value;
}
ElementType& Queue_back(ListQueue& Queue){
if (emptyQueue(Queue)) {
terminate();
}
return Queue.Auxiliary.back->value;
}
bool fullQueue(const ListQueue& Queue){
return Queue.size == ListQueueMaxSize;
}
bool emptyQueue(const ListQueue& Queue){
return Queue.size == zero;
}
void pop_Queue(ListQueue& Queue){
const bool EmptyQueue = emptyQueue(Queue);
size_t& size = Queue.size;
ListQueueNode* deleteNode = Queue.Auxiliary.front;
ListQueueNode*& node = Queue.List;
ListQueueNode*& front = Queue.Auxiliary.front;
ListQueueNode*& frontNext = Queue.Auxiliary.front->next;
if (!EmptyQueue){
front = frontNext;
unLink(node, deleteNode);
delete deleteNode;
deleteNode = nullptr;
--size;
return;
}
terminate();
}
const size_t& QueueSize(const ListQueue& Queue) {
return Queue.size;
}
void destroyQueue(ListQueue& Queue) {
ListQueueNode*& Firsh = Queue.List;
ListQueueNode*& deleteNode = Firsh;
ListQueueNode* Next = Firsh->next;
size_t& size = Queue.size;
ListQueueAuxiliary& Auxiliary = Queue.Auxiliary;
while (Firsh){
Next = Firsh->next;
delete deleteNode;
deleteNode = Next;
}
size = zero;
Auxiliary = {};
}
任务队列
基于任务处理的队列;
这个任务是啥? 你觉得能够处理任务是啥 函数?
是的 ,那咋维护函数? 或者说,如何在队列的数据结构中 使用函数来实现任务呢
学过函数指针的就知道,基础知识要打捞啊
维护一个函数指针变量即可,如果需要参数的话,队列元素加一个 数据,
先看看实例:
#include<iostream>
#include"ListQueue.h"
#include<thread>
using namespace std;
using namespace std::this_thread;
using namespace chrono;
Task make_Task(Hero* h, TaskProcessingFunction func) {
Task task;
task.hero = h;
task.Disposefunc = func;
return task;
}
//玩我的世界游戏
void PlayMinecraft(Hero& h){
cout << "正在穿越.....\n";
int c = 0;
for (size_t i = 0; i < 2; i++){
c += 200 * i * 2 * i + 1;
}
//休眠 n ms
sleep_for(milliseconds(c));
cout << h.name<<"穿越回了现代... 玩着风靡全球的沙盒游戏中....\n";
}
//玩原神
void PlayAugusteGusteau(Hero& h) {
cout << "正在穿越.....\n";
int c = 0;
for (size_t i = 0; i < 2; i++) {
c += 200 * i * 2 * i + 1;
}
//休眠 n ms
sleep_for(milliseconds(c));
cout << h.name << "穿越回了现代... 玩着米哈游研发的开放世界角色扮演游戏中....\n";
}
//玩绝地求生大逃杀
void PlayPUBG(Hero& h) {
cout << "正在穿越.....\n";
int c = 0;
for (size_t i = 0; i < 2; i++) {
c += 200 * i * 2 * i + 1;
}
//休眠 n ms
sleep_for(milliseconds(c));
cout << h.name << "穿越回了现代... 玩着蓝洞游戏研发的第一视角射击游戏中....\n";
}
void setTasks(Task task[], int index, Hero heros[], TaskProcessingFunction func) {
task[index] = make_Task(heros + index,func);
}
int main(void) {
ListQueue queue;
initQueue(queue);
Hero heros[3]{ "刘备","关羽","张飞" };
Task task[3];
setTasks(task, 0, heros, PlayMinecraft);
setTasks(task, 1, heros, PlayPUBG);
setTasks(task, 2, heros, PlayAugusteGusteau);
for (size_t i = 0; i < 3; i++){
push_Queue(queue, task[i]);
}
while (!emptyQueue(queue)){
Task& t = Queue_front(queue);
Hero& hero = *t.hero;
t.Disposefunc(hero);
pop_Queue(queue);
}
destroyQueue(queue);
}
为啥需要任务队列?
任务队列 是大规模的函数调用 ,
任务队列:线程池的辅助
说说单线程:就是单一的老板 在忙工作并没有什么员工 进程就是这家公司 ,只有员工
多线程:"员工做事情 " 而 线程池 就像一个部门,任务队列,就像管理层 管理着一个个部门 执行一系列的工作
优先级队列
按照升序或者降序排序的]队列
生活中也有这个例子:医院排队缴费墙上写着"老人或者拥有军人证书的"请到第一窗口"进行缴费"这就是优先级
以前高铁站缴费也要排队,但只要有残疾人或者老人,拥有军人证书的军人,就会优先服务
链式优先级队列算法声明
#ifndef __PriorityQueue_H__
#define __PriorityQueue_H__
using Element = user define;
using Node = struct PriorityQueueNode;
using PriorityCompare = bool (*)(const Element&, const Element&);
struct PriorityQueueNode{
Element value;
Node* next;
};
struct _PriorityQueueAuxiliary{
Node* froot;
Node* back;
};
using PriorityQueueAuxiliary = struct _PriorityQueueAuxiliary;
struct PriorityQueue{
PriorityCompare Compare;
Node *List;
size_t size;
PriorityQueueAuxiliary Auxiliary;
};
const size_t MaxSize = 1000;
void initPriorityQueue(PriorityQueue& priorityQueue, PriorityCompare c);
void PushPriorityQueue(PriorityQueue& priorityQueue,const Element& value);
bool fullPriorityQueue(const PriorityQueue& priorityQueue);
bool emptyPriorityQueue(const PriorityQueue& priorityQueue);
Element& PriorityQueueFroot( PriorityQueue& priorityQueue);
void PopPriorityQueue(PriorityQueue& priorityQueue);
void setCompare(PriorityQueue& priorityQueue, PriorityCompare Compare);
const size_t& PriorityQueueSize(PriorityQueue& priorityQueue);
void destroyPriorityQueue(PriorityQueue& priorityQueue);
#endif
链式优先级队列算法实现
#include"PriorityQueue.h"
#include<stdexcept>
using namespace std;
const size_t zero = 0;
//创建优先级队列结点
Node* CreatePriorityQueueNode(Node*nullPtr=nullptr) {
Node* node = new Node;
node->next = nullPtr;
return node;
}
//创建优先级队列元素
Node* CreatePriorityQueueNode(const Element &value,Node* nullPtr = nullptr) {
Node* node = new Node{value,nullPtr};
return node;
}
void initPriorityQueue(PriorityQueue& priorityQueue, PriorityCompare c){
Node*& List = priorityQueue.List = CreatePriorityQueueNode();
priorityQueue.Auxiliary = { List,List };
priorityQueue.size = zero;
priorityQueue.Compare = c;
}
bool fullPriorityQueue(const PriorityQueue& priorityQueue){
return priorityQueue.size == MaxSize;
}
bool emptyPriorityQueue(const PriorityQueue& priorityQueue){
return priorityQueue.size == zero;
}
void GetPriorityNode(Node*& ,PriorityCompare &);
Element& PriorityQueueFroot(PriorityQueue& priorityQueue)
{
if (emptyPriorityQueue(priorityQueue)) {
terminate();
}
GetPriorityNode(priorityQueue.Auxiliary.froot, priorityQueue.Compare);
return priorityQueue.Auxiliary.froot->value;
}
void Link(Node*& node, Node* NewNode) {
if (node) {
node->next = NewNode;
}
node = NewNode;
}
const size_t& PriorityQueueSize(PriorityQueue& priorityQueue){
return priorityQueue.size;
}
void PushPriorityQueue( PriorityQueue& priorityQueue,const Element& value) {
const bool iSfront = priorityQueue.size == zero;
if (fullPriorityQueue(priorityQueue)) {
terminate();
}
Link(priorityQueue.Auxiliary.back, CreatePriorityQueueNode(value));
++priorityQueue.size;
if (iSfront) {
priorityQueue.Auxiliary.froot = priorityQueue.List->next;
}
}
void GetPriorityNode(Node*& froot, PriorityCompare &Compare) {
Node** node = &froot;
Node* last = (froot);
Node* current = last->next;
while (current){
if (Compare(current->value,(*node)->value)) {
node = &(last->next);
}
last = current;
current = current->next;
}
froot = *node;
}
void GetPriorityNode(Node*& froot, Node*&DeleteNode, Node*& back, PriorityCompare &Compare) {
Node** node = &froot;
Node* last = (froot);
Node* current = last->next;
while (current) {
if (Compare(current->value, (*node)->value)) {
node = &(last->next);
back = last;
}
last = current;
current = current->next;
}
DeleteNode = *node;
*node = (*node)->next;
}
void setCompare(PriorityQueue& priorityQueue, PriorityCompare Compare) {
priorityQueue.Compare = Compare;
}
void PopPriorityQueue(PriorityQueue& priorityQueue) {
if (emptyPriorityQueue(priorityQueue)){
terminate();
}
size_t &size = priorityQueue.size;
Node*& ListNext = priorityQueue.List->next;
Node* &froot = priorityQueue.Auxiliary.froot;
froot = ListNext;
Node*& back= priorityQueue.Auxiliary.back;
PriorityCompare& Compare =priorityQueue.Compare;
Node* DeleteNode;
GetPriorityNode(froot, DeleteNode, back, Compare);
ListNext = froot;
delete DeleteNode;
DeleteNode = nullptr;
--size;
if (size == zero) {
back = ListNext;
}
}
void destroyPriorityQueue(PriorityQueue& priorityQueue) {
Node*& Firsh = priorityQueue.List;
Node*& deleteNode = Firsh;
size_t& size = priorityQueue.size;
PriorityQueueAuxiliary& Auxiliary = priorityQueue.Auxiliary;
while (Firsh) {
Node* next = Firsh->next;
delete deleteNode;
deleteNode = next;
}
priorityQueue = {};
}
获取指定优先级的值操作
void GetPriorityNode(Node*& froot, PriorityCompare &Compare)
获取删除指定优先级的结点
void GetPriorityNode(Node*& froot, Node*&DeleteNode, Node*& back, PriorityCompare &Compare);
高并发Web服务器队列的应用
在高并发Http反向代理服务器 Ningx 中有一个有关于性能息息相关的模块–文件缓存
文件(File)是磁盘的一个小单元,系统启动(Run)的时候,会把系统文件加载到内存里
此时有一些文件是没必要的,如何维护这些没必要的文件此时很关键,用队列维护 好主意
符合先进先出的数据结构自然当选,
NingxQueue.h
#ifndef __NINGXQUEUE_H__
#define __NINGXQUEUE_H__
#include<stdlib.h>
using NingxQueueNode = struct NingxQueueNode;
//ningx 双端队列结点
struct NingxQueueNode{
NingxQueueNode* prev;
NingxQueueNode* next;
};
//ningx 双端队列
struct NingxQueue {
NingxQueueNode* List;
size_t size;
};
#define CreatorNingxQueueNode(Node)\
Node = new NingxQueueNode; \
\
Node->prev = Node; \
Node->next = Node
#define NingxQueueInit(Queue) \
CreatorNingxQueueNode(Queue.List); \
Queue.size = 0u
\
#define NingxQueueLink(List,Node) \
(Node)->next = List->next; \
(Node)->next->prev = (Node); \
(Node)->prev = List; \
List->next = (Node)
#define NingxQueueUnLink(Node) \
(Node)->next->prev = (Node)->prev; \
(Node)->prev->next = (Node)->next \
#define NingxQueueSize(Queue) ((Queue.size))
#define NingxQueueInsertFroot(Queue,Node) \
NingxQueueLink(Queue.List,(Node)); \
++NingxQueueSize(Queue) ;\
#define NingxQueueFirst(Queue)\
Queue.List->prev
\
#define NingxQueueLast(Queue)\
(((Queue.List)->prev))
\
#define isEnd(List) (List)
#define NingxQueueEmpty(Queue) (Queue.size)
#define NingxQueueElement(node,type,Link)\
(type*)((char*)node - offsetof(type,Link))
#define NingxQueueDelete(Queue,Node) \
NingxQueueUnLink(Node); \
--NingxQueueSize(Queue);\
#define NingxQueueDestroy(Queue)\
delete Queue.List; \
Queue = {}
#endif
main.cpp
#include<iostream>
#include"NingxQueue.h"
using std::cout;
using std::endl;
struct NingxCachedOpenfile {
//...其他属性 忽略
int fd; //文件描述符
NingxQueueNode QueueNode;//队列结点
};
int main(void) {
NingxQueue Queue;
NingxQueueInit(Queue);
NingxQueueNode* p = nullptr;
const size_t &Size = NingxQueueSize(Queue);
cout << "NingxQueueSize :" << Size << endl;
for (size_t i = 0; i < 10; i++){
NingxCachedOpenfile* e = new NingxCachedOpenfile;
e->fd = i + 1;
NingxQueueInsertFroot(Queue, &e->QueueNode);
}
cout << "NingxQueueSize :" << Size << endl;
for (p = Queue.List->next; p != isEnd(Queue.List); p = p->next) {
NingxCachedOpenfile* CachedOpenfile = NingxQueueElement(p, NingxCachedOpenfile, QueueNode);
cout << "fd = " << CachedOpenfile->fd << endl;
}
while (NingxQueueEmpty(Queue)){
p = NingxQueueLast(Queue);
NingxCachedOpenfile* CachedOpenfile = NingxQueueElement(p, NingxCachedOpenfile, QueueNode);
cout << "fd = " << CachedOpenfile->fd << endl;
NingxQueueDelete(Queue,p);
delete CachedOpenfile;
}
cout << "NingxQueueSize :" << Size << endl;
NingxQueueDestroy(Queue);
return 0;
}