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


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

相关推荐
Growthofnotes几秒前
C++—14、C++ 中的指针最基础的原理
开发语言·c++
bohu8321 分钟前
ros2笔记-4.3 用C++做一个巡逻海龟
c++·笔记·ros2·服务通信
F-2H2 小时前
C语言:构造类型(共用体/联合体,枚举)
java·linux·c语言·开发语言·数据结构·c++·算法
qq762118222 小时前
ffmpeg7.0 aac转pcm
c++·pcm·aac
秋知叶i4 小时前
【轻松学C:编程小白的大冒险】--- 选择 开发工具(IDE)Dev-c++ 03
c语言·开发语言·c++
daily_23334 小时前
c++领域展开第十幕——类和对象(内存管理——c/c++内存分布、c++内存管理方式、new/delete与malloc/free区别)超详细!!!!
c语言·c++
就叫飞六吧4 小时前
C语言中,`extern` 和 `#include`
c语言·c++·算法
涛ing5 小时前
12. C语言 数组与指针(深入理解)
linux·c语言·开发语言·数据结构·c++·算法·ubuntu
黑果果的思考7 小时前
C++例程:使用I/O模拟IIC接口(6)
开发语言·c++