stack和queue --->容器适配器

不支持迭代器,迭代器无法满足他们的性质

边出边判断

实现

复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<stack>
#include<queue>
using namespace std;
int main()
{
	stack<int> st;
	st.push(1);
	st.push(2);
	st.push(3);
	st.push(4);

	while (!st.empty())
	{
		cout << st.top() << " ";
		st.pop();
	}
	cout << endl;
}

//用适配器的方式实现栈

cpp 复制代码
//Stack.h

#pragma once
#include<vector>
#include<list>
//模板
//template<class T>
//class stack
//{
//	T* _a;
//	size_t _top;
//	size_t _capacity;
//};

//传什么就是什么
//stack<int,vector<int>> s1;
//stack<int,list<int>> s1;

namespace DD
{
//加上模板的方式
    template<class T, class Container>
	class stack
	{
	public:
		void push(const T& x)//入栈
		{
			_con.push_back(x);
		}
		void pop()//出栈
		{
			_con.pop_back();
		}
		const T& top() const//取栈顶元素
		{
			return _con.back();
		}
		size_t size()const//size
		{
			return _con.size();
		}
		bool empty() const//判空
		{
			return _con.empty();
		}
	private:
		Container _con;
	};
}
cpp 复制代码
//Test.cpp

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<stack>
#include<queue>
using namespace std;
#include"Stack.h"
int main()
{
    //显示传一个容器
	//DD::stack<int,vector<int>> st;//实现的数组栈
	DD::stack<int,list<int>> st;//实现链式栈
	st.push(1);
	st.push(2);
	st.push(3);
	st.push(4);

	while (!st.empty())
	{
		cout << st.top() << " ";
		st.pop();
	}
	cout << endl;
	return 0;
}
//4 3 2 1

//也可以是缺省的

cpp 复制代码
 template<class T, class Container=vector<int>>
cpp 复制代码
//也可以是缺省的
DD::stack<int>st;

//4 3 2 1

//用适配器的方式实现队列

cpp 复制代码
//Queue.h

#pragma once
#include<vector>
#include<list>
#include<deque>

namespace DD
{
	template<class T, class Container = deque<T>>
	class queue
	{
	public:
		void push(const T& x)
		{
			_con.push_back(x);//尾插
		}

		void pop()
		{
			_con.pop_front();//头出
		}

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

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

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

		bool empty() const
		{
			return _con.empty();
		}
	private:
		Container _con;
	};
}
cpp 复制代码
//Test.cpp

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<stack>
#include<queue>
using namespace std;
#include"Queue.h"//.h是用来展开的
int main()
{
	//DD::queue<int>q;     //1 2 3 4
	//DD::queue<int, list<int>>q;  //1 2 3 4

	DD::queue<int, vector<int>>q;//不支持,会报错
	
	q.push(1);
	q.push(2);
	q.push(3);
	q.push(4);
	while (!q.empty())//队列不为空取队头数据
	{
		cout << q.front() << " ";
		q.pop();
	}
	cout << endl;
	return 0;
}

deque的介绍

deque(双端队列):是一种双开口的"连续"空间的数据结果,双开口的含义是:可以在头尾两端进行插入和删除操作,并且数据复杂度为O(1)

vector 插入数据需要扩容,与vector比较,头插效率高,不需要搬移元素

list不支持随机访问

与list相比其底层是连续空间,空间利用率比较高,不需要存储额外字段

deque并不是真正连续的空间,而是由一段连续的小空间拼接而成,实际deque类似于一个动态的二维数组

为什么选择deque(核心是迭代器支撑的)作为stack和queue的底层默认容器

stack是一种先进后出的特殊线性结构,因此只要具有push_back()和pop_back()操作的线性结构都可以作为stack的底层容器,vector和list都可以

queue是先进先出的特殊线性数据结构,只要具有push_back()和pop_front()操作的线性结构都可以作为queue的底层容器,比如list

STL中对stack和queue默认选择dequeu作为其底层容器主要是因为

1)stack和queue不需要遍历(没有迭代器),只需要在固定的一端或者两端进行操作

2)在stack中元素增长时,deque比vector的效率高,不需要挪动数据,;queue中的元素增长时,deque不仅效率高,而且内存使用率高

结合了deque的缺点,完美地避开了他的缺点

deque借助其迭代器维护其假想连续的结构的方式

头插和尾插

priority_queue的模拟实现

通过对priority_queue的底层结构是堆,依次此处秩序堆堆进行通用的封装即可

cpp 复制代码
//PriorityQueue.h

#pragma once
#include<vector>
namespace DD
{
	//默认用vector适配
	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 = (parent - 1) / 2;
				}
				else
				{
					break;
				}
			}
		}
		//优先级队列的插入
		void push(const T& x)
		{
			//要向上调整
			_con.push_back(x);
			AdjustUp(_con.size() - 1);//size是最后一个数据的下一个位置
		}

		void AdjustDown(int parent)
		{
			size_t child = parent * 2 + 1;
			while (child < _con.size())
			{
				// 假设法,选出左右孩子中小的那个孩子
				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 pop()
		{
			//直接交换堆顶的数据和最后一个数据
			swap(_con[0], _con[_con.size() - 1]);
			_con.pop_back();
			//从根位置向下调整
			AdjustDown(0);
		}
		//判空
		bool empty()
		{
			return _con.empty();
		}

		const T& top()
		{
			return _con[0];//返回堆顶位置的数据就是根位置的数据
		}

		size_t size()
		{
			return _con.size();
		}
	private:
		Container _con;
	};
}
cpp 复制代码
//Test.cpp

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<stack>
#include<queue>
using namespace std;
#include"Stack.h"
#include"Queue.h"//.h是用来展开的

