1.list的介绍及使用
list是STL中的带头双向循环链表,list中的接口比较多,此处类似,只需要掌握如何正确的使用,然后再去深入研究背后的原理,已达到可扩展的能力。以下为list中一些常见的重要接口。
1.1list的构造
以下是list构造的解释以及标准库的介绍。


1.2list的迭代器
list 的迭代器属于双向迭代器,仅支持 ++/-- 单步移动,不支持 +/- 跳步操作;vector 的迭代器属于随机迭代器,除了支持双向迭代器的全部功能,还支持 +/- 跳步、[] 随机访问等操作。list 的节点在空间上不连续,因此插入操作不会导致迭代器失效,但删除节点会导致指向该节点的迭代器失效;而 vector 因内存连续,插入(扩容 / 移动)和删除(元素移动)都会导致迭代器失效。



1.3list capacity
由于list的节点在空间上不是连续的所以list提供了专门的接口来记录list的capacity。



1.4list element access
以下是返回头尾节点的接口。

1.5list modifiers
以下是list的增删查改接口。

2.stack
2.1.stack的使用
以下是stack的常用接口。

以下是最小栈的解法。
cpp
class MinStack
{
public:
void push(int x)
{
// 只要是压栈,先将元素保存到_elem中
_elem.push(x);
// 如果x小于_min中栈顶的元素,将x再压入_min中
if(_min.empty() || x <= _min.top())
_min.push(x);
}
void pop()
{
// 如果_min栈顶的元素等于出栈的元素,_min顶的元素要移除
if(_min.top() == _elem.top())
_min.pop();
栈的弹出压入序列
逆波兰表达式求值
_elem.pop();
}
int top(){return _elem.top();}
int getMin(){return _min.top();}
private:
// 保存栈中的元素
std::stack<int> _elem;
// 保存栈的最小值
std::stack<int> _min;
};
1.2stack的模拟实现
栈的特性和vector有些相似所以在模拟实现栈是完全可以使用vector来模拟实现。
cpp
#include<vector>
namespace bite
{
template<class T>
class stack
{
public:
stack() {}
void push(const T& x) {_c.push_back(x);}
void pop() {_c.pop_back();}
T& top() {return _c.back();}
const T& top()const {return _c.back();}
size_t size()const {return _c.size();}
bool empty()const {return _c.empty();}
private:
std::vector<T> _c;
};
}
3.queue
3.1queue的使用
以下是queue的常用接口。

3.2queue的模拟实现
因为queue的接口中存在头删和尾插,因此使用vector来封装效率太低,故可以借助list来模拟实现queue,具体如下:
cpp
#include <list>
namespace bite
{
template<class T>
class queue
{
public:
queue() {}
void push(const T& x) {_c.push_back(x);}
void pop() {_c.pop_front();}
T& back() {return _c.back();}
const T& back()const {return _c.back();}
T& front() {return _c.front();}
const T& front()const {return _c.front();}
size_t size()const {return _c.size();}
bool empty()const {return _c.empty();}
private:
std::list<T> _c;
};
}
4.priority_queue的介绍和使用
4.1priority_queue的使用
priority_queue(优先级队列)是 C++ STL 的容器适配器,底层基于堆(heap)结构实现。默认情况下,它通过less<T>比较规则实现大顶堆(较大的元素优先出队);也可通过指定模板参数(如greater<T>)改为小顶堆,或自定义仿函数实现任意优先级规则。

4.2priority_queue的模拟实现
由于priority_queue底层就是堆所以可以使用vector对其进行封装就可以实现了。不过由于vector是顺序表所以还需我们自行实现向上向下调整算法。如下:
cpp
template <class T>
class myless
{
public:
bool operator()(const T& x,const T& y)
{
return x < y;
}
};
template <class T>
class mygreater
{
public:
bool operator()(const T& x, const T& y)
{
return x > y;
}
};
template <class T, class Container = std::vector<T>, class Compare = std::less<T> >
class priority_queue
{
public:
priority_queue()
{
}
template <class InputIterator>
priority_queue(InputIterator first, InputIterator last);
bool empty() const
{
return c.empty();
}
size_t size() const
{
return c.size();
}
T& top()
{
return c.front();
}
const T& top() const
{
return c.front();
}
void a(size_t x)
{
size_t y = (x - 1) / 2;
while (x > 0)
{
if (comp(c[x], c[y]))
{
std::swap(c[x], c[y]);
x = y;
y = (x - 1) / 2;
}
else {
break;
}
}
}
void b(size_t x)
{
size_t y = 2 * x + 1;
while (y < c.size())
{
if ((y + 1) < c.size() && comp(c[y], c[x]))
{
++y;
}
if (comp(c[y], c[x]))
{
std::swap(c[x], c[y]);
x = y;
y = x * 2 + 1;
}
else
{
break;
}
}
}
void push(const T& x)
{
c.push_back(x);
a(c.size() - 1);
}
void pop()
{
std::swap(c[0], c[c.size() - 1]);
c.pop_back();
b(0);
}
private:
Container c;
Compare comp;
};
5.容器适配器
适配器是一种设计模式(设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结),该种模式是将一个类的接口转换成客户希望的另外一个接口。STL标准库中sstack、queue的底层使用的其实是容器适配器默认使用deque。
5.1deque的简单介绍
deque(双端队列)结合了 vector(支持随机下标访问)和 list(头尾增删效率高)的核心优点:既可以像 vector 一样通过下标随机访问元素,又能像 list 一样高效完成头尾的插入 / 删除操作。但 deque 无法完全取代 vector 和 list------ 它的中间位置 insert/erase 效率极低,随机访问效率略低于 vector,中间操作效率远低于 list。deque 的底层并非二维数组,而是由 "中控数组 + 多个分段连续的内存块" 组成,通过迭代器的无缝跳转逻辑,保证了元素在逻辑上的连续性;且 deque 在扩容时无需拷贝全部元素,这一点比 vector 更高效。以下是deque的底层结构:
