stack&queue

一、栈和队列

以上是栈、队列以及优先级队列的常见接口,但在优先级队列中一般默认是大的数据优先级高,优先访问。

二、栈的实现

在cpp标准库中,stack是一个模板类,stack本身并不是直接管理数据,而是通过适配器模式将其他容器作为其底层存储机制,在默认情况下其使用的是deque(双端队列)作为其底层容器,当然也可以使用其他容器作为其底层容器。如下图所示简介一下deque的方法。


栈的代码实现

cpp 复制代码
#include <iostream>
using namespace std;
#include <deque>

namespace asy {
	template<class T,class Container=deque<T>>
	class myStack {
	public:
		void push(const T& val) {
			_con.push_back(val);
		}
		bool empty() {
			return _con.empty();
		}
		const T& top() {
			return _con.back();
		}
		//栈:先进后出,栈顶先出
		void pop() {
			_con.pop_back();
		}

		size_t size(){
			return _con.size();
		}
	private:
		Container _con;
	};

	void fun1() {
		myStack<int> s1;
		s1.push(1);
		s1.push(2);
		s1.push(3);
		s1.push(4);
		while (!s1.empty()) {
			cout << s1.top() << " ";
			s1.pop();
		}
		cout << endl;
	}
}

如上图,通过底层使用deque实现了与stack相同的行为。在这里如果不直接说明则底层是deque,也可以通过vector实现,如下图

三、队列的实现

这里队列的实现依然是使用deque作为底层(默认情况下),也可以指定其他容器作为底层实现。

cpp 复制代码
#pragma once

#include <iostream>
using namespace std;
#include <deque>

namespace asy {
	template<class T, class Container = deque<T>>
	class queue {
	public:
		void push(const T& val) {
			_con.push_back(val);
		}
		const T& top() {
			return _con.front();
		}

		const T& back() {
			return _con.back();
		}

		void pop() {
			_con.pop_front();
		}

		bool empty() {
			return _con.empty();
		}

		size_t size() {
			return _con.size();
		}

	private:
		Container _con;
	};

	void test1() {
		queue<int> q1;
		q1.push(1);
		q1.push(2);
		q1.push(3);
		q1.push(4);
		while (!q1.empty()) {
			cout << q1.top() << " ";
			q1.pop();
		}
		cout << endl;
	}
}

四、仿函数

在学习优先级队列实现之前先了解什么是仿函数。在cpp中仿函数是指那些重载了()运算符的对象,仿函数本质上是一个像函数一样被调用的类或对象,通过重载operator()运算符实现。

cpp 复制代码
namespace category {
	struct less {
		bool operator()(int x, int y) {
			return x < y;
		}
	};

	struct gerater {
		bool operator()(int x, int y) {
			return x > y;
		}
	};
    
    struct add {
		int operator()(int x,int y) {
			return x + y;
		}
	};
}

如上所示,在命名空间category中定义一个结构体,在结构体中重载operator()运算符,此时less和greater和add就是类型(就像int一样)。

如上图,仿函数的使用类似定义一个less类型的函数,然后将数据放在这个函数里面。那么如何将仿函数支持泛型的比较呢?这里就需要仿函数支持模板。如下图所示。

五、优先级队列

cpp 复制代码
template<class T,class Container=vector<T>>
class priority_queue {
public:

	void AdjustUp(int child) {
		int parent = (child - 1) / 2;
		while (child > 0) {
			if (_con[child] < _con[parent]) {
				swap(_con[child], _con[parent]);
				child = parent;
				parent = (child - 1) / 2;
			}
			else {
				break;
			}
		}
	}

	void AdjustDown(int parent) {
		int child = parent * 2 + 1;
		if (child + 1 < _con.size() && _con[child + 1] < _con[child]) {
			child++;
		}
		if (_con[child] < _con[parent]) {
			swap(_con[child], _con[parent]);
			parent = child;
			child = parent * 2 + 1;
		}
		else {
			break;
		}
	}

	void push(const T& val) {
		_con.push_back(val);
		AdjustUp(_con.size() - 1);
	}

	void pop() {
		assert(_con, empty());
		swap(0, _con.size() - 1);
		_con.pop_back();
		AdjustDown(0);
	}

	const T& top() {
		return _con.front();
	}

	size_t size() {
		return _con.size();
	}

	bool empty() {
		return _con.empty();
	}

private:
	Container _con;
};

如上图所示,每次push数据时都会调用向上调整算法以及每次pop数据时调用向下调整算法使得整个队列保持小堆的形态。

如上图,将仿函数的使用应用到调整算法中。

代码结果如上图所示,在代码77行默认的是less类型仿函数,因此最终结果就是小堆,当然通过如下方法可以修改为大大堆排列。


也可以这样指定仿函数类型:

相关推荐
AA陈超6 分钟前
虚幻引擎UE5专用服务器游戏开发-20 添加基础能力类与连招能力
c++·游戏·ue5·游戏引擎·虚幻
mit6.82427 分钟前
[Meetily后端框架] AI摘要结构化 | `SummaryResponse`模型 | Pydantic库 | vs marshmallow库
c++·人工智能·后端
R-G-B34 分钟前
【02】MFC入门到精通——MFC 手动添加创建新的对话框模板
c++·mfc·mfc 手动添加创建新的对话框
linux kernel1 小时前
第七讲:C++中的string类
开发语言·c++
Tipriest_1 小时前
[数据结构与算法] 优先队列 | 最小堆 C++
c++·优先队列·数据结构与算法·最小堆
宛西南浪漫戈命1 小时前
Centos 7下使用C++使用Rdkafka库实现生产者消费者
c++·centos·linq
帅_shuai_3 小时前
C++ 模板参数展开
c++
chilavert3183 小时前
技术演进中的开发沉思-30 MFC系列:五大机制
c++·windows
七七七七073 小时前
C++类对象多态底层原理及扩展问题
开发语言·c++
雨落倾城夏未凉4 小时前
8.Qt文件操作
c++·后端·qt