#include"PriorityQueue.h"
int main()
{
	//默认是大的优先级高
	DD::priority_queue<int>pq;
	//4 3 2 1

	//可以改成小的优先级高
	//priority_queue<int,vector<int>,greater<int>>pq;
	//1 2 3 4

	pq.push(4);
	pq.push(2);
	pq.push(1);
	pq.push(3);

	while (!pq.empty())
	{
		cout << pq.top() << " ";
		pq.pop();
	}
	cout << endl;
	return 0;
}

//我们是小堆 所以是 1 2 3 4

优先级队列还支持迭代器区间构造

cpp 复制代码
//PoriorityQueue.h

#pragma once
#include<vector>
namespace DD
{
	//默认用vector适配
	template<class T,class Container=vector<T>>
	class priority_queue
	{
	public:
		//我们不写编译器会自动生成,自动生成会调用Container _con的默认构造
		//强制生成默认构造
		priority_queue() = default;
		template <class InputIterator>
		priority_queue(InputIterator first, InputIterator last)
			:_con(first, last)
		{
			//建堆
			//从最后一个结点的叶子结点开始,叶子结点不需要我们建,所以建倒着走的第一个非叶子结点,他是最后一个结点的父亲
			for (int i = (_con.size() - 1 - 1) / 2; i >= 0; i--);//_con.size()-1是最后一个叶子结点的下标
			{
				AdjustDown(i);
			}

		}
			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 = (parent - 1) / 2;
				}
				else
				{
					break;
				}
			}
		}
		//优先级队列的插入
		void push(const T& x)
		{
			//要向上调整
			_con.push_back(x);
			AdjustUp(_con.size() - 1);//size是最后一个数据的下一个位置
		}

		void AdjustDown(int parent)
		{
			size_t child = parent * 2 + 1;
			while (child < _con.size())
			{
				// 假设法,选出左右孩子中小的那个孩子
				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 pop()
		{
			//直接交换堆顶的数据和最后一个数据
			swap(_con[0], _con[_con.size() - 1]);
			_con.pop_back();
			//从根位置向下调整
			AdjustDown(0);
		}
		//判空
		bool empty()
		{
			return _con.empty();
		}

		const T& top()
		{
			return _con[0];//返回堆顶位置的数据就是根位置的数据
		}

		size_t size()
		{
			return _con.size();
		}
	private:
		Container _con;
	};
}
cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
#include"PriorityQueue.h"
int main()
{
//迭代器区间可以是我们容器的,也可以是指向数组的指针
  int a[] = { 1,4,2,5,6,3,2 };
  DD::priority_queue<int>pq1(a, a + sizeof(a) / sizeof(int));

仿函数

cpp 复制代码
//仿函数
//仿函数是一个类
//这个类型的对象可以像函数一样使用,因为重载了operator()
template<class T>
struct Less
{
	//重载了opertor()
	bool operator()(const T& x, const T& y)const
	{
		return x < y;
	}
};
int main()
{
	//lessFunc是这个类型的对象
	Less<int>lessFunc;
	cout << lessFunc(1, 2) << endl;
	cout << lessFunc.operator()(1, 2) << endl;//本质是调用operator()

}

//1
//1

外:

仿函数可以用来建堆,以及日期类的比较

传小于是大堆

多参数构造函数支持隐式类型转换

我们默认没传是大堆

cpp 复制代码
sort(aq1.begin(),dq1.end(),less<int>());  //是函数对应的参数,要加()

priority_queue<int,vector<int>,less<int>> pq;   //是类对应的参数,不加()
相关推荐
皮卡蛋炒饭.几秒前
宽搜bfs与深搜dfs
算法·宽度优先
yuuki2332334 分钟前
【C++】掌握list:C++链表容器的核心奥秘
c++·后端·链表·list
Coder_Boy_5 分钟前
基于SpringAI的智能AIOps项目:部署相关容器化部署管理技术图解版
人工智能·spring boot·算法·贪心算法·aiops
王哈哈^_^6 分钟前
【完整源码+数据集】道路拥塞数据集,yolo道路拥塞检测数据集 8921 张,交通拥堵识别数据集,路口拥塞识别系统实战教程
深度学习·算法·yolo·目标检测·计算机视觉·分类·毕业设计
Chen不旧7 分钟前
Java模拟死锁
java·开发语言·synchronized·reentrantlock·死锁
菩提树下的凡夫16 分钟前
如何将python的程序py文件转换为exe程序
开发语言·python
萧曵 丶18 分钟前
Java 安全的单例模式详解
java·开发语言·单例模式
leoufung23 分钟前
LeetCode 64. Minimum Path Sum 动态规划详解
算法·leetcode·动态规划
superman超哥23 分钟前
Rust 错误处理模式:Result、?运算符与 anyhow 的最佳实践
开发语言·后端·rust·运算符·anyhow·rust 错误处理
lly20240624 分钟前
Web 品质样式表
开发语言