priority_queue模拟实现+仿函数+反向迭代器
- 1.priority_quyue
- 1.1priority_queue的使用
- 1.2priority_queue模拟实现
- 1.2.1无参构造+一段区间构造
- 1.2.2push
- 1.2.3pop
- 1.2.4empty
- 1.2.5size
- 1.2.6top
 
 
- 2.仿函数
- 2.1什么是仿函数
- 2.2增加仿函数的priority_queue模拟实现完整代码
 
- 3.反向迭代器
- 3.1list反向迭代器
- 3.2vector反向迭代器
 
自我名言:只有努力,才能追逐梦想,只有努力,才不会欺骗自己。
喜欢的点赞,收藏,关注一下把!
1.priority_quyue
priority_queue文档介绍
- 优先队列也和栈,队列一样是一种容器适配器,容器适配器即将特定容器类封装作为其底层容器类。
- 优先级底层是堆,而堆又是一个完全二叉树,因此可以选用vector和dequeue来作为特定的容器,dequeue头插头删效率高,但是随机访问效率低一些。因此选择vector作为特定的容器更为合适。
- 优先级队列默认是一个大堆。
- 优先级队列规定优先级高的先出。

priority_queue默认是一个大堆,这是由第三个参数less(仿函数)所控制的,虽然less明面意思是小于,但是默认是一个大堆,默认大的优先级较高,大的先出。greater(仿函数),明面意思是大于,但是默认是一个小堆,默认小的优先级比较高,小的先出。
这里先不介绍仿函数,直接用就可以了,下面再详细讲。
1.1priority_queue的使用
| 函数说明 | 接口说明 | 
|---|---|
| priority_queue()/priority_queue(first,last) | 构造一个空的优先级队列 | 
| empty() | 检测优先级队列是否为空,是返回true,否则返回false | 
| push(x) | 在优先级队列中插入元素x | 
| pop() | 删除优先级队列中最大(最小)元素,即堆顶元素 | 
| top() | 返回优先级队列中最大(最小元素),即堆顶元素 | 

注意缺省值不能隔着传。

写一道题来熟悉接口。
 215. 数组中的第K个最大元素
 

 在数据结构的学过堆,并且这里问题提供两个思路
思路一:
堆排序
时间复杂度:O(N*log2N)
思路二:
拿N个元素建立一个大堆,然后popK-1次,这样top拿的就是第K个最大的元素。
时间复杂度:建堆O(N),调整堆O(Klog2N) ----> O(N+Klog2N)
思路三:
拿K个元素建立一个小堆,再将N-K个元素与堆顶元素比较,大于堆顶元素就入堆,最后堆顶元素就是就是第K个大的元素。
时间复杂度:O(K+(N-K)*log2K) ----->O(N)
这里给出第三个思路的代码。
class Solution {
public:
    int findKthLargest(vector<int>& nums, int k) {
        //前k个建小堆
        priority_queue<int,vector<int>,greater<int>> pq(nums.begin(),nums.begin()+k);
        //N-k与堆顶元素比较,大于堆顶就入堆,再次调整成小堆
        for(size_t i=k;i<nums.size();++i)
        {
            if(nums[i]>pq.top())
            {
                pq.pop();
                pq.push(nums[i]);
            }
        }
        return pq.top();
    }
};
1.2priority_queue模拟实现
关于这的一些向上调整算法和向下调整算法再堆的实现,画图和代码分析建堆,堆排序,时间复杂度以及TOP-K问题里都有详细介绍,这里不在细说了。
1.2.1无参构造+一段区间构造
//大堆
template<class T, class Container = vector<T>>
class priority_queue
{
public:
	priority_queue()
	{}
	template <class InputIterator>
	priority_queue(InputIterator first, InputIterator last)
		:_con(first, last)
	{
		//向下调整法建堆
		for (int i =( _con.size() - 1 - 1) / 2; i >= 0; --i)
		{		
			adjustdown(i);
		}
	}
	void adjustdown(int parent)
	{
		int minchild = parent * 2 + 1;
		while (minchild < _con.size())
		{
			if (minchild + 1 < _con.size() && _con[minchild + 1] > _con[minchild])
			{
				minchild++;
			}
			if (_con[minchild] > _con[parent])
			{
				swap(_con[minchild], _con[parent]);
				parent = minchild;
				minchild = parent * 2 + 1;
			}
			else
			{
				break;
			}
		}
	}
private:
	Container _con;
};
1.2.2push
//向上调整法
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 push(const T& val)
{
	_con.push_back(val);
}
1.2.3pop
void pop()
{
	assert(!empty());
	swap(_con[0], _con[_con.size() - 1]);
	_con.pop_back();
	adjustdown(0);
	
}
1.2.4empty
bool empty()
{
	return _con.empty();
}
1.2.5size
size_t size()
{
	return _con.size();
}
1.2.6top
const T& top()
{
	assert(!empty());
	return _con[0];
}
这里还是和库里有些区别,我们写第三个参数,仿函数,下面我们来介绍它,并且在完善我们的代码。
2.仿函数
2.1什么是仿函数
仿函数其实是一个类的对象,也可以说是函数对象,因为这个类的对象可以像函数一样使用。
仿函数类别有很多种,今天主要介绍less和greater(比大小仿函数 )。
还记得C语言给我们提供了一个qsort函数,这个函数用到了函数指针。
 这个函数指针指向一个比大小的函数。
