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


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

相关推荐
LXS_3571 天前
Day 18 C++提高 之 STL常用容器(string、vector、deque)
开发语言·c++·笔记·学习方法·改行学it
deng-c-f1 天前
Linux C/C++ 学习日记(53):原子操作(二):实现shared_ptr
开发语言·c++·学习
一个不知名程序员www1 天前
算法学习入门---结构体和类(C++)
c++·算法
墨雪不会编程1 天前
C++ string 详解:STL 字符串容器的使用技巧
java·开发语言·c++
yangpipi-1 天前
《C++并发编程实战》第5章 C++内存模型和原子操作
android·java·c++
SunkingYang1 天前
MFC进程间消息通信深度解析:SendMessage、PostMessage与SendNotifyMessage的底层实现与实战指南
c++·mfc·共享内存·通信·postmessage·sendmessage·进程间
XFF不秃头1 天前
力扣刷题笔记-旋转图像
c++·笔记·算法·leetcode
王老师青少年编程1 天前
csp信奥赛C++标准模板库STL案例应用3
c++·算法·stl·csp·信奥赛·lower_bound·标准模版库
Tim_101 天前
【C++入门】04、C++浮点型
开发语言·c++
hkNaruto1 天前
【C++】记录一次C++程序编译缓慢原因分析——滥用stdafx.h公共头文件
开发语言·c++