C++ priority_queue (STL容器适配器)

目录

适配器

priority_queue

priority_queue的使用

priority_queue模拟实现


适配器

适配器是一种设计模式(设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结),适配器是将一个类的接口转换成客户希望的另外一个接口。

举个栗子, 咱们香港的插头和我们内地是不一的, 如下图, 这种插头在咱们内地是不方便使用的, 要是香港同胞到对岸深圳转一转, 被繁华的深圳所吸引, 不禁多留了两天, 那这时候手机要充电怎么充电啊, 不过没关系, 我们有适配器, 其实真正给手机充电的还是手机充电器, 适配器只是方便了人们的使用而已. 

  C++ priority_queue (STL容器适配器)_第1张图片
          港版充电器                                                     适配器                                                          适配器的使用

常见的容器适配器有stack , queue,  priority_queue,  它们就相当于上图的适配器, 真正给手机充电的是还是充电头, 同样的道理, 它们底层是靠别的容器实现的
例如:
stack可以用vector, deque, list实现. 
queue可以用 deque, list实现
priority_queue, 可以用 deque, vector实现  

C++STL容器适配器之queue
C++ STL容器适配器之stack

priority_queue

简介

优先队列priority_queue是一个
堆数据结构详解链接

1. 底层容器可以是任何标准容器类模板,也可以是其他特定设计的容器类。容器必须可以通过随机访问迭代器访问,并支持以下操作:
empty():检测容器是否为空
size():返回容器中有效元素个数
front():返回容器中第一个元素的引用
push_back():在容器尾部插入元素
pop_back():删除容器尾部元素
2. 标准容器类vector和deque满足这些需求。默认情况下,如果没有为特定的priority_queue类实例化指定容器类,则使用vector。
3. 需要支持随机访问迭代器,以便始终在内部保持堆结构。容器适配器通过在需要时自动调用算法函数make_heap、push_heap和pop_heap来自动完成此操作。算法头文件 #include
4. priority_queue 的使用需要头文件 #include
5. 所有需要用到堆的时候,都可以考虑使用priority_queue。注意: 默认情况下priority_queue是大堆。如果要创建小堆,需要将第三个模板参数换成greater比较方式

priority_queue图示:

C++ priority_queue (STL容器适配器)_第2张图片

priority_queue的使用

所有需要用到堆的时候,都可以考虑使用priority_queue。注意: 默认情况下priority_queue是大堆。如果要创建小堆,需要将第三个模板参数换成greater比较方式

函数名称 接口说明

priority_queue()

 

构造一个空的优先级队列

priority_queue(first, last)

将[first, last)范围内所有的数据构造成一个新的优先队列
empty( ) 检测优先级队列是否为空,是返回true,否则返回
false
top( ) 返回优先级队列中最大(最小元素),即堆顶元素
push(x) 在优先级队列中插入元素x
pop() 删除优先级队列中最大(最小)元素,即堆顶元素

注意 :

1. 默认priority_queue底层实现用vector, 默认是大堆
如果要用deque实现或, 创建小堆, 需要传入模板参数, priority_queue共有三个模板参数, 第一个是数据类型, 后两个是缺省参数, 第二个缺省值是vector, 第三个缺省值是less
下面创建的priority_queue依次是, 用deque实现的大根堆, 用vector实现的小根堆, 用deque实现的小根堆

priority_queue> pq1;
priority_queue, greater> pq2;
priority_queue, greater> pq3;

需要注意的是, 缺省值less和greater是仿函数, 需要头文件#include

仿函数: 可以当成函数使用的类,因为类中重载了函数调用运算符(或小括号运算符)  "()"

2. 如果在priority_queue中放自定义类型的数据,用户需要在自定义类型中提供> 或者< 的重载。因为less和greater这两个仿函数(类)中重载的()运算符 中只是简单地用> , <比较, 如自定义类型不能直接比较则会出错 .

例如, 自定义类型Date类, 时间的比较, 未重载>, <则不能比较, 所以需要我们在Date类中重载>, <运算符, 如下

class Date {
    int _year;
    int _month;
    int _day;

public:
    Date(int year = 1900, int month = 1, int day = 1)
    : _year(year)
    , _month(month)
    , _day(day)
    {}
    bool operator<(const Date& d)const {
        return (_year < d._year) || (_year == d._year && _month < d._month) ||
       (_year == d._year && _month == d._month && _day < d._day);
    }
    bool operator>(const Date& d)const {
        return (_year > d._year) || (_year == d._year && _month > d._month) ||
        (_year == d._year && _month == d._month && _day > d._day);
    }
    friend ostream& operator<<(ostream& _cout, const Date& d) {
        _cout << d._year << "-" << d._month << "-" << d._day;
        return _cout;
    }
};

 

3. 有些情况下,用户可能需要提供比较器规则

如果priority_queue pq; 传入的是Date类对象的指针, 就算我们在Date类中重载了><的也不能对两个地址进行比较, 所以我们要自己提供比较器, 也就是要自己写一个仿函数(类), 重载一下小括号运算符(). 如下:
这个自己提供的比较器可以是类模板, 也可以是普通类, 模板类就可以实例出其他的指针类型

class Less1 {
public:
    bool operator()(const Date* pLeft, const Date* pRight) {
        return *pLeft < *pRight;
    }
};
template
class Less2 {
public:
    bool operator()(const T pLeft, const T pRight) {
        return *pLeft < *pRight;
    }
};

priority_queue, Less1> pq1;
priority_queue, Less2> pq2;

 

priority_queue模拟实现

头文件priority_queue.h

#pragma once
#include
#include
#include
#include
using namespace std;
template 
class Greater {
public:
	bool operator()(const T& left, const T& right){
		return left > right;
	}
};
template 
class Less {
public:
	bool operator()(const T& left, const T& right) {
		return left < right;
	}
};
template, class Cmp = Less>
class my_priority_queue {
	Con m_data;
	Cmp m_cmp;
public:
	my_priority_queue() {

	}
	template 
	my_priority_queue(InputIterator first, InputIterator last)
		: m_data(first, last){
		make_heap(m_data.begin(), m_data.end(), m_cmp);
	}
	void push(const T& val) {
		m_data.push_back(val);
		push_heap(m_data.begin(), m_data.end(), m_cmp);
	}
	void pop() {
		pop_heap(m_data.begin(), m_data.end(), m_cmp);
		m_data.pop_back();
	}
	T& top() {
		return m_data.front();
	}
	int size() {
		return m_data.size();
	}
	bool empty() {
		return m_data.empty();
	}

};

测试入口main.cpp 

#include
#include"priority_queue.h"
#include
#include
#include
using namespace std;
void Test_priority_queue() {
	cout << "STL中的priority_queue\n";
	priority_queue pq;
	for (int i = 1; i <= 5; ++i) {
		pq.push(i);
	}
	cout << "size = " << pq.size() << endl;
	for (int i = 1; !pq.empty(); i *= 2) {
		for (int j = i; !pq.empty() && j > 0; --j) {
			cout << pq.top() << ' ';
			pq.pop();
		}
		cout << endl;
	}
	cout << "size = " << pq.size() << endl;
}
void Test_my_priority_queue() {
	cout << "自己实现的的priority_queue\n";
	my_priority_queue, Less> pq;
	//my_priority_queue pq;
	for (int i = 1; i <= 5; ++i) {
		pq.push(i);
	}
	cout << "size = " << pq.size() << endl;
	for (int i = 1; !pq.empty(); i *= 2) {
		for (int j = i; !pq.empty() && j > 0; --j) {
			cout << pq.top() << ' ';
			pq.pop();
		}
		cout << endl;
	}
	cout << "size = " << pq.size() << endl;
}
int main() {
	Test_priority_queue();
	Test_my_priority_queue();
	system("pause");
	return 0;
}

 运行结果 :

C++ priority_queue (STL容器适配器)_第3张图片

你可能感兴趣的:(C++,STL)