目录
- 前言
- 一、栈(stack)
- 1. 基本代码结构
- 2. 简介
- 3. 成员类型
- 4. 成员函数
- 1. 构造函数
- 2. empty()
- 3. size()
- 4. top()
- 5. push()
- 6.pop()
- 7. 综合测试实现的stack的所有函数接口
- 二、队列(queue)
- 1. 基本代码结构
- 2. 队列的简介
- 3. 成员类型
- 4. 成员函数
- 1. 构造函数
- 2. empty()
- 3. size()
- 4. front()
- 5. back()
- 6. push()
- 7. pop()
- 8. 综合测试实现的queue的所有函数接口
- 三、优先级队列(priority_queue)
- 1. 基本代码结构
- 2. 简介
- 3. 成员类型
- 4. 成员函数
- 1. 构造函数
- 2. empty()
- 3. size()
- 4. top()
- 5. push()
- 6. pop()
- 7. 综合测试实现的priority_queue的所有函数接口
前言
前面我们学习的都是C++标准模板库中的一些容器,今天我们要学习几个容器适配器,容器适配器的底层原理是通过适配另一个容器的功能来完成当前容器功能的实现,今天学习的栈和队列是通过deque来适配的,下面我们详细讲解stack和queue还有priority_queue的模拟实现
一、栈(stack)
1. 基本代码结构
2. 简介
3. 成员类型
4. 成员函数
1. 构造函数
栈的底层是使用deque来进行适配的,deque是一个自定义类型的成员,所以栈自身不需要实现默认构造函数,编译器生成的默认构造函数会去调用deque的默认构造函数完成初始化。
2. empty()
这个函数的功能是判断栈是否为空,如果为空则返回true,如果不为空,则返false。同样的道理,stack的底层是适配了一个deque,所以直接调用deque的empty()完成判断即可。
- 代码:
bool empty() const
{
return _con.empty();
}
3. size()
这个函数的功能是求栈中的元素个数。同样的道理,stack的底层是适配了一个deque,所以直接调用deque的size()完成判断即可。
- 代码:
size_t size() const
{
return _com.size();
}
4. top()
这个函数的功能是求栈的栈顶元素。同样的道理,stack的底层是适配了一个deque,所以直接调用deque的back()完成判断即可。
- 代码:
const T& top() const
{
return _con.back();
}
T& top()
{
return _con.back();
}
5. push()
这个函数的功能是将元素入栈。同样的道理,stack的底层是适配了一个deque,所以直接调用deque的push_back()完成判断即可。
- 代码:
void push(const T& val)
{
_con.push_back(val);
}
6.pop()
这个函数的功能是将元素出栈。同样的道理,stack的底层是适配了一个deque,所以直接调用deque的pop_back()完成判断即可。
- 代码:
void pop()
{
_con.pop_back();
}
7. 综合测试实现的stack的所有函数接口
- 代码:
void test_stack()
{
hjt::stack<int> st;
st.push(1);
st.push(2);
st.push(3);
st.push(4);
st.push(5);
while (!st.empty())
{
cout << st.top() << " ";
st.pop();
}
cout << endl;
}
int main()
{
test_stack();
return 0;
}
运行结果:
二、队列(queue)
1. 基本代码结构
namespace hjt
{
template <class T,class Container = deque<T>>
class queue
{
public:
// 成员函数
private:
Container _con;
};
}
2. 队列的简介
3. 成员类型
4. 成员函数
1. 构造函数
队列的底层是使用deque来进行适配的,deque是一个自定义类型的成员,所以队列自身不需要实现默认构造函数,编译器生成的默认构造函数会去调用deque的默认构造函数完成初始化。
2. empty()
这个函数的功能是判断队列是否为空,如果为空则返回true,如果不为空,则返false。同样的道理,queue的底层是适配了一个deque,所以直接调用deque的empty()完成判断即可。
- 代码:
bool empty() const
{
return _con.empty();
}
3. size()
这个函数的功能是求队列中的元素个数。同样的道理,queue的底层是适配了一个deque,所以直接调用deque的size()完成判断即可。
- 代码:
size_t size() const
{
return _con.size();
}
4. front()
这个函数的功能是求队列的队头元素。同样的道理,queue的底层是适配了一个deque,所以直接调用deque的front()完成判断即可。
- 代码:
const T& front() const
{
return _con.front();
}
T& front()
{
return _con.front();
}
5. back()
这个函数的功能是求队列的队尾元素。同样的道理,queue的底层是适配了一个deque,所以直接调用deque的back()完成即可。
- 代码:
const T& back() const
{
return _con.back();
}
T& back()
{
return _con.back();
}
6. push()
这个函数的功能是将元素入队。同样的道理,queue的底层是适配了一个deque,所以直接调用deque的push_back()完成即可。
- 代码:
void push(const T& val)
{
_con.push_back(val);
}
7. pop()
这个函数的功能是将元素出队。同样的道理,queue的底层是适配了一个deque,所以直接调用deque的pop_front()完成即可。
- 代码:
void pop()
{
_con.pop_front();
}
8. 综合测试实现的queue的所有函数接口
- 代码:
void test_queue()
{
hjt::queue<int> q;
q.push(1);
q.push(2);
q.push(3);
q.push(4);
q.push(5);
q.push(6);
while (!q.empty())
{
cout << q.front() << " ";
q.pop();
}
cout << endl;
}
- 运行结果:
三、优先级队列(priority_queue)
1. 基本代码结构
// 实现优先级队列
template <class T,class Container = vector<T>>
class priority_queue
{
public:
// 成员函数
private:
Container _con;
};
2. 简介
3. 成员类型
4. 成员函数
1. 构造函数
优先级队列的底层是使用vector来进行适配的,vector是一个自定义类型的成员,所以优先级队列自身不需要实现默认构造函数,编译器生成的默认构造函数会去调用vector的默认构造函数完成初始化。
2. empty()
这个函数的功能是判断优先级队列是否为空,如果为空则返回true,如果不为空,则返false。同样的道理,priority_queue的底层是适配了一个vector,所以直接调用vector的empty()完成判断即可。
- 代码:
bool empty() const
{
return _con.empty();
}
3. size()
这个函数的功能是求优先级队列中元素个数,同样的道理,priority_queue的底层是适配了一个vector,所以直接调用vector的empty()完成判断即可。
- 代码:
size_t size() const
{
return _con.size();
}
4. top()
这个函数的功能是求优先级队列中队顶元素,队顶元素是第一个元素,所以返回_con中的第一个元素即可。
- 代码:
const T& top() const
{
return _con[0];
}
5. push()
这个函数的功能是将数据插入priority_queue中,并且要保证插入数据之后仍然满足堆的性质,所以还需要实现一个向上调整算法
- 代码:
void push(const T& val)
{
_con.push_back(val);
AjustUp(_con.size() - 1);
}
void AjustUp(int child)
{
int parent = (child - 1) / 2;
while (child > 0)
{
if (_con[parent] < _con[child])
{
swap(_con[parent], _con[child]);
child = parent;
parent = (child - 1) / 2;
}
else
{
break;
}
}
}
6. pop()
这个函数的功能是删除priority_queue中的队顶元素,并且要保证插入数据之后仍然满足堆的性质,所以还需要实现一个向下调整算法
void pop()
{
assert(!_con.empty());
swap(_con[0], _con[_con.size() - 1]);
_con.pop_back();
AjustDown(0);
}
void AjustDown(int parent)
{
int child = parent * 2 + 1;
while (child < _con.size())
{
if(child + 1 < _con.size() && _con[child] < _con[child + 1])
{
child++;
}
if (_con[parent] < _con[child])
{
swap(_con[parent], _con[child]);
parent = child;
child = parent * 2 + 1;
}
else
{
break;
}
}
}
7. 综合测试实现的priority_queue的所有函数接口
- 代码
void test_priority_queue()
{
hjt::priority_queue<int> pq;
pq.push(1);
pq.push(2);
pq.push(3);
pq.push(4);
pq.push(5);
pq.push(6);
cout << "pq:" << endl;
while (!pq.empty())
{
cout << pq.top() << " ";
pq.pop();
}
cout << endl;
hjt::priority_queue<int> pq1;
pq1.push(3);
pq1.push(1);
pq1.push(2);
pq1.push(5);
pq1.push(6);
pq1.push(7);
cout << "pq1:" << endl;
while (!pq1.empty())
{
cout << pq1.top() << " ";
pq1.pop();
}
cout << endl;
}
- 运行结果: