目录
1.stack与queue
stack
queue
2.priority_queue
2.1相关介绍
2.2模拟实现priority_queue
--仿函数:
--push
--pop
--top
--size
--empty
--迭代器区间构造
2.3仿函数
3.容器适配器
stack模拟实现
queue模拟实现
学习目标:
1.stack和queue介绍与使用
2.priority_queue的介绍和使用
3.容器适配器
1.stack与queue
stack
queue
stack与queue比较
- stack:只能尾插尾删,提供top(栈顶)
- queue:只能头删尾插,提供front,back
list与vector比较
- list:
- 插入删除效率高,提供了push_back,pop_back,push_front,pop_front
- 不支持随机访问,只有front,back
- vector:
- 头插头删效率低,提供了:push_back,pop_back
- 支持随机访问,提供了[],front,back
2.priority_queue
2.1相关介绍
1.优先级队列是一种容器适配器,它的第一个元素总是它包含元素的中最大的
2.与堆类似
3.接口功能与queue基本相同,其pop相当于弹出堆顶元素
4.其参数:
使用仿函数来决定是建立大堆或小堆
1.默认情况下priority_queue是大堆, 若要建立小堆:将第三个模板参数换位greater
priority_queue<int, vector<int>, greater<int>> q;
2.如果在priority_queue中放自定义类型的数据,用户需要在自定义类型中提供> 或者< 的重载
2.2模拟实现priority_queue
思路:
1.选择vector容器
2.priority_queue与堆类似,相当于完全二叉树
--插入数据: 1.在尾部插入数据2.开始向上调整
--删除数据: 1.将堆顶元素与尾部元素交换 2.从堆顶开始向下调整
3.使用仿函数来改变大小堆的建立
--仿函数:
template<class T> struct less { bool operator()(const T& left, const T& right) { return left < right; } }; template<class T> struct greater { bool operator()(const T& left, const T& right) { return left > right; } };
--push
void push(const T& x) { //1.在尾部插入元素 _con.push_back(x); //2.向上调整(从尾部) addjust_up(size()-1); } void addjust_up(size_t child) { Cmp cmp; size_t parent = (child - 1) / 2; while (child > 0) { //孩子比父节点大,交换 /*if (_con[child] > _con[parent]) */ if (cmp(_con[parent] , _con[child])) { swap(_con[child],_con[parent]); child = parent; parent = (child - 1) / 2; } //否则直接结束 else { break; } } }
--pop
void pop() { if (empty()) return; //1.交换堆顶与尾部元素 swap(_con[0],_con[size()-1]); _con.pop_back(); //2.向下调整(从根) addjust_down(0); } void addjust_down(size_t parent) { Cmp cmp; size_t child = parent * 2 + 1; //2.向下调整 while (child < size()) { //1.找到孩子节点较大的一个 /*if (child + 1 < size() - 1 && _con[child + 1] > _con[child]) */ if (child + 1 < size() - 1 && cmp(_con[child], _con[child + 1])) { ++child; } /*if (_con[child] > _con[parent]) */ if (cmp(_con[parent], _con[child])) { swap(_con[child],_con[parent]); parent = child; child = parent * 2 + 1; } else { break; } } }
--top
//堆顶元素不可修改,改了会改变堆的性质 const T& top() { return _con.front(); }
--size
size_t size() { return _con.size(); }
--empty
bool empty() { return _con.empty(); }
--迭代器区间构造
//迭代器区间构造 template<class iterator> priority_queue(iterator first,iterator last) :_con(first,last) { //从队列中第一个非叶子节点开始向下调整 for (int num = ((size() - 1) - 1) / 2; num >= 0; num--) { addjust_down(num); } }
效果展示:
2.3仿函数
仿函数:通常指的是可以像函数一样调用的对象
仿函数是一个类或对象,它实现函数调用运算符operate(),使你可以像调用普通函数一样使用仿函数来执行一些操作
与C语言中的回调函数功能类似,回调函数作为参数传递给另一个函数,并且可以在后者执行过程中被调用, 其通常作为函数指针或函数引用的形式
示例:
template<class T> struct Less { bool operator()(const T& left, const T& right) { return left < right; } }; void test1() { Less<int> cmp; cout << cmp(1, 2) << endl; }
效果:
3.容器适配器
1.适配器定义:适配器是一种模式,该模式把类的接口转换为用户期望的另一个接口
stack和queue被成为容器适配器:这是因为stack和queue只是对其他容器的接口进行了包装,STL中stack和queue默认使用deque
stack模拟实现
template<class T,class Container = deque<T>> class Stack { public: //构造函数 Stack() {} void push(const T& x) { _con.push_back(x); } void pop() { _con.pop_back(); } const T& top() { return _con.back(); } const size_t size() { return _con.size(); } bool empty() { return _con.empty(); } private: Container _con; };
queue模拟实现
template<class T , class container = deque<T>> class Queue { public: //构造函数 Queue() {} void push(const T& x) { _con.push_back(x); } void pop() { _con.pop_front(); } T& back() { return _con.back(); } const T& back()const { return _con.back(); } const T& front()const { return _con.front(); } size_t size() const { return _con.size(); } bool empty() { return _con.empty(); } private: container _con; };