数据结构算法-队列技术点

基本描述

排队,做核酸这些大家都有吧, 学校打饭是不是按照队伍的形式来 打饭?
在这里插入图片描述

队列原理精讲

队列:是一个先进先出 的一种数据结构,
队列:受限线性结构;
队列::只允许前面出队后面入队
在这里插入图片描述
出队的时候有两种方法:
物理删除,逻辑删除
所谓的物理删除 该怎么删除就这么删除
逻辑删除:不去直接删除 而是直接访问下一个元素 所谓的:忽略 不去直接删除 好处 避免了大量的移动 效率高

队列的算法实现:

顺序队列

顺序队列:用顺序结构来做的队列 效果如上

初始化队列
尾部添加元素(往后添加)
头部删除元素(逻辑删除)
访问队头
访问队尾
获取队列元素个数

顺序队列:
//元素类型
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;
}
  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小森程序员

若能帮助到你,小费自愿付费

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值