C++ 容器适配器揭秘:stack, queue 和 priority_queue 的模拟实现

stack和queue的模拟实现并不复杂,所以不做过多讲解。

一、stack的模拟实现

. stack.h

cpp 复制代码
#pragma once
#include<iostream>
#include<vector>
using namespace std;

namespace LC
{
	template<class T, class Container = vector<T>>
	class stack
	{
	public:
		void push(const T& x)
		{
			_con.push_back(x);
		}
		const T& top()
		{
			return _con.back();
		}
		void pop()
		{
			_con.pop_back();
		}
		bool empty()
		{
			return _con.empty();
		}
		size_t size()const
		{
			return _con.size();
		}
	private:
		Container _con;
	};
}

. test.cc

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS
#include"stack.h"
int main()
{
	LC::stack<int> s1;

	s1.push(1);
	s1.push(2);
	s1.push(3);
	s1.push(4);
	s1.push(5);

	cout << "s1.size():" << s1.size() << endl;
	while (!s1.empty())
	{
		cout << s1.top() << " ";
		s1.pop();
	}

	cout << endl;

	LC::stack<double> s2;
	s2.push(1.1);
	s2.push(2.2);
	s2.push(3.3);
	s2.push(4.4);
	s2.push(5.5);

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

二、queue的模拟实现

. queue.h

cpp 复制代码
#pragma once

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

namespace LC
{
	template<class T, class Container = list<T>>
	class queue
	{
	public:
		void push(const T& x)
		{
			_con.push_back(x);
		}
		bool empty()
		{
			return _con.empty();
		}
		size_t size()const
		{
			return _con.size();
		}
		const T& front()
		{
			return _con.front();
		}
		const T& back()
		{
			return _con.back();
		}
		void pop()
		{
			_con.pop_front();``
		}
	private:
		Container _con;
	};
}

. test.cc

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS
#include"queue.h"
int main()
{
	LC::queue<double> q1;
	q1.push(1);
	q1.push(2);
	q1.push(3);
	q1.push(4);
	q1.push(5);
	/*q1.push(1.1);
	q1.push(2.2);
	q1.push(3.3);
	q1.push(4.4);
	q1.push(5.5);*/
	cout << "q1.size():" << q1.size() << endl;
	while (!q1.empty())
	{
		cout << q1.front() << " ";
		q1.pop();
	}
	return 0;
}

三、priority_queue

优先级队列是一种容器适配器,特别设计为其首个元素始终是所包含元素中最大的一个,基于某种严格的弱排序准则

1. 构造函数

cpp 复制代码
//传入一个仿函数对象和容器对象
explicit priority_queue (const Compare& comp = Compare(),const Container& ctnr = Container());
//在传入仿函数对象和容器对象的基础上增加了一段迭代器区间
template <class InputIterator>
priority_queue (InputIterator first, InputIterator last,const Compare& comp = Compare(),const Container& ctnr = Container());

2. empty

cpp 复制代码
//判断优先级队列是否为空
bool empty() const;

3. size

cpp 复制代码
//返回优先级队列中元素的个数
size_type size() const;

4. top

cpp 复制代码
//返回的是priority_queue中优先级最高的元素
const value_type& top() const;

5. push

cpp 复制代码
//插入一个新的元素,并调用push_heap算法进行重新排序
void push (const value_type& val);

6. pop

cpp 复制代码
//删除priority_queue中优先级最高的元素
void pop();

7. swap

cpp 复制代码
//交换两个priority_queue对象的内容
void swap (priority_queue& x) noexcept

四、priority_queue的模拟实现

1. 仿函数

cpp 复制代码
//按降序排序
template<class T>
class Less
{
public:
	bool operator()(const T& x, const T& y)
	{
		return x < y;
	}
};
//按升序排序
template<class T>
class Greater
{
public:
	bool operator()(const T& x, const T& y)
	{
		return x > y;
	}
};

2. 成员变量

cpp 复制代码
template<class T, class Container = vector<T>, class Compare = Less<T>>
class priority_queue
{
private:
	Container _con;
};

3. push

cpp 复制代码
void push(const T& x)
{
	_con.push_back(x);
	adjust_up(_con.size() - 1);//调整优先级
}

4. adjust_up

cpp 复制代码
void adjust_up(size_t child)
{
	Compare _com;
	size_t parent = (child - 1) / 2;
	while (child > 0)
	{
		//if (_con[child] > _con[parent])
		if (_com(_con[parent], _con[child]))
		{
			swap(_con[child], _con[parent]);
			child = parent;
			parent = (child - 1) / 2;
		}
		else
		{
			break;
		}
	}
}

向上调整,将优先级最大的元素排在队首,利用父子节点的下标关系,比较父子之间的大小,孩子大于(或小于)父亲,孩子往上调整,父亲往下走(交换孩子与父亲的数据),继续下一次判断。_com是仿函数对象,主要是为了便于控制升序,降序

5. pop

cpp 复制代码
void pop()
{
	swap(_con[0], _con[size() - 1]);
	_con.pop_back();
	adjust_down(0);
}

删除数据,首先将删除的队首数据调整到队尾,再删除数据,接着向下调整优先级

6. adjust_down

cpp 复制代码
void adjust_down(size_t parent)
{
	Compare _com;
	size_t child = 2 * parent + 1;
	while (child < size())
	{
		//if (child + 1 < size() && _con[child + 1] > _con[child])
		if (child + 1 < size() && _com(_con[child], _con[child + 1]))
		{
			++child;
		}
		if (_com(_con[parent], _con[child]))
		{
			swap(_con[child], _con[parent]);
			parent = child;
			child = 2 * parent + 1;
		}
		else
		{
			break;
		}
	}
}

如果右孩子大于左孩子,下标指向右孩子,接着判断孩子是否大于(或小于)父亲,符合条件,交换数据,继续调整,否则,调整完毕,退出循环

7. top,size,empty

cpp 复制代码
const T& top()
{
	return _con[0];
}
size_t size()
{
	return _con.size();
}
bool empty()
{
	return _con.empty();
}

优先级队列的底层结构是堆,所以,这里不做过多讲解,如果还有疑问的话,可以看数据结构------树这篇文章,有更详细的讲解。

五、priority_queue的完整代码

. priority_queue.h

cpp 复制代码
#pragma once
#include<iostream>
#include<vector>
using namespace std;

namespace LC
{
	template<class T>
	class Less
	{
	public:
		bool operator()(const T& x, const T& y)
		{
			return x < y;
		}
	};

	template<class T>
	class Greater
	{
	public:
		bool operator()(const T& x, const T& y)
		{
			return x > y;
		}
	};
	template<class T, class Container = vector<T>, class Compare = Less<T>>
	class priority_queue
	{
	public:
		void adjust_up(size_t child)
		{
			Compare _com;
			size_t parent = (child - 1) / 2;
			while (child > 0)
			{
				//if (_con[child] > _con[parent])
				if (_com(_con[parent], _con[child]))
				{
					swap(_con[child], _con[parent]);
					child = parent;
					parent = (child - 1) / 2;
				}
				else
				{
					break;
				}
			}
		}
		void push(const T& x)
		{
			_con.push_back(x);
			adjust_up(_con.size() - 1);
		}
		void adjust_down(size_t parent)
		{
			Compare _com;
			size_t child = 2 * parent + 1;
			while (child < size())
			{
				//if (child + 1 < size() && _con[child + 1] > _con[child])
				if (child + 1 < size() && _com(_con[child], _con[child + 1]))
				{
					++child;
				}
				if (_com(_con[parent], _con[child]))
				{
					swap(_con[child], _con[parent]);
					parent = child;
					child = 2 * parent + 1;
				}
				else
				{
					break;
				}
			}
		}
		void pop()
		{
			swap(_con[0], _con[size() - 1]);
			_con.pop_back();
			adjust_down(0);
		}
		const T& top()
		{
			return _con[0];
		}
		size_t size()
		{
			return _con.size();
		}
		bool empty()
		{
			return _con.empty();
		}
	private:
		Container _con;
	};
}

. test.cc

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS

#include"priority_queue.h"

void testpriority_queue1()
{
	LC::priority_queue<int, vector<int>, LC::Less<int>> q1;
	q1.push(1);
	q1.push(4);
	q1.push(2);
	q1.push(7);
	q1.push(6);
	cout << typeid(q1).name() << endl;
	cout << "q1.size():" << q1.size() << endl;
	while (!q1.empty())
	{
		cout << q1.top() << " ";
		q1.pop();
	}
}
int main()
{
	testpriority_queue1();

	return 0;
}
相关推荐
辞旧 lekkk6 小时前
【Qt】信号和槽
linux·开发语言·数据库·qt·学习·mysql·萌新
2zcode6 小时前
运动模糊图像复原的MATLAB仿真与优化
开发语言·matlab
袁雅倩19976 小时前
当吸尘器、筋膜枪都用上Type-C,供电方案该怎么选?浅谈PD取电芯片ECP5702的应用
c语言·开发语言·支持向量机·动态规划·推荐算法·最小二乘法·图搜索算法
Aaswk7 小时前
Java Lambda 表达式与流处理
java·开发语言·python
万邦科技Lafite8 小时前
京东item_get接口实战案例:实时商品价格监控全流程解析
java·开发语言·数据库·python·开放api·淘宝开放平台
王老师青少年编程8 小时前
csp信奥赛C++高频考点专项训练之字符串 --【子串查找】:[NOIP 2009 提高组] 潜伏者
c++·字符串·csp·高频考点·信奥赛·子串查找·潜伏者
Cyber4K9 小时前
【Python专项】进阶语法-系统资源监控与数据采集(1)
开发语言·python·php
初願致夕霞9 小时前
基于系统调用的Linux网络编程——UDP与TCP
linux·网络·c++·tcp/ip·udp
Le_ee9 小时前
ctfweb:php/php短标签/.haccess+图片马/XXE
开发语言·前端·php
yong999010 小时前
MATLAB读取高光谱图像
开发语言·matlab