C++既然包容C了,为什么不直接用这个函数指针呢?
 C++主要觉得函数指针太麻烦了。因此引入了仿函数。
拿冒泡排序为例。
下面是普通的冒泡排序,如果排升序>,降序<,但是这都不能由使用者来决定,只能由写这个排序的人才能决定。这样给用户的体验感不好,自己不能控制。如果自己能够控制排序的方式就好了,所以这里可以写个比大小的仿函数。
void Bubblesort(int* a,int n)
{
	for (int i = 0; i < n - 1; ++i)
	{
		int flag = 1;
		for (int j = 0; j < n - i - 1; ++j)
		{
			if (a[j] > a[j+1])
			{
				swap(a[j], a[j + 1]);
				flag = 0;
			}
		}
		if (flag == 1)
		{
			break;
		}
	}
}
仿函数
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;
	}
};
这样看起来为什么一个类的对象可以叫做函数对象了,这个对象可以像函数一样调用。
less<int> lessfunc;
greater<int> greaterfunc
lessfunc(0, 1);
greaterfunc(0,1)
//这里是运算符重载  lessfunc.operator()(0,1)
现在将冒泡排序写成一个函数模板,这样就可以自己控制升序还是降序了。
template<class T,class Compare>
void Bubblesort(T* a,int n,Compare _com)
{
	for (int i = 0; i < n - 1; ++i)
	{
		int flag = 1;
		for (int j = 0; j < n - i - 1; ++j)
		{
			//升序
			//if (a[j] > a[j+1])
			if (_com(a[j],a[j+1]))
			{
				swap(a[j], a[j + 1]);
				flag = 0;
			}
		}
		if (flag == 1)
		{
			break;
		}
	}
}
int main()
{	
	int a[] = { 4,1,2,5,7,3,9,0,6,8 };
	Bubblesort(a, sizeof(a) / sizeof(a[0]), bit::greater<int>());
	return 0;
}
2.2增加仿函数的priority_queue模拟实现完整代码
#include<iostream>
#include<queue>
#include<vector>
#include<assert.h>
#include<algorithm>
using namespace std;
namespace bit
{
	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>>
	template<class T, class Container = vector<T>,class Compare=less<T>>
	class priority_queue
	{
	public:
		priority_queue()
		{}
		template <class InputIterator>
		priority_queue(InputIterator first, InputIterator last)
			:_con(first, last)
		{
			//向下调整法建堆
			for (int i =( _con.size() - 1 - 1) / 2; i >= 0; --i)
			{		
				adjustdown(i);
			}
		}
		void adjustdown(int parent)
		{
			Compare _com;
			int minchild = parent * 2 + 1;
			while (minchild < _con.size())
			{
				
				//if (minchild + 1 < _con.size() && _con[minchild + 1] > _con[minchild])
				if (minchild + 1 < _con.size() && _com(_con[minchild],_con[minchild+1]))
				{
					minchild++;
				}
				//if (_con[minchild] > _con[parent])
				if (_com(_con[parent],_con[minchild]))
				{
					swap(_con[minchild], _con[parent]);
					parent = minchild;
					minchild = parent * 2 + 1;
				}
				else
				{
					break;
				}
			}
		}
		void adjustup(int child)
		{
			Compare _com;
			int 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& val)
		{
			_con.push_back(val);
			adjustup(_con.size() - 1);
		}
		void pop() 
		{
			assert(!empty());
			swap(_con[0], _con[_con.size() - 1]);
			_con.pop_back();
			adjustdown(0);
		}
		bool empty()
		{
			return _con.empty();
		}
		size_t size()
		{
			return _con.size();
		}
		const T& top()
		{
			assert(!empty());
			return _con[0];
		}
	private:
		Container _con;
	};
}
3.反向迭代器
在前面vector和list模拟实现,我们只实现了正向迭代器和const正向迭代器,没有去实现反向迭代器。
这是因为反向迭代器也是一个容器适配器。
 给我一个正向迭代器我可以适配出反向迭代器。
 给我一个const正向迭代器我可以适配出const反向迭代器。
