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;
}
相关推荐
筱璦2 小时前
C#期货分仓、策略交易模拟演示系统(含资源下载)
开发语言·c#·策略模式·量化交易·期货交易
froginwe112 小时前
Highcharts 测量图:全面解析与优化实践
开发语言
雪芽蓝域zzs2 小时前
uni-app x 使用 UTS 语言使用 mixins
开发语言·javascript·uni-app
郝学胜-神的一滴2 小时前
[力扣 105]二叉树前中后序遍历精讲:原理、实现与二叉树还原
数据结构·c++·算法·leetcode·职场和发展
DaqunChen2 小时前
全栈开发的演变:从LAMP到MEAN再到现代JavaScript
开发语言·javascript·ecmascript
闻缺陷则喜何志丹2 小时前
【ST表 前缀和】P7809 [JRKSJ R2] 01 序列|普及+
c++·算法·前缀和·洛谷·st表
Fate_I_C2 小时前
Kotlin 特有语法糖
android·开发语言·kotlin
xh didida2 小时前
C++ --list接口使用及实现
开发语言·c++·list