c++之priority_queue实现

本文详细介绍了优先级队列的数据结构及其实现原理。探讨了如何使用C++ STL中的vector作为底层容器,并通过仿函数实现大堆和小堆。此外,还提供了完整的代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

priority_queue(优先级队列)

优先级队列的定义:优先级队列 是不同于先进先出队列的另一种队列。每次从队列中取出的是具有最高优先权的元素。

实现原理:优先级队列默认的容器一般采用STL中的vector容器。因为vector具有高效的连续存储的效率,它的随机访问
的效率比较高,当然也可以采用stack或者dequeue,其它本身是一个堆的结构,默认条件下生成大堆

== 注意:优先级队列的实现的底层容器,默认采用vector,也可以采用dequeue,只是vector的随机访问效率较高,切记!!!千万不能使用list,因为list不支持随机访问!!! ==

优先级队列是一种新的数据结构,它能够快速的获取最大的,也可以通过pop操作获取第K大的数,而且时间复杂度
为O(1),它的默认为大堆,不过我们可以通过定义仿函数来实现大堆和小堆的变换。

仿函数

仿函数less的实现,必须重载()运算符
//仿函数类
//必须重载()运算符

template<class T>
struct Less
{
	bool operator()(const T& val1, const T& val2)
	{
		return val1 < val2;
	}
};
template<class T>
struct Greater
{
	bool operator()(const T& val1, const T& val2)
	{
		return val1 > val2;
	}
};
在实现完仿函数后,我们要在开始声明所用的泛型模板
template<class T, class Container=vector<T>,class Compare=Greater<T>>
对于Compare来说,这是一个定义比较规则的类,在compare里指定所要使用的规则,Less还是Greater,然后再在
priority_queue中创建对象_com,在节点比较的时候调用_com的()运算符,在这里大家可能听起来比较绕,下面
代码先码上

在这里插入图片描述

	//大堆向上调整
	void shiftUp(int child)
	{
		int parent = (child - 1) / 2;
		while (child > 0)
		{
			//if (_c[parent] < _c[child])
			if(_com(_c[parent], _c[child]))
			{
				swap(_c[parent], _c[child]);
				child = parent;
				parent = (child - 1) / 2;
			}
			else
				break;
		}
	}
这里的Greater用于建小堆,如果需要建大堆可以使用Less,这样的话就大大减小了代码的冗余度,减少了我们
写一些这种结构类似的代码,提高了效率,向传统的写法,我们至少得写两遍重复的代码,在这里我们使用了仿函数
重载()运算符,相当于在比较的时候调用了仿函数里面的()这个函数、

完整代码如下:

#include<iostream>
#include<list>
#include<vector>
#include<stack>
#include<deque>
using namespace std;


//仿函数类
//必须重载()运算符

template<class T>
struct Less
{
	bool operator()(const T& val1, const T& val2)
	{
		return val1 < val2;
	}
};

template<class T>
struct Greater
{
	bool operator()(const T& val1, const T& val2)
	{
		return val1 > val2;
	}
};



template<class T, class Container=vector<T>,class Compare=greater<T>>

class priorityQueue
{
public:

	//向上调整
	void shiftUp(int child)
	{
		int parent = (child - 1) / 2;
		while (child > 0)
		{
			//if (_c[parent] < _c[child])
			if(_com(_c[parent], _c[child]))
			{
				swap(_c[parent], _c[child]);
				child = parent;
				parent = (child - 1) / 2;
			}
			else
				break;
		}
	}

	void push(const T& val)
	{
		//尾插+向上调整
		_c.push_back(val);
		shiftUp(_c.size() - 1);
	}

	//向下调整
	void shiftDown(int parent)
	{
		int child = parent * 2+1;

		while (child < _c.size())
		{
			if (child + 1 < _c.size() &&_com(_c[child] , _c[child + 1] ))
			{
				child++;
			}
			if(_com(_c[parent] , _c[child]))
			//if (_c[parent] < _c[child])
			{
				swap(_c[parent], _c[child]);
				parent = child;
				child = parent * 2 + 1;
			}
			else
				break;
		}
	}

	//删除堆顶元素  交换首尾元素,向下调整
	void pop()
	{
		swap(_c[0], _c[_c.size() - 1]);
		_c.pop_back();
		shiftDown(0);


	}

	T& top()
	{
		//return _c[0];
		return _c.front();
	}

	bool empty()
	{
		return _c.empty();
	}

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

private:
	Container _c;
	Compare _com;
};

void test()
{
	//大堆
	//优先级队列的默认容器:vector,vector--->随机访问的效率高于双端队列
	
	//priorityQueue<int, vector<int>,less<int>> pq;
	//小堆
	priorityQueue<int, vector<int>, greater<int>> pq;

	//priorityQueue<int, deque<int>> pq;
	//list不支持随机访问,不能做优先级队列的底层容器
	//priorityQueue<int, list<int>> pq;
	pq.push(1);
	pq.push(5);
	pq.push(23);
	pq.push(32);
	pq.push(10);



}

//int main()
//{
//	test();
//	return 0;
//}
LRU(Least Recently Used)是一种缓存淘汰策略,当缓存空间不足时,先淘汰最近最少使用的缓存块。在 C++ 中,可以使用 `std::priority_queue` 数据结构来实现 LRU。 下面是基于 `std::priority_queue` 实现 LRU 的代码示例: ```c++ #include <iostream> #include <queue> #include <unordered_map> template <typename T> class LRUCache { public: LRUCache(int capacity) : capacity_(capacity) {} void put(int key, const T& value) { if (cache_.find(key) != cache_.end()) { // 如果 key 已经存在,则更新 value 并移动到队首 auto it = cache_[key]; it->second = value; cache_list_.erase(it); cache_list_.push_front({key, value}); cache_[key] = cache_list_.begin(); } else { // 如果 key 不存在,则插入新的键值对,并将其移动到队首 if (cache_list_.size() == capacity_) { // 如果队列已满,则删除队尾元素 auto last = cache_list_.back(); cache_list_.pop_back(); cache_.erase(last.first); } cache_list_.push_front({key, value}); cache_[key] = cache_list_.begin(); } } const T* get(int key) { if (cache_.find(key) != cache_.end()) { // 如果 key 存在,则返回 value 并将其移动到队首 auto it = cache_[key]; cache_list_.erase(it); cache_list_.push_front(*it); cache_[key] = cache_list_.begin(); return &it->second; } else { // 如果 key 不存在,则返回 nullptr return nullptr; } } private: int capacity_; std::list<std::pair<int, T>> cache_list_; // 双向链表存储键值对 std::unordered_map<int, typename std::list<std::pair<int, T>>::iterator> cache_; // 哈希表存储键值对的迭代器 }; int main() { LRUCache<int> cache(3); cache.put(1, 10); cache.put(2, 20); cache.put(3, 30); cache.put(4, 40); std::cout << *cache.get(2) << std::endl; // 输出 20 std::cout << *cache.get(3) << std::endl; // 输出 30 std::cout << (cache.get(5) == nullptr) << std::endl; // 输出 1 return 0; } ``` 在上述实现中,我们使用了一个双向链表 `cache_list_` 存储键值对,同时使用一个哈希表 `cache_` 存储每个键对应的迭代器。在 `put` 操作中,如果缓存中已经存在该键,则更新该键对应的值并将其移动到队首;如果不存在该键,则首先判断缓存是否已满,若已满则删除队尾元素,然后将新的键值对插入到队首。在 `get` 操作中,如果缓存中存在该键,则返回其对应的值并将其移动到队首;如果不存在该键,则返回 nullptr。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值