也就是我们复用现有的来帮我们实现所需要的。

3.1list反向迭代器
复用iterator创造reverse_iterator,因此把iterator传过去。
 
template<class iterator,class Ref ,class Ptr>
class Reverseiterator
{
public:
//构造
	Reverseiterator(iterator It)
		:_it(It)
	{}
private:
	iterator _it;
};

//++rit
	self& operator++()
	{
		--it;
		return *this;
	}
	//rit++
	self operator++(int)
	{
		iterator tmp(*this);
		--it;
		return tmp;
	}
	//--rit
	self& opeartor--()
	{
		++it;
		return *this;
	}
	//rit--
	self operator--(int)
	{
		iterator tmp(*this);
		++it;
		return tmp;
	}

Ref operator*()
	{
		iterator tmp = _it;
		//先--,在解引用
		return *(--tmp);
	}
	
//针对自定义类型
Ptr operator->()
{
	return &(operator*());
}
完整代码
template<class iterator,class Ref ,class Ptr>
class Reverseiterator
{
	typedef Reverseiterator<iterator, Ref, Ptr> self;
public:
	Reverseiterator(iterator It)
		:_it(It)
	{}
	Ref operator*()
	{
		iterator tmp = _it;
		return *(--tmp);
	}
	Ptr operator->()
	{
		return &(operator*());
	}
	//++rit
	self& operator++()
	{
		--_it;
		return *this;
	}
	//rit++
	self operator++(int)
	{
		iterator tmp(*this);
		--_it;
		return tmp;
	}
	//--rit
	self& operator--()
	{
		++_it;
		return *this;
	}
	//rit--
	self operator--(int)
	{
		iterator tmp(*this);
		++_it;
		return tmp;
	}
	bool operator!=(const self& s)
	{
		return _it != s._it;
	}
private:
	iterator _it;
};
reverse_iterator rbegin()
	{
		return reverse_iterator(end());
	}
reverse_iterator rend()
{
	return reverse_iterator(begin());
}
3.2vector反向迭代器
我们的思路和list的反向迭代器一样,把上面代码复用给vector,就实现了vector的反向迭代器。
 






![BUUCTF_练[PASECA2019]honey_shop](https://img-blog.csdnimg.cn/img_convert/17a1cde907f694f396d69af38f049551.png)















