priority_queue 优先级队列(堆) 的模拟实现

目录

一、优先级队列的模板参数列表

二、优先级队列的构造函数(建堆 nlogn)

AdjustDown() 向下调整:

建堆的时间复杂度:

三、pop()接口 (堆顶元素的删除: logn)

四、push()接口 (logn)

AdjustUp() 向下调整:

五、其他函数

六、源码及测试:


priority_queue 的本质就是堆,以下来介绍优先级队列的模拟实现

一、优先级队列的模板参数列表

 定义优先级队列类,模板参数分别为存入元素的类型T,

                                存放元素的底层结构默认使用std命名空间中的vector<T>、

                                以及比较方式less<T>,也给出了less类、以及Greater类

template<class T>
	class less
	{
	public:
		bool operator()(const T& left, const T& right)const
		{
			return left < right;
		}
	};
	template<class T>
	class Greater
	{
	public:
		bool operator()(const T& left, const T& right)const
		{
			return left > right;
		}
	};
	template <class T, class Contioner = std::vector<T>, class Compare = less<T>>
    class priority_queue
    {
    
    };

二、优先级队列的构造函数(建堆 时间复杂度为nlogn

这一步最重要的就是建堆,具体思路就是从优先级队列(堆)的第一个非叶子结点开始来进行向下调整,直到将顶点元素也完成向下调整。

首先利用类中对数组(默认Container使用vector<T>)_con中的vector的区间构造函数来对_con进行初始化。

然后对从第一个非叶子结点的位置进行向下调整直到将堆顶元素也进行向下调整为止。

    class priority_queue
	{
	public:
		priority_queue()
		{}

		template<class Iterator>
		priority_queue(Iterator first, Iterator last)
			: _con(first, last) // 1、使用vector的区间构造函数来初始化_con
		{
			// 2、建堆:从完全二叉树的最后一个非叶子结点来进行向下调整
			for (int i = (size() - 2) / 2; i >= 0; i--)
			{
				AdjustDown(i);
			}
		}
     private:
         Container _con;
    };

AdjustDown() 向下调整:

        在parent的右孩子存在的条件下,选择俩个孩子中较大的那个来进行与parent的比较,如果parent位置元素小于child位置元素,就进行交换,parent和child都不断向下更新重复判断,直到parent大于child或者child超出访问范围。

建堆的时间复杂度:

        为向下调整的时间复杂度logn * 遍历元素的n 即为 nlogn

        private:
		void AdjustDown(int parent)
		{
			size_t sz = size();
			int child = 2 * parent - 1;
			Compare com;
			while (child < sz)
			{
				// 如果左孩子存在  且  左孩子小于右孩子  就将child进行更新
				if (child + 1 < sz && com(_con[child], _con[child + 1]))
					child += 1;
				if (com(_con[parent], _con[child]))
				{
					std::swap(_con[parent], _con[child]);
					parent = child;
					child = parent * 2 - 1;
				}
				else
					return;
			}
		}

三、pop()接口 (堆顶元素的删除: logn)

即为固定的3步走:看下方代码即可。

        void pop()
		{
			// 1、将堆顶元素与最后一个元素进行位置交换
			std::swap(_con[0], _con[size() - 1]);

			// 2、将换到最后一个位置的堆顶元素进行尾删
			_con.pop_back();

			// 3、将新的堆顶元素进行向下调整
			AdjustDown(0);
		}

四、push()接口 (logn)

将待插入元素尾插进_con,然后对该元素进行向上调整即可

        void push(T val)
		{
			// 1、将代插入的元素进行尾部插入
			_con.push_back(val);

			// 2、将该元素进行向上调整
			AdjustUp();
		}

AdjustUp() 向下调整:

        void AdjustDown(size_t parent)
		{
			size_t sz = size();
			size_t child = 2 * parent + 1;
			Compare com;
			while (child < sz)
			{
				// 如果左孩子存在  且  左孩子小于右孩子  就将child进行更新
				if (child + 1 < sz && com(_con[child], _con[child + 1]))
					child += 1;
				if (com(_con[parent], _con[child]))
				{
					std::swap(_con[parent], _con[child]);
					parent = child;
					child = parent * 2 + 1;
				}
				else
					return;
			}
		}

五、其他函数

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

		const T& top()const
		{
			return _con[0];
		}

		bool empty()const
		{
			return _con.empty();
		}

六、源码及测试:

#include<iostream>
#include<vector>
using namespace std;
namespace wei
{
	template<class T>
	class less
	{
	public:
		bool operator()(const T& left, const T& right)const
		{
			return left < right;
		}
	};
	template<class T>
	class Greater
	{
	public:
		bool operator()(const T& left, const T& right)const
		{
			return left > right;
		}
	};
	template <class T, class Contioner = std::vector<T>, class Compare = less<T>>
	class priority_queue
	{
	public:
		priority_queue()
		{}

		template<class Iterator>
		priority_queue(Iterator first, Iterator last)
			: _con(first, last) // 1、使用vector的区间构造函数来初始化_con
		{
			// 2、建堆:从完全二叉树的最后一个非叶子结点来进行向下调整
			for (int i = (size() - 2) / 2; i >= 0; i--)
			{
				AdjustDown(i);
			}
		}

		void push(T val)
		{
			// 1、将代插入的元素进行尾部插入
			_con.push_back(val);

			// 2、将该元素进行向上调整
			AdjustUp();
		}

		void pop()
		{
			if (empty())
				return;
			// 1、将堆顶元素与最后一个元素进行位置交换
			std::swap(_con[0], _con[size() - 1]);

			// 2、将换到最后一个位置的堆顶元素进行尾删
			_con.pop_back();

			// 3、将新的堆顶元素进行向下调整
			AdjustDown(0);
		}

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

		const T& top()const
		{
			return _con[0];
		}

		bool empty()const
		{
			return _con.empty();
		}
	private:
		void AdjustDown(size_t parent)
		{
			size_t sz = size();
			size_t child = 2 * parent + 1;
			Compare com;
			while (child < sz)
			{
				// 如果左孩子存在  且  左孩子小于右孩子  就将child进行更新
				if (child + 1 < sz && com(_con[child], _con[child + 1]))
					child += 1;
				if (com(_con[parent], _con[child]))
				{
					std::swap(_con[parent], _con[child]);
					parent = child;
					child = parent * 2 + 1;
				}
				else
					return;
			}
		}
		void AdjustUp()
		{
			size_t child = size() - 1;
			Compare com;
			size_t parent = (child - 1) / 2;
			while (child)
			{
				if (com(_con[parent], _con[child]))
				{
					std::swap(_con[parent], _con[child]);
					child = parent;
					parent = (child - 1) / 2;
				}
				else
					return;
			}
		}
	private:
		Contioner _con;
	};
}

void TestMyPriority_queue1()
{
	int array[] = { 1,2,3,4,5,6,7,8,9 };
	wei::priority_queue<int> q(array, array+sizeof(array)/sizeof(array[0]));
	cout << q.size() << endl;
	cout << q.top() << endl;
}

void TestMyPriority_queue2()
{
	wei::priority_queue<int> q;
	q.push(1);
	q.push(2);
	q.push(3);
	q.push(4);
	q.push(5);
	q.push(6);
	cout << q.size() << endl;
	cout << q.top() << endl;
	q.pop();
	q.pop();
	cout << q.size() << endl;
	cout << q.top() << endl;
}

void TestMyPriority_queue3()
{
	int array[] = { 1,2,3,4,5,6,7,8,9 };
	wei::priority_queue<int, vector<int>, wei::Greater<int>> q(array, array + sizeof(array) / sizeof(array[0]));
	cout << q.size() << endl;
	cout << q.top() << endl;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值