STL,英文全称 standard template library,中文可译为标准模板库或者泛型库,其包含有大量的模板类和模板函数,是 C++ 提供的一个基础模板的集合,用于完成诸如输入/输出、数学计算等功能
容器的分类
int32 AdapterTest::vectorCreTest()
{
// 空的vector容器,因为容器中没有元素,所以没有为其分配空间
// 当添加第一个元素(比如使用 push_back() 函数)时,vector 会自动分配内存
std::vector<int32> testVec;
// 增加容器的容量
testVec.reserve(10);
// 除了创建空的向量容器外,也可以在创建的同时指定元素的初始值及元素的个数
std::vector<int32> primes{2, 3, 5, 7, 11, 13, 17, 19};
// 在创建vector容器的同时指定元素的个数
std::vector<int32> values(20);
// 指定元素的个数及初始默认值
std::vector<int32> values1(10,3);
return 0;
}
int32 AdapterTest::vectorFuncTest()
{
std::vector<int32> nums;
for (int i = 0; i < 30;++i)
{
if((i & 1) == 0)
{
nums.push_back(i);
}
}
/*
* vector容器的遍历
* - begin()
* 返回指向容器中第一个元素的迭代器
* - end()
* 返回指向容器最后一个元素所在位置后一个位置的迭代器
*/
cout << "vector iterator traversal begin...." << endl;
std::vector<int32>::iterator it = nums.begin();
for(;it != nums.end();++it)
{
cout << *it << " ";
}
cout << endl;
cout << "vector iterator traversal end...." << endl;
cout << endl;
/*
*
* -rbegin()
* 返回指向最后一个元素的迭代器
* -rend()
* 返回指向第一个元素所在位置前一个位置的迭代器
*
*/
cout << "vector reverse_iterator traversal begin......" << endl;
std::vector<int32>::reverse_iterator rit = nums.rbegin();
for (; rit != nums.rend();++ rit)
{
cout << *rit << " ";
}
cout << endl;
cout << "vector reverse_iterator traversal end......" << endl;
/*
* - cbegin()
* 和begin()功能相同,只不过在其基础上,增加了const属性,不能用于修改元素
* - cend()
* 和end()功能相同,只不过在其基础上,增加了const属性,不能用于修改元素
* const_iterator 可以接收 begin() 返回的数据 也可以接收cbegin()返回的数据
*/
cout << "vector reverse_iterator traversal begin......" << endl;
std::vector<int32>::const_iterator cit = nums.begin();
for(;cit != nums.end();++cit)
{
cout << *cit << " ";
}
cout << "vector reverse_iterator traversal end......" << endl;
cout << endl;
/*
* -crbegin()
* 和rbegin()功能相同,只不过在其基础上,增加了const属性,不能用于修改元素。
* -crend()
* 和rend()功能相同,只不过在其基础上,增加了const属性,不能用于修改元素。
* 在使用反向迭代器进行++或--运算时,++指的是迭代器向左移动一位,--指的是迭代器向右移动一位,即这两个运算符的功能也“互换”了
*/
// const_reverse_iterator 可以接收 rbegin() 也可以接收crbegin()的返回值
cout << "vector const_reverse_iterator traversal begin......" << endl;
std::vector<int32>::const_reverse_iterator crit = nums.rbegin();
for (;crit != nums.rend();++crit)
{
cout << *crit << " ";
}
cout << endl;
cout << "vector const_reverse_iterator traversal end......" << endl;
/*
*
* 重载了 []
* size() 容器中元素的个数
*
*/
for(int i = 0; i < nums.size();++i)
{
cout << nums[i] << " ";
}
cout << endl;
/*
* vector 增 删 改 查 操作
* - front()
* 返回第一个元素的引用
* - back()
* 返回最后一个元素的引用
* - push_back()
* 在序列的尾部添加一个元素
* - pop_back()
* 弹出序列尾部的元素
*/
std::vector<int32> vecTest{10,20,30,40};
cout << "front() begin" << endl;
//cout << *vecTest.begin() << endl;
//vecTest.front();
//num = -1;
cout << "front : " << vecTest.front() << " back : " << vecTest.back() << endl;
//cout << "num : " << num << endl;
cout << "front() end" << endl;
vecTest.push_back(50);
vecTest.insert(vecTest.end(),60);
// 仅仅是弹出尾部的元素 没有返回值
vecTest.pop_back();
// 增加容器的容量
cout << "capacity : " << vecTest.capacity() << endl;
vecTest.reserve(100);
cout << "capacity : " << vecTest.capacity() << endl;
/*
*
* 使用反向迭代器进行遍历
*
*
*/
std::vector<std::string> vecStr{"BOSS","EMPLOYEE","MANAGER"};
auto first = vecStr.rbegin();
auto end = vecStr.rend();
while (first != end)
{
cout << *first << " ";
// 前移一个
++first;
}
return 0;
}
/**
*
* 访问单个元素
* @brief AdapterTest::vectorFuncTest1
* @return
*/
int32 AdapterTest::vectorFuncTest1()
{
std::vector<int32> vecNums{10,20,30,40};
// vector 的索引从0开始,这和普通数组一样。通过使用索引,总是可以访问到vector容器中现有的元素
cout << "vecNums[0] : " << vecNums[0] << endl;
for (int i = 0; i < vecNums.size();++i)
{
cout << vecNums[i] << " ";
}
cout << endl;
}
insert
int32 AdapterTest::vecInsertEleTest()
{
int arr[]{10,20,4,6,16};
std::vector<int32> vecNum;
// 插入数组中的元素 在指定位置的前面插入元素
vecNum.insert(vecNum.end(),arr,arr+5);
std::vector<int32> vecOther{9,10,20,30};
// 在vecNum的末尾插入另外一个元素
vecNum.insert(vecNum.end(),vecOther.begin(),vecOther.end());
//排序
std::sort(vecNum.begin(),vecNum.end());
std::vector<int32>::const_iterator iter = vecNum.begin();
for(;iter != vecNum.end();++iter)
{
cout << *iter << " ";
}
}
emplace
/**
* emplace()是 C++11 标准新增加的成员函数,用于在vector容器指定位置之前插入一个新的元素
* emplace() 每次只能插入一个元素,而不是多个
* @brief AdapterTest::vecEmplaceTest
* @return
*/
int32 AdapterTest::vecEmplaceTest()
{
std::vector<int32> vecTest;
for(int i = 0; i <= 10; ++i)
{
vecTest.emplace(vecTest.end(),i);
}
std::vector<int32>:: const_iterator iter = vecTest.begin();
for(; iter != vecTest.end();++iter)
{
cout << *iter << " ";
}
cout << endl;
return 0;
}
STL list 容器,又称双向链表容器,即该容器的底层是以双向链表的形式实现的。这意味着,list 容器中的元素可以分散存储在内存空间里,而不是必须存储在一整块连续的内存空间中 st 容器中各个元素的前后顺序是靠指针来维系的,每个元素都配备了 2 个指针,分别指向它的前一个元素和后一个元素。其中第一个元素的前向指针总为 null,因为它前面没有元素;同样,尾部元素的后向指针也总为 null。
基于这样的存储结构,list 容器具有一些其它容器(array、vector 和 deque)所不具备的优势,即它可以在序列已知的任何位置快速插入或删除元素(时间复杂度为O(1))。并且在 list 容器中移动元素,也比其它容器的效率高
/**
*
* list 相关的方法测试
* @brief AdapterTest::listTest
* @return
*/
int32 AdapterTest::listTest()
{
// 创建一个没有任何元素的空list容器
std::list<int32> li1;
// 创建一个包含n个元素的list容器
std::list<int32> li2(10);
// 创建一个包含n个元素的list容器,并为每个元素指定初始值
std::list<int32> li3(10,8);
// 在已有 list 容器的情况下,通过拷贝该容器可以创建新的list容器
std::list<int32> li4(li3);// 采用此方式,必须保证新旧容器存储的元素类型一致
std::list<int32> testList;
for(int i = 0; i < 100;i+=10){
if ((i & 1) == 0){
testList.push_back(i);
}
}
cout << "size : " << testList.size() << endl;
// begin() 返回指向容器中第一个元素的双向迭代器
// end() 返回指向容器中最后一个元素所在位置的下一个位置的双向迭代器
std::list<int32>::iterator iter = testList.begin();
// 1.遍历
cout << "------using iterator to travelsal list begin------" << endl;
for(;iter != testList.end();++iter)
{
cout << *iter << " ";
}
cout << endl;
cout << "------using iterator to travelsal list end------" << endl;
// const_iterator cbegin() 也可以换成 begin() cend() 也可以换成 end()
std::list<int32>::const_iterator citer = testList.cbegin();
cout << "------using const_iterator to travelsal list begin------" << endl;
for(;citer != testList.cend();++citer)
{
cout << *citer << " ";
}
cout << endl;
cout << "------using const_iterator to travelsal list end------" << endl;
// 反向迭代器 rbegin() rend()
cout << "------using reverse_iterator to travelsal list begin------" << endl;
// std::list::const_reverse_iterator 使用这个也可以
std::list<int32>::reverse_iterator riter = testList.rbegin();
for(;riter != testList.rend();++ riter)
{
cout << *riter << " ";
}
cout << endl;
cout << "------using reverse_iterator to travelsal list end------" << endl;
cout << "empty : " << testList.empty() << endl;
cout << "size : " << testList.size() << endl;
// 返回第一个元素的引用
cout << "front : " << testList.front() << endl;
// 返回最后一个元素的引用
cout << "back : " << testList.back() << endl;
// 在容器尾部插入一个元素
testList.push_back(766);
cout << "back : " << testList.back() << endl;
// 删除容器尾部的一个元素 无返回值
testList.pop_back();
// 在容器中的指定位置插入元素。该函数和insert()功能相同,但效率更高
testList.emplace(testList.end(),800);
cout << "back : " << testList.back() << endl;
// insert() 在容器中的指定位置插入元素
testList.insert(testList.begin(),900);
cout << "front : " << testList.front() << endl;
// 删除指定区间的元素 返回指向下一个元素的迭代器
iter = testList.erase(testList.begin());
cout << *iter << endl;
}
int32 AdapterTest::listRemoveTest()
{
std::list<int32> testList;
for(int i = 0;i<100;++i){
testList.push_back(i);
}
std::list<int32>::const_iterator iter = testList.begin();
for (;iter != testList.end();++iter)
{
cout << *iter << " ";
}
cout << endl;
for(iter = testList.begin();iter != testList.end();)
{
if((*iter & 1) == 0)
{
// 删除 iter 指向的元素 并返回指向下一个元素的迭代器
iter = testList.erase(iter);
} else {
++iter;
}
}
cout << "------------------------------" << endl;
iter = testList.begin();
for (;iter != testList.end();++iter)
{
cout << *iter << " ";
}
cout << endl;
}
3.1 pair类模板
C++ STL 标准库提供了 pair 类模板,其专门用来将 2 个普通元素 first 和 second(可以是 C++ 基本数据类型、结构体、类自定的类型)创建成一个新元素
pair 类模板定义在头文件中,所以在使用该类模板之前,需引入此头文件
#include
using namespace std;
pair对象的创建
int32 RelConTest::pairCreTest()
{
// 默认构造函数,即创建空的pair对象
strIntPair pair1;
// 直接使用两个元素初始化对象
strIntPair pair2("Mathematics",78);
// 调用拷贝构造函数
strIntPair pair3(pair2);
// 调用移动构造函数
strIntPair pair4(make_pair("Electric",98));
// 创建pair 手动为 pair赋值
strIntPair pair5;
pair5.first = "Java";
pair5.second = 90;
cout << "first : " << pair2.first << ",second : " << pair2.second << endl;
}
头文件中除了提供创建 pair 对象的方法之外,还为 pair 对象重载了 <、<=、>、>=、==、!= 这 6 的运算符,其运算规则是:对于进行比较的 2 个 pair 对象,先比较 pair.first 元素的大小,如果相等则继续比较 pair.second 元素的大小
3.2 关联容器概述及分类
关联式容器在存储元素值的同时,还会为各元素额外再配备一个值(又称为"键",其本质也是一个 C++ 基础数据类型或自定义类型的元素),它的功能是在使用关联式容器的过程中,如果已知目标元素的键的值,则直接通过该键就可以找到目标元素,而无需再通过遍历整个容器的方式。
关联式容器可以快速查找、读取或者删除所存储的元素,同时该类型容器插入元素的效率也比序列式容器高。
关联式容器所具备的这些特性,归咎于 STL 标准库在实现该类型容器时,底层选用了 「红黑树」这种数据结构来组织和存储各个键值对
C++ STL关联式容器种类
3.3 map 容器
作为关联式容器的一种,map
容器存储的都是 pair
对象,也就是用 pair
类模板创建的键值对。其中,各个键值对的键和值可以是任意数据类型,包括 C++ 基本数据类型(int
、double
等)、使用结构体或类自定义的类型。
使用 map
容器存储的各个键值对,键的值既不能重复也不能被修改。换句话说,map 容器中存储的各个键值对不仅键的值独一无二,键的类型也会用 const
修饰,这意味着只要键值对被存储到 map
容器中,其键的值将不能再做任何修改
map
容器存储的都是 pair
类型的键值对元素,更确切的说,该容器存储的都是 pair
类型(其中 K
和 T
分别表示键和值的数据类型)的键值对元素
map
容器定义在 头文件中,并位于
std
命名空间中。因此,如果想使用 map 容器,代码中应包含如下语句:
#include
// 没有引入std空间
std::map<int,int> mapTest;
using namespace std;
map<int,int> mapTest;
map
类模板定义如下 :
template <typename _Key, // 指定key的类型
typename _Tp, // 指定value的类型
typename _Compare = std::less<_Key>,//指定比较器的类型
typename _Alloc = std::allocator<std::pair<const _Key, _Tp> > >
class map{
}
C++中创建map的方法
源文件代码
int32 RelConTest::mapCreTest()
{
//1 通过调用map容器类的默认构造函数,可以创建出一个空的map容器
std::map<std::string,int32> mapTest;
//2 在创建map的同时进行初始化
std::map<std::string,int32> mapInit{{"C++",99},{"algorithm",90}};
//3 map容器中存储的键值对,其本质都是pair类模板创建的pair对象
// 上面的代码使用pair改写
std::map<std::string,int32> mapPair{std::make_pair("C++",99),std::make_pair("algorithm",90)};
//4 利用先前已创建好的map容器,再创建一个新的map容器
std::map<std::string,int32> mapNew(mapPair);
//5 在创建map的同时 指定排序规则
std::map<int32,std::string,std::less<int32>> mapSort;
return 0;
}
头文件代码
class Item;
struct ItemPriority;
typedef std::pair<string,int32> strIntPair;
typedef std::map<int32,Item,std::greater<int32>> ItemMap;
class RelConTest
{
public:
RelConTest();
int32 pairCreTest();
int32 mapFuncTest();
};
class Item
{
public:
Item() {}
Item(int32 iItemId,int32 iPriority)
: m_iItemId(iItemId),
m_iPriority(iPriority){}
friend std::ostream& operator <<(std::ostream& os,const Item& item);
public:
int32 m_iItemId;
int32 m_iPriority;
};
// 函数对象类
struct ItemPriority
{
ItemPriority();
// 重载 ()
bool operator()(const Item& l,const Item& r)
{
if(l.m_iPriority != r.m_iPriority)
{
return l.m_iPriority < r.m_iPriority;
}
return l.m_iItemId < r.m_iItemId;
}
};
C++ map容器包含的成员方法
int32 RelConTest::mapFuncTest()
{
ItemMap itemMap;
itemMap.insert(make_pair(10001,Item(10001,10)));
itemMap.insert(make_pair(10007,Item(10007,10)));
itemMap.insert(make_pair(10002,Item(10007,10)));
itemMap.insert(make_pair(10835,Item(10835,10)));
itemMap.insert(make_pair(17331,Item(17331,10)));
itemMap.insert(make_pair(18023,Item(18023,10)));
// map的遍历
// begin() end()
std::map<int32,Item>::iterator iter = itemMap.begin();
for(;iter != itemMap.end();++iter)
{
cout << "[" << iter->first << "] : " << iter->second << endl;
}
/**
*
* 在map容器中查找键为key的键值对,如果成功找到,则返回指向该键值对的双向迭代器;反之,
* 则返回和end()方法一样的迭代器。另外,如果map容器用const 限定,则该方法返回的是const类型的双向迭代器
*
*/
std::map<int32,Item>::iterator it = itemMap.find(10001);
if (it != itemMap.end())
{
cout << "find it" << endl;
}
else
{
cout << "not find please check it" << endl;
}
/**
* lower_bound()
* 返回一个指向当前map容器中第一个大于或等于
* key的键值对的双向迭代器。如果map容器用const限定,
* 则该方法返回的是const类型的双向迭代器
*
*/
std::map<int32,Item>::iterator lower_bound_it = itemMap.lower_bound(10007);
if (lower_bound_it != itemMap.end())
{
cout << "upper_bound : " << (lower_bound_it->first) << endl;
}
else
{
cout << "not find it "<< endl;
}
/**
*
* 返回一个指向 大于给定key的迭代器 如果找不到返回end()
*/
std::map<int32,Item>::iterator upper_bound_it = itemMap.upper_bound(10002);
cout << (upper_bound_it != itemMap.end()) << endl;
/*
* 该方法返回一个pair对象(包含 2 个双向迭代器),其中pair.first和lower_bound()方法的返回值等价,
* pair.second和upper_bound()方法的返回值等价。
* 也就是说,该方法将返回一个范围,该范围中包含的键为key的键值对(map容器键值对唯一,因此该范围最多包含一个键值对)
*/
cout << "equal_range : " << endl;
std::pair<std::map<int32,Item>::iterator,std::map<int32,Item>::iterator> pairResult;
pairResult = itemMap.equal_range(10002);
cout << pairResult.first->first << endl;
cout << pairResult.second->first << endl;
cout << (pairResult.first == pairResult.second) << endl;
// 移除map指向的元素 并返回离被删除元素最近的元素的
std::map<int32,Item>::iterator erIt = itemMap.erase(itemMap.begin());
cout << "erIt->first : " << erIt->first << endl;
// 键值对的个数
cout << "size : " << itemMap.size() << endl;
return 0;
}
map获取键对应的值的两种方法
map
中重载了 []
这意味着,类似于借助数组下标可以直接访问数组中元素,通过指定的键,我们可以轻松获取 map 容器中该键对应的值
使用at()
成员函数
除了借助 [ ]
运算符获取 map
容器中指定键对应的值,还可以使用 at()
成员方法。和前一种方法相比,at()
成员方法也需要根据指定的键,才能从容器中找到该键对应的值;不同之处在于,如果在当前容器中查找失败,该方法不会向容器中添加新的键值对,而是直接抛出 out_of_range
异常。
C++ 11 map insert 的四种用法
/**
1、引用传递一个键值对val表示一个键值对 该方法会返回一个pair对象,其中pair.first表示一个迭代器,pair.second为一个bool类型变量:
1) 如果成功插入val则该迭代器指向新插入的 val,bool值为true;
2) 如果插入val失败,则表明当前map容器中存有和val的键相同的键值对(用p表示),此时返回的迭代器指向p,bool值为false
*/
pair<iterator,bool> insert (const value_type& val);
//2、以右值引用的方式传递键值对
template <class P>
pair<iterator,bool> insert (P&& val);
insert()
方法还支持向map
容器的指定位置插入新键值对,该方法的语法格式如下//以普通引用的方式传递 val 参数
iterator insert (const_iterator position, const value_type& val);
//以右值引用的方式传递 val 键值对参数
template <class P>
iterator insert (const_iterator position, P&& val);
3.4 multimap 容器
公共的头文件部分commondef.h
#ifndef COMMONDEF_H
#define COMMONDEF_H
#include
#include
#include
#include
#include
#include
#include
#include // pair 类模板定义在头文件中
#include
#include
#include
#include
#include
#include
#define TABLE_NUM 14
#define AISTD std::
#define TABLE_NAME_LEN 128
const char PATH_SEPARATOR = '/';
#define DATE_CHANGE_NUM 1000000LL
#define BUFFER_SIZE 1024
#define LINE cout << "********************************************************" << endl;
#define LINEFEED cout << endl;
#define FUNCTION_BEGIN \
cout << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << " : begin >>> " << endl;
#define FUNCTION_END \
cout << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << " : end >>> " << endl;
typedef std::string aistring;
typedef int int32;
typedef long long int64;
typedef short int int16;
using namespace std;
#endif // COMMONDEF_H
简单的理解容器适配器,其就是将不适用的序列式容器(包括 vector、deque 和 list)变得适用。容器适配器的底层实现和模板 A、B 的关系是完全相同的,即通过封装某个序列式容器,并重新组合该容器中包含的成员函数,使其满足某些特定场景的需要。
STL 提供了 3 种容器适配器,分别为 stack
栈适配器、queue
队列适配器以及 priority_queue
优先权队列适配器。其中,各适配器所使用的默认基础容器以及可供用户选择的基础容器
容器适配器 | 基础容器筛选条件 | 默认使用的基础容器 |
---|---|---|
stack | 基础容器需包含以下成员函数: empty() size() back() push_back() pop_back() 满足条件的基础容器有 vector、deque、list | deque |
queue | 基础容器需包含以下成员函数: empty() size() front() back() push_back() pop_front() 满足条件的基础容器有 deque、list | deque |
priority_queue | 基础容器需包含以下成员函数: empty() size() front() push_back() pop_back() 满足条件的基础容器有vector、deque | vector |
stack容器适配器的创建
/**
*
* stack使用的基础容器有 :
* - vector
* - list
* - deque (默认)
* @brief AdapterTest::stackTest
* @return
*
*/
int32 AdapterTest::stackTest()
{
// 创建一个不包含任何元素的 stack 适配器,并采用默认的 deque 基础容器
stack<int32> s1;
// 使用基础容器list来初始化 stack 适配器,只要该容器的类型和 stack 底层使用的基础容器类型相同即可
stack<int32,list<int32>> s2;
for(int i = 0;i < 10;++i)
{
// 压栈
s1.push(i);
}
if(!s1.empty())
{
// 栈顶元素
cout << "top : " << s1.top() << endl;
// 栈中元素的个数
cout << "size : " << s1.size() << endl;
}
while(!s1.empty()){
std::cout << s1.top() << " ";
s1.pop();
}
std::cout << endl;
return 0;
}
和 stack
栈容器适配器不同,queue
容器适配器有 2 个开口,其中一个开口专门用来输入数据,另一个专门用来输出数据
最先进入 queue
的元素,也可以最先从 queue
中出来,即用此容器适配器存储数据具有“先进先出(简称 “FIFO” )”的特点,因此 queue
又称为队列适配器。
queue适配器的创建及常用成员函数
int32 AdapterTest::queueTest()
{
// 创建一个空的 queue 容器适配器,其底层使用的基础容器选择默认的 deque 容器
queue<int32> q1;
// 创建了一个使用 list 容器作为基础容器的空 queue 容器适配器
queue<int32,list<int32>> q2;
// 用基础容器来初始化 queue 容器适配器,只要该容器类型和 queue 底层使用的基础容器类型相同即可
std::deque<int32> values{1,6,7,10,12};
queue<int32> q3(values);
/**
* queue支持的成员函数
* - empty()
* - front() 返回queue中第一个元素的引用.如果queue是常量,就返回一个常引用;如果queue为空,返回值是未定义的
* - back() 返回queue中最后一个元素的引用.如果queue是常量,就返回一个常引用;如果 queue 为空,返回值是未定义的
* - push() 在queue的尾部添加一个元素的副本.这是通过调用底层容器的成员函数push_back()来完成的.
* - pop() 删除 queue 中的第一个元素
*/
cout << "empty : " << q3.empty() << endl;
int32& val = q3.front();
cout << "val : " << val << endl;
val = q3.back();
cout << "val : " << val << endl;
q3.push(20);
val = q3.back();
cout << "val : " << val << endl;
while (! q3.empty())
{
cout << "front ele " << q3.front() << endl;
q3.pop();
}
return 0;
}
priority_queue 容器适配器模拟的也是队列这种存储结构,即使用此容器适配器存储元素只能“从一端进(称为队尾),从另一端出(称为队头)”,且每次只能访问 priority_queue 中位于队头的元素
但是,priority_queue 容器适配器中元素的存和取,遵循的并不是 “First in,First out”(先入先出)原则,而是"First in,Largest out"原则。直白的翻译,指的就是先进队列的元素并不一定先出队列,而是优先级最大的元素最先出队列
priority_queue 容器适配器为了保证每次从队头移除的都是当前优先级最高的元素,每当有新元素进入,它都会根据既定的排序规则找到优先级最高的元素,并将其移动到队列的队头;同样,当 priority_queue 从队头移除出一个元素之后,它也会再找到当前优先级最高的元素,并将其移动到队头
基于 priority_queue 的这种特性,因此该容器适配器有被称为优先级队列
template <typename T,
typename Container=std::vector<T>,
typename Compare=std::less<T> >
class priority_queue{
//......
}
typename T
:指定存储元素的具体类型;
typename Container
:指定 priority_queue
底层使用的基础容器,默认使用 vector
容器
typename Compare
:指定容器中评定元素优先级所遵循的排序规则,默认使用std::less
按照元素值从大到小进行排序,还可以使用std::greater
按照元素值从小到大排序,但更多情况下是使用自定义的排序规则
由于 priority_queue 容器适配器模板位于头文件中,并定义在 std 命名空间里,因此在试图创建该类型容器之前,程序中需包含以下 2 行代码:
#include
using namespace std;
/**
* priority_queue 使用的基础容器
* - vector (默认)
* - dequeu
* @brief AdapterTest::priorityQueueTest
* @return
*/
int32 AdapterTest::priorityQueueTest()
{
// 创建一个空的priority_queue容器适配器,底层采用默认的vector容器,排序方式也采用默认的std::less方法
std::priority_queue<int32> pq;
// 可以使用普通数组或其它容器中指定范围内的数据,对priority_queue容器适配器进行初始化:
int values[]{20,30,90,17,23,45};//使用普通数组
std::priority_queue<int32> q1(values,values+5);
std::vector<int32> v1{100,78,32,87,49,23};//使用向量
std::priority_queue<int32> q2(v1.begin(),v1.end());
// 指定优先级队列的底层排序规则 小的排在前面
std::priority_queue<int32,std::deque<int32>,std::greater<int32>> q3(v1.begin(),v1.end());
/**
* priority_queue提供的成员函数
* - empty() 如果 priority_queue 为空的话,返回 true;反之,返回 false
* - size() 返回 priority_queue 中存储元素的个数
* - top() 返回 priority_queue 中第一个元素的引用形式
* - push(const T& obj)
* 根据既定的排序规则,将元素 obj 的副本存储到 priority_queue 中适当的位置。
* - push(T&& obj)
* 根据既定的排序规则,将元素 obj 移动存储到 priority_queue 中适当的位置
* - pop()
* 移除 priority_queue 容器适配器中第一个元素
* - swap(priority_queue& other)
* 将两个priority_queue容器适配器中的元素进行互换,
* 需要注意的是,进行互换的2个priority_queue容器
* 适配器中存储的元素类型以及底层采用的基础容器类型
* 都必须相同
*/
cout << "size : " << q3.size() << endl;
while (!q3.empty())
{
cout << q3.top() << " ";
q3.pop();
}
cout << endl;
cout << "---------------------q2---------------------" << endl;
cout << "size : " << q2.size() << endl;
while (!q2.empty())
{
cout << q2.top() << " ";
q2.pop();
}
cout << endl;
int32 nums[]{10,34,56,89,78,20};
std::priority_queue<int32> q4(nums,nums+5);
q2.swap(q4);
cout << "---------------------q2---------------------" << endl;
while (!q2.empty())
{
cout << q2.top() << " ";
q2.pop();
}
cout << endl;
return 0;
}
template <typename T>
// 函数对象类
class IntegerComp
{
public:
IntegerComp() {}
//重载()
bool operator()(const T& l,const T& r)
{
return l < r;
}
};
上面的 class
关键字也可以使用 struct
关键字替代
// 函数对象类
template <typename T>
struct IntegerComp
{
public:
IntegerComp() {}
//重载()
bool operator()(const T& l,const T& r)
{
return l > r;
}
};
自定义优先级 coding
/**
*
*
* 优先级队列自定义排序规则
* @brief AdapterTest::priorityQueueCustomerTest
* @return
*/
int32 AdapterTest::priorityQueueCustomerTest()
{
int values[]{10,6,23,78,87,90};
// l < r 时升序
// l > r 时降序
std::priority_queue<int32,std::deque<int32>,IntegerComp<int32>> prioQueue(values,values + 6);
cout << "------------prioQueue: ------------" << endl;
while(! prioQueue.empty())
{
cout << prioQueue.top() << " ";
prioQueue.pop();
}
cout << endl;
}