08 stack、queue和priority_queue的使用和模拟实现
2021/11/11 23:12:29
本文主要是介绍08 stack、queue和priority_queue的使用和模拟实现,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
stack和queue在STL中并没有将其划分在容器的行列,而是将其称为容器适配器,这是因为stack和queue只是对其他容器的接口进行了包装,STL中stack和queue默认使用deque容器。
文章目录
- 一、容器适配器
- 二、stack
- 模拟实现stack
- 三、queue
- 模拟实现queue
- 四、priority_queue
- 使用优先级队列排序日期类
- 模拟实现priority_queue
一、容器适配器
容器适配器 是一个封装了序列容器的类模板,它在一般序列容器的基础上提供了一些不同的功能。 之所以称作适配器类,是因为它可以通过适配容器现有的接口来提供不同的功能。
说白了就是通过一种容器来实现另一种容器的功能,比如用链表实现栈,栈的push操作就可以用链表的push_back来实现,而栈的pop操作用链表的pop_back实现,至于链表的其他接口(栈用不到的接口,比如头插头删)则不对外进行暴露,因此虽然表面上看上去是一个栈,但是在底层实现上确是一个链表。
STL中的stack和queue在底层上默认用的是双端队列deque:
Container是一个缺省参数,我们在使用的时候可以自定义这个容器适配器,比如不想用deque而想用vector或list,直接在实例化对象的时候传入vector或list即可。
二、stack
stack是STL中的栈,其功能和数据结构中的栈一样。
常用接口:
成员函数 | 功能 |
---|---|
empty() | 判断栈是否为空 |
size() | 获取栈中有效元素个数 |
top() | 获取栈顶元素 |
push(x) | 将元素x入栈 |
pop() | 栈顶元素出栈 |
swap() | 交换两个栈中的数据 |
#include <iostream> #include <stack> #include <list> using namespace std; int main() { stack<int, list<int>> st;//用list作为容器适配器 st.push(1); st.push(2); st.push(3); st.push(4); cout << st.size() << endl; //4 while (!st.empty()) { cout << st.top() << " "; st.pop(); } cout << endl; //4 3 2 1 stack<int, list<int>> st1; st1.swap(st);//交换st到st1 cout << st.size() << endl; //0 while (!st.empty()) { cout << st.top() << " ";//空 st.pop(); } cout << endl; return 0; }
模拟实现stack
#include<deque> namespace hjl //防止命名冲突 { template<class T, class Container = std::deque<T>> class stack { public: //元素入栈 void push(const T& x) { _con.push_back(x); } //元素出栈 void pop() { _con.pop_back(); } //获取栈顶元素 T& top() { return _con.back(); } const T& top() const { return _con.back(); } //获取栈中有效元素个数 size_t size() const { return _con.size(); } //判断栈是否为空 bool empty() const { return _con.empty(); } //交换两个栈中的数据 void swap(stack<T, Container>& st) { _con.swap(st._con); } private: Container _con; }; }
三、queue
queue是STL中的队列,功能和数据结构中的队列一样。
成员函数 | 功能 |
---|---|
empty() | 判断队列是否为空 |
size() | 获取队列中有效元素个数 |
front() | 获取队头元素 |
back() | 获取队尾元素 |
push(x) | 将x入到队尾 |
pop() | 队头出队列 |
swap() | 交换两个队列中的数据 |
#include <iostream> #include <list> #include <queue> using namespace std; int main() { queue<int, list<int>> q; q.push(1); q.push(2); q.push(3); q.push(4); cout << q.size() << endl; //4 while (!q.empty()) { cout << q.front() << " "; q.pop();//队头出队列 } cout << endl; //1 2 3 4 return 0; }
模拟实现queue
#include<deque> namespace hjl //防止命名冲突 { template<class T, class Container = std::deque<T>> class queue { public: //队尾入队列 void push(const T& x) { _con.push_back(x); } //队头出队列 void pop() { _con.pop_front(); } //获取队头元素 T& front() { return _con.front(); } const T& front() const { return _con.front(); } //获取队尾元素 T& back() { return _con.back(); } const T& back() const { return _con.back(); } //获取队列中有效元素个数 size_t size() const { return _con.size(); } //判断队列是否为空 bool empty() const { return _con.empty(); } //交换两个队列中的数据 void swap(queue<T, Container>& q) { _con.swap(q._con); } private: Container _con; }; }
四、priority_queue
priority_queue又被称为优先级队列,它和队列的区别在于,默认使用vector作为底层存储数据的容器,并且在vector上又使用了堆算法将vector中元素构成堆的结构,这也就意味着如果入队一组无序的数据,在出队列时会变成有序,默认情况下priority_queue是大堆,也就是降序。
它相比于队列多了第三个参数,这个参数默认是less,建大堆(也就是降序,大数先出队列),也可以换成greater,建小堆(升序,小数先出队列)。
其接口和队列一样,只是在入队和出队时作了排序
成员函数 | 功能 |
---|---|
push(x) | 插入元素x到队尾然后排序 |
pop() | 弹出队头元素(堆顶元素) |
top() | 访问队头元素(堆顶元素) |
size() | 获取队列中有效元素个数 |
empty() | 判断队列是否为空 |
swap() | 交换两个队列的内容 |
#include <iostream> #include <functional> #include <queue> using namespace std; int main() { priority_queue<int> q; q.push(3); q.push(6); q.push(0); q.push(2); q.push(9); q.push(8); q.push(1); while (!q.empty()) { cout << q.top() << " "; q.pop(); } cout << endl; //9 8 6 3 2 1 0 priority_queue<int,vector<int>,greater<int>> q1; q1.push(3); q1.push(6); q1.push(0); q1.push(2); q1.push(9); q1.push(8); q1.push(1); while (!q1.empty()) { cout << q1.top() << " "; q1.pop(); } cout << endl; //0 1 2 3 6 8 9 return 0; }
使用优先级队列排序日期类
自定义类要使用less,必须要重载操作符<
,要使用greater,必须要重载操作符>
,并且也可以传入一个自定义的仿函数:
#include<iostream> #include<assert.h> #include<queue> #include<vector> #include <functional> using namespace std; class Date { public: Date(int year = 0, int month = 0, int day = 0); void Print(); //比较日期的大小 friend bool operator>(const Date& a,const Date& b); friend bool operator<(const Date& a, const Date& b); friend bool operator==(const Date& a, const Date& b); //日期减日期 int operator-(const Date& d); friend ostream& operator<<(ostream& out, const Date& d); private: int _year; int _month; int _day; }; //获取某年某月的天数,因为要多次调用,可以写成内联函数 inline int GetMonthDay(int year, int month) { static int dayArray[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 }; int day = dayArray[month]; if (month == 2 && ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))) { day = 29; } return day; } //构造函数 Date::Date(int year, int month, int day) { //检查日期的合法性 if (year >= 0 && month > 0 && month < 13 && day>0 && day <= GetMonthDay(year, month)) { _year = year; _month = month; _day = day; } else { cout << "非法日期"; cout << year << "-" << month << "-" << day << endl; } } //比较大小只需要实现>和==即可,其他比较操作符都可以用这两个操作符实现,提高代码复用率 bool operator>(const Date& a, const Date& b) { if (a._year > b._year) { return true; } else if (a._year == b._year) { if (a._month > b._month) { return true; } else if (a._month == b._month) { if (a._day > b._day) { return true; } } } return false; } bool operator<(const Date& a, const Date& b) { return !(a == b) && !(a > b); } bool operator==(const Date& a, const Date& b) { return a._year == b._year && a._month == b._month && a._day == b._day; } ostream& operator<<(ostream& out, const Date& d) { cout << d._year << "-" << d._month << "-" << d._day << endl; return out; } struct cmp { bool operator()(Date a, Date b) { return a > b; } }; int main() { //priority_queue<Date,vector<Date>,greater<Date>> q; //priority_queue<Date, vector<Date>, less<Date>> q; priority_queue<Date, vector<Date>,cmp> q;//传入仿函数cmp q.push(Date(1, 5, 15)); q.push(Date(10, 4, 6)); q.push(Date(7, 7, 1)); q.push(Date(10, 12, 8)); q.push(Date(5, 11, 9)); q.push(Date(10, 7, 1)); while (!q.empty()) { cout << q.top(); q.pop(); } return 0; }
模拟实现priority_queue
#include<vector> #include<iostream> namespace hjl { //比较方式(使内部结构为大堆) template<class T> struct less { bool operator()(const T& l, const T& r) { return l < r; } }; //比较方式(使内部结构为小堆) template<class T> struct greater { bool operator()(const T& l, const T& r) { return l > r; } }; //仿函数默认为less template<class T, class Container = std::vector<T>,class Compare=less<T>> class priority_queue { public: //向上调整算法,每push一个数都要调用向上调整算法,保证插入后是一个大堆 void AdjustUp(int child) { Compare com; int parent = (child - 1) / 2; while (child > 0) { if (com(_con[parent],_con[child])) { std::swap(_con[parent], _con[child]); child = parent; parent= (child - 1) / 2; } else { break; } } } //向下调整算法,每次调用pop都要进行向下调整算法重新构成大堆 void AdjustDwon(int parent) { Compare com; int child = parent * 2 + 1; while (child < _con.size()) { if (child + 1 < _con.size() &&com( _con[child] ,_con[child + 1])) { child++; } if (com(_con[parent] ,_con[child])) { std::swap(_con[parent], _con[child]); parent = child; child = parent * 2 + 1; } else { break; } } } //迭代器初始化 template<class InputIterator> priority_queue(InputIterator first, InputIterator last) :_con(first, last)//在这里传迭代器进行初始化 { for (size_t i = 1; i <_con.size(); i++) { AdjustUp(i);//向上调整建堆 } } void push(const T& x) { _con.push_back(x); AdjustUp(_con.size() - 1); } void pop() { std::swap(_con[0], _con[_con.size() - 1]); _con.pop_back(); AdjustDwon(0); } T top() { return _con[0]; } size_t size() { return _con.size(); } bool empty() { return _con.empty(); } private: Container _con; }; }
这篇关于08 stack、queue和priority_queue的使用和模拟实现的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-02在 Objective-C 中strong 和 retain有什么区别-icode9专业技术文章分享
- 2024-11-02NSString 中的 hasPrefix 有什么作用-icode9专业技术文章分享
- 2024-11-02在 C 和 Objective-C 中inline的用法是什么-icode9专业技术文章分享
- 2024-11-02文件掩码什么意思?-icode9专业技术文章分享
- 2024-11-02在 Git 提交之前运行 composer cs-fix 命令怎么实现-icode9专业技术文章分享
- 2024-11-02为 Composer 的 cs-fix 命令指定一个目录怎么实现-icode9专业技术文章分享
- 2024-11-02微信公众号开发中怎么获取用户的 unionid-icode9专业技术文章分享
- 2024-11-01lip-sync公司指南:一文读懂主要玩家和技术
- 2024-11-01Anthropic的新RAG方法——提升大型语言模型在特定领域的表现
- 2024-11-01UniApp 中组件的生命周期是多少-icode9专业技术文章分享