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类型仿函数,因此最终结果就是小堆,当然通过如下方法可以修改为大大堆排列。


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

相关推荐
布茹 ei ai几秒前
QtWeatherApp - 简单天气预报软件(C++ Qt6)(附源码)
开发语言·c++·qt·开源·开源项目·天气预报
Bruce_kaizy几秒前
c++图论————图的基本与遍历
c++·算法·图论
Zmm147258369_2 分钟前
好用的PC耐力板机构
c++
Code Slacker31 分钟前
LeetCode Hot100 —— 普通数组(面试纯背版)(五)
数据结构·c++·算法·leetcode·面试
秦苒&42 分钟前
【C语言】详解数据类型和变量(一):数据类型介绍、 signed和unsigned、数据类型的取值范围、变量、强制类型转换
c语言·开发语言·c++·c#
智者知已应修善业1 小时前
【删除有序数组中的重复项 II之O(N)算法】2024-1-31
c语言·c++·经验分享·笔记·算法
爱装代码的小瓶子1 小时前
【c++进阶】C++11新特性:一切皆可{}初始化
开发语言·c++·visual studio
xiaoye-duck1 小时前
吃透C++类和对象(中):构造函数与析构函数深度解析
c++
AA陈超1 小时前
Lyra Starter Game 中 GameFeature 类(如 ShooterCore)的加载流程
c++·笔记·学习·ue5·虚幻引擎
加成BUFF2 小时前
C++入门讲解3:数组与指针全面详解
开发语言·c++·算法·指针·数组