C++ STL顺序容器 保姆级详解

在C++的STL中,顺序容器是按顺序存储数据的容器类,用于存储和操作数据集合。顺序容器主要包括 vector、deque、list 和 forward_list,它们各自有不同的实现方式和应用场景。下面详细介绍每种顺序容器的特点、常用操作及其应用场景。

vector:动态数组

vector 是一种动态数组,可以动态调整大小,同时支持快速的随机访问

特点

  1. 连续存储vector 内部数据存储在连续的内存中,因此支持快速的随机访问(O(1))。
  2. 动态扩展:当添加新元素超过当前容量时,vector 会自动分配更大的内存块,将数据复制过去。通常,新容量是原来的 1.5 倍或 2 倍,具体取决于实现。
  3. 自动管理内存:当超出容量时,vector 会自动分配更多空间;当 vector 销毁时,内存会自动释放。
  4. 迭代器失效:当 vector 扩容或元素被删除时,原有的迭代器可能失效,因为底层内存块可能会更改。

常用操作:

push_back():在末尾添加一个元素。
pop_back():删除末尾的一个元素。
resize():调整 vector 的大小。
at():访问指定位置的元素(带边界检查)。
operator[]:访问指定位置的元素(不带边界检查)。

适用场景:

适用于需要快速随机访问和在末尾插入删除的场景。
不适合频繁在中间位置进行插入或删除的情况,因为这会导致大量元素的移动。

成员函数详情

以下是 std::vector 常用函数的原型说明,包括构造函数、元素访问、容量管理、修改操作等。

  1. 构造函数

std::vector 提供了多种构造方式,可以根据不同的需求创建 vector 对象。

//默认构造函数
std::vector<T> vec;
//创建一个空的 `vector`,不包含任何元素。

//指定大小的构造函数
std::vector<T> vec(size_t count);
//创建一个包含 count 个默认初始化元素的 vector。

//指定大小和初始值的构造函数
std::vector<T> vec(size_t count, const T& value);
//创建一个包含 count 个 value 值的元素的 vector。

//拷贝构造函数
std::vector<T> vec(const std::vector<T>& other);
//复制构造函数,用 other 中的元素创建一个新的 vector。

//移动构造函数
std::vector<T> vec(std::vector<T>&& other);
//使用 other 的内容创建新 vector,并避免拷贝,提高效率。

//初始化列表构造函数
std::vector<T> vec(std::initializer_list<T> init);
//使用初始化列表创建 vector,如 {1, 2, 3}。
  1. 元素访问
//operator[]:访问指定位置的元素,不进行边界检查。
T& operator[](size_t pos);
const T& operator[](size_t pos) const;

//at:访问指定位置的元素,带边界检查,超出范围时抛出 std::out_of_range 异常。
T& at(size_t pos);
const T& at(size_t pos) const;

//front:返回 vector 中第一个元素的引用。
T& front();
const T& front() const;

//back:返回 vector 中最后一个元素的引用。
T& back();
const T& back() const;

//data:返回指向 vector 底层数组的指针。
T* data();
const T* data() const;
  1. 迭代器
//begin:返回指向第一个元素的迭代器。
iterator begin();
const_iterator begin() const;

//end:返回指向最后一个元素之后的位置的迭代器。
iterator end();
const_iterator end() const;

//rbegin 和 rend:反向迭代器,适用于反向遍历。
reverse_iterator rbegin();
const_reverse_iterator rbegin() const;

reverse_iterator rend();
const_reverse_iterator rend() const;
//注意end()返回的迭代器指向容器末尾元素之后的位置(超尾) rend()返回的迭代器指向容器第一个元素之前的位置
  1. 容量管理
//empty:检查 vector 是否为空。
bool empty() const;

//size:返回 vector 中元素的数量。
size_t size() const;

//max_size:返回 vector 可存储的最大元素数量。
size_t max_size() const;

//reserve:预留存储空间,至少容纳指定数量的元素,以避免频繁的内存分配。
void reserve(size_t new_cap);

//capacity:返回当前分配的存储空间,可以容纳的最大元素数。
size_t capacity() const;

//shrink_to_fit:请求减少内存使用,将多余的容量释放。
void shrink_to_fit();
  1. 修改操作
//clear:清空 vector 中的所有元素。
void clear();

//insert:在指定位置插入元素或多个元素。
iterator insert(const_iterator pos, const T& value);
iterator insert(const_iterator pos, T&& value);
iterator insert(const_iterator pos, size_t count, const T& value);
template <class InputIt>
iterator insert(const_iterator pos, InputIt first, InputIt last);
iterator insert(const_iterator pos, std::initializer_list<T> ilist);

//emplace:在指定位置直接构造元素,避免拷贝或移动。
iterator emplace(const_iterator pos, Args&&... args);

//push_back:在末尾添加一个元素。
void push_back(const T& value);
void push_back(T&& value);

//emplace_back:在末尾直接构造一个元素。
template <class... Args>
void emplace_back(Args&&... args);

//pop_back:移除末尾的元素。
void pop_back();

//erase:删除指定位置或区间的元素。
iterator erase(const_iterator pos);
iterator erase(const_iterator first, const_iterator last);

//resize:调整 vector 的大小,如果新大小小于当前大小,则删除末尾元素;如果大于当前大小,则添加默认值或指定值的元素。
void resize(size_t count);
void resize(size_t count, const T& value);

//swap:交换两个 vector 的内容。
void swap(std::vector<T>& other);
  1. 赋值操作
//operator=:将 vector 赋值为另一个 vector 或初始化列表。
vector& operator=(const vector& other);
vector& operator=(vector&& other) noexcept;
vector& operator=(std::initializer_list<T> ilist);

//assign:将 vector 的内容替换为指定数量的元素、来自迭代器区间的元素,或来自初始化列表的元素。
void assign(size_t count, const T& value);
template <class InputIt>
void assign(InputIt first, InputIt last);
void assign(std::initializer_list<T> ilist);

deque:双端队列

deque 是一种双端队列,支持在两端进行高效的插入和删除操作。

特点

  1. 双端队列deque 支持在头部和尾部进行高效的插入和删除操作,适合实现双向队列、双向缓存等结构。
  2. 分块存储deque 将数据分块存储在不同的内存块中,方便在头尾插入数据而不移动整个容器。
  3. 快速访问:虽然不像 vector 那样提供严格连续的内存,但 deque 仍支持常数时间(O(1))的随机访问,效率接近 vector
  4. 迭代器的稳定性deque 的迭代器在头部和尾部插入和删除操作时不会失效(除非扩容),但在中间插入和删除时会导致迭代器失效。

常用操作

push_front():在头部插入一个元素。
pop_front():删除头部的元素。
push_back():在尾部插入一个元素。
pop_back():删除尾部的元素。
at()operator[]:访问指定位置的元素。

适用场景

适合需要在两端频繁插入和删除的场景,如双向队列、滑动窗口等应用。
适用于需要在头尾两端进行操作并支持随机访问的情况。

成员函数详情

  1. 构造函数
//std::deque 提供了多种构造方式,用于创建不同初始化状态的 deque 对象。

//默认构造函数
//创建一个空的 deque。
std::deque<T> deq;

//指定大小的构造函数
//创建一个包含 count 个默认初始化元素的 deque。
std::deque<T> deq(size_t count);

//指定大小和初始值的构造函数
//创建一个包含 count 个 value 值的元素的 deque。
std::deque<T> deq(size_t count, const T& value);

//拷贝构造函数
//复制构造函数,用 other 中的元素创建一个新的 deque。
std::deque<T> deq(const std::deque<T>& other);

//移动构造函数
//使用 other 的内容创建新 deque,并避免拷贝,提高效率。
std::deque<T> deq(std::deque<T>&& other);

//初始化列表构造函数
//使用初始化列表创建 deque,如 {1, 2, 3}。
std::deque<T> deq(std::initializer_list<T> init);
  1. 元素访问
//operator[]:访问指定位置的元素,不进行边界检查。
T& operator[](size_t pos);
const T& operator[](size_t pos) const;

//at:访问指定位置的元素,带边界检查,超出范围时抛出 std::out_of_range 异常。
T& at(size_t pos);
const T& at(size_t pos) const;

//front:返回 deque 中第一个元素的引用。
T& front();
const T& front() const;

//back:返回 deque 中最后一个元素的引用。
T& back();
const T& back() const;
  1. 迭代器
//begin:返回指向第一个元素的迭代器。
iterator begin();
const_iterator begin() const;

//end:返回指向最后一个元素之后的位置的迭代器。
iterator end();
const_iterator end() const;

//rbegin 和 rend:反向迭代器,适用于反向遍历。
reverse_iterator rbegin();
const_reverse_iterator rbegin() const;

reverse_iterator rend();
const_reverse_iterator rend() const;
  1. 容量管理
//empty:检查 deque 是否为空。
bool empty() const;

//size:返回 deque 中元素的数量。
size_t size() const;

//max_size:返回 deque 可存储的最大元素数量。
size_t max_size() const;

//shrink_to_fit:请求减少内存使用,将多余的容量释放。
void shrink_to_fit();
  1. 修改操作
//clear:清空 deque 中的所有元素。
void clear();

//insert:在指定位置插入元素或多个元素。
iterator insert(const_iterator pos, const T& value);
iterator insert(const_iterator pos, T&& value);
iterator insert(const_iterator pos, size_t count, const T& value);
template <class InputIt>
iterator insert(const_iterator pos, InputIt first, InputIt last);
iterator insert(const_iterator pos, std::initializer_list<T> ilist);

//emplace:在指定位置直接构造元素,避免拷贝或移动。
iterator emplace(const_iterator pos, Args&&... args);

//push_back:在末尾添加一个元素。
void push_back(const T& value);
void push_back(T&& value);

//emplace_back:在末尾直接构造一个元素。
template <class... Args>
void emplace_back(Args&&... args);

//push_front:在头部插入一个元素。
void push_front(const T& value);
void push_front(T&& value);

//emplace_front:在头部直接构造一个元素。
template <class... Args>
void emplace_front(Args&&... args);

//pop_back:删除末尾的元素。
void pop_back();

//pop_front:删除头部的元素。
void pop_front();

//erase:删除指定位置或区间的元素。
iterator erase(const_iterator pos);
iterator erase(const_iterator first, const_iterator last);

//resize:调整 deque 的大小,如果新大小小于当前大小,则删除末尾元素;如果大于当前大小,则添加默认值或指定值的元素。
void resize(size_t count);
void resize(size_t count, const T& value);

//swap:交换两个 deque 的内容。
void swap(std::deque<T>& other);
  1. 赋值操作
//operator=:将 deque 赋值为另一个 deque 或初始化列表。
deque& operator=(const deque& other);
deque& operator=(deque&& other) noexcept;
deque& operator=(std::initializer_list<T> ilist);

//assign:将 deque 的内容替换为指定数量的元素、来自迭代器区间的元素,或来自初始化列表的元素。
void assign(size_t count, const T& value);
template <class InputIt>
void assign(InputIt first, InputIt last);
void assign(std::initializer_list<T> ilist);

list:双向链表

list 是一种双向链表,元素不连续存储,支持高效的插入和删除操作。

特点

  1. 双向链表std::list 是一个双向链表,每个节点包含指向前后节点的指针。
  2. 高效插入和删除:在任意位置进行插入或删除的时间复杂度为常数时间 O(1),适合需要频繁插入、删除的场景。
  3. 迭代器稳定性:由于不使用连续内存,list 中的插入或删除操作不会使其他迭代器失效,只有删除操作会使相关迭代器失效。
  4. 不支持随机访问list 不支持使用 [] 或 at 访问特定位置的元素,访问指定位置的元素需要顺序遍历,时间复杂度为 O(n)。

常用操作

push_front()push_back():在头部或尾部插入元素。
pop_front()pop_back():删除头部或尾部的元素。
insert():在指定位置插入元素。
erase():删除指定位置的元素。

适用场景

适合频繁在任意位置插入和删除元素,但不需要随机访问的场景。
适用于实现队列、栈、双向链表等数据结构。

成员函数详情

  1. 构造函数

//默认构造函数
//创建一个空的 list。
std::list<T> lst;

//指定大小的构造函数
//创建一个包含 count 个默认初始化元素的 list。
std::list<T> lst(size_t count);

//指定大小和初始值的构造函数
//创建一个包含 count 个 value 值的元素的 list。
std::list<T> lst(size_t count, const T& value);

//拷贝构造函数
//复制构造函数,用 other 中的元素创建一个新的 list。
std::list<T> lst(const std::list<T>& other);

//移动构造函数
//使用 other 的内容创建新 list,并避免拷贝,提高效率。
std::list<T> lst(std::list<T>&& other);

//初始化列表构造函数
//使用初始化列表创建 list,如 {1, 2, 3}。
std::list<T> lst(std::initializer_list<T> init);
  1. 元素访问
//front:返回 list 中第一个元素的引用。
T& front();
const T& front() const;

//back:返回 list 中最后一个元素的引用。
T& back();
const T& back() const;
  1. 迭代器
//begin:返回指向第一个元素的迭代器。
iterator begin();
const_iterator begin() const;

//end:返回指向最后一个元素之后的位置的迭代器。
iterator end();
const_iterator end() const;

//rbegin 和 rend:反向迭代器,适用于反向遍历。
reverse_iterator rbegin();
const_reverse_iterator rbegin() const;

reverse_iterator rend();
const_reverse_iterator rend() const;
  1. 容量管理
//empty:检查 list 是否为空。
bool empty() const;

//size:返回 list 中元素的数量。
size_t size() const;

//max_size:返回 list 可存储的最大元素数量。
size_t max_size() const;
  1. 修改操作
//clear:清空 list 中的所有元素。
void clear();

//insert:在指定位置插入元素或多个元素。
iterator insert(const_iterator pos, const T& value);
iterator insert(const_iterator pos, T&& value);
iterator insert(const_iterator pos, size_t count, const T& value);
template <class InputIt>
iterator insert(const_iterator pos, InputIt first, InputIt last);
iterator insert(const_iterator pos, std::initializer_list<T> ilist);

//emplace:在指定位置直接构造元素,避免拷贝或移动。
iterator emplace(const_iterator pos, Args&&... args);

//push_back:在末尾添加一个元素。
void push_back(const T& value);
void push_back(T&& value);

//emplace_back:在末尾直接构造一个元素。
template <class... Args>
void emplace_back(Args&&... args);

//push_front:在头部插入一个元素。
void push_front(const T& value);
void push_front(T&& value);

//emplace_front:在头部直接构造一个元素。
template <class... Args>
void emplace_front(Args&&... args);

//pop_back:删除末尾的元素。
void pop_back();

//pop_front:删除头部的元素。
void pop_front();

//erase:删除指定位置或区间的元素。
iterator erase(const_iterator pos);
iterator erase(const_iterator first, const_iterator last);

//resize:调整 list 的大小,如果新大小小于当前大小,则删除末尾元素;如果大于当前大小,则添加默认值或指定值的元素。
void resize(size_t count);
void resize(size_t count, const T& value);

//swap:交换两个 list 的内容。
void swap(std::list<T>& other);
  1. 赋值操作
//operator=:将 list 赋值为另一个 list 或初始化列表。
list& operator=(const list& other);
list& operator=(list&& other) noexcept;
list& operator=(std::initializer_list<T> ilist);

//assign:将 list 的内容替换为指定数量的元素、来自迭代器区间的元素,或来自初始化列表的元素。
void assign(size_t count, const T& value);
template <class InputIt>
void assign(InputIt first, InputIt last);
void assign(std::initializer_list<T> ilist);
  1. 专有操作

std::list 提供了一些特有的操作,主要用于链表的合并、拆分和排序:

//merge:将另一个已排序的 list 合并到当前 list,并保持顺序。
void merge(list& other);
template <class Compare>
void merge(list& other, Compare comp);

//splice:将一个 list 的元素插入到另一个 list 中的指定位置。
void splice(const_iterator pos, list& other);
void splice(const_iterator pos, list& other, const_iterator it);
void splice(const_iterator pos, list& other, const_iterator first, const_iterator last);

//remove:移除所有等于指定值的元素。
void remove(const T& value);

//remove_if:移除满足特定条件的所有元素。
template <class UnaryPredicate>
void remove_if(UnaryPredicate p);

//reverse:反转 list 中所有元素的顺序。
void reverse();

//unique:移除连续的重复元素,仅保留一个。
void unique();
template <class BinaryPredicate>
void unique(BinaryPredicate p);

//sort:对 list 中的元素进行排序。
void sort();
template <class Compare>
void sort(Compare comp);

forward_list:单向链表

forward_list 是一种单向链表,与 list 类似,但只支持单向遍历,只包含指向下一个节点的指针。其设计目标是提供比 std::list 更小的内存开销和更高的性能,适用于需要简单链表结构且只需从头到尾单向遍历的场景。

特点

  1. 单向链表:每个节点只包含一个指向下一个节点的指针,不包含指向前一个节点的指针。
  2. 轻量级:因为只有一个方向的指针,相比 std::list,内存开销更小。
  3. 高效的头部插入和删除:在链表头部插入或删除操作的时间复杂度为 O(1),适合实现简单的队列或栈。
  4. 不支持双向遍历和随机访问:只能从头到尾单向遍历链表,不支持 [] 或 at 进行随机访问。

常用操作

push_front():在头部插入元素。
pop_front():删除头部的元素。
insert_after():在指定位置后插入元素。
erase_after():删除指定位置后的元素。

适用场景

适合内存较为紧张、对链表大小没有严格需求的场景。
适用于实现单链表,或只需要单向遍历的数据结构,如简单的队列。

成员函数详情

  1. 构造函数
//默认构造函数
//创建一个空的 forward_list。
std::forward_list<T> flst;

//指定大小的构造函数
//创建一个包含 count 个默认初始化元素的 forward_list。
std::forward_list<T> flst(size_t count);

//指定大小和初始值的构造函数
//创建一个包含 count 个 value 值的元素的 forward_list。
std::forward_list<T> flst(size_t count, const T& value);

//拷贝构造函数
//用 other 中的元素创建一个新的 forward_list。
std::forward_list<T> flst(const std::forward_list<T>& other);

//移动构造函数
//使用 other 的内容创建新 forward_list,避免不必要的拷贝。
std::forward_list<T> flst(std::forward_list<T>&& other);

//初始化列表构造函数
//使用初始化列表创建 forward_list,如 {1, 2, 3}。
std::forward_list<T> flst(std::initializer_list<T> init);
  1. 元素访问

std::forward_list 不提供随机访问,因此只有一个头部访问函数。

//front:返回 forward_list 中第一个元素的引用。
T& front();
const T& front() const;
  1. 迭代器
//begin:返回指向第一个元素的迭代器。
iterator begin();
const_iterator begin() const;

//end:返回指向最后一个元素之后的位置的迭代器。
iterator end();
const_iterator end() const;
  1. 容量管理
//empty:检查 forward_list 是否为空。
bool empty() const;
  1. 修改操作

std::forward_list 的修改操作比 std::list 简单,因为它是单向链表,没有提供像 emplace_back 或 push_back 的操作。

//clear:清空 forward_list 中的所有元素。
void clear();

//insert_after:在指定位置后插入元素或多个元素。
iterator insert_after(const_iterator pos, const T& value);
iterator insert_after(const_iterator pos, T&& value);
iterator insert_after(const_iterator pos, size_t count, const T& value);
template <class InputIt>
iterator insert_after(const_iterator pos, InputIt first, InputIt last);
iterator insert_after(const_iterator pos, std::initializer_list<T> ilist);

//emplace_after:在指定位置后直接构造元素。
template <class... Args>
iterator emplace_after(const_iterator pos, Args&&... args);

//push_front:在头部插入一个元素。
void push_front(const T& value);
void push_front(T&& value);

//emplace_front:在头部直接构造一个元素。
template <class... Args>
void emplace_front(Args&&... args);

//pop_front:删除头部的元素
void pop_front();

//erase_after:删除指定位置后的元素或区间。
iterator erase_after(const_iterator pos);
iterator erase_after(const_iterator first, const_iterator last);

//resize:调整 forward_list 的大小,如果新大小小于当前大小,则删除多余的元素;如果大于当前大小,则添加默认值或指定值的元素。
void resize(size_t count);
void resize(size_t count, const T& value);

//swap:交换两个 forward_list 的内容。
void swap(forward_list<T>& other);
  1. 赋值操作
//operator=:将 forward_list 赋值为另一个 forward_list 或初始化列表。
forward_list& operator=(const forward_list& other);
forward_list& operator=(forward_list&& other) noexcept;
forward_list& operator=(std::initializer_list<T> ilist);

//assign:将 forward_list 的内容替换为指定数量的元素、来自迭代器区间的元素,或来自初始化列表的元素。
void assign(size_t count, const T& value);
template <class InputIt>
void assign(InputIt first, InputIt last);
void assign(std::initializer_list<T> ilist);
  1. 专有操作

由于 std::forward_list 的单向链表特性,它也支持一些常用的链表操作:

//merge:将另一个已排序的 forward_list 合并到当前 forward_list,并保持顺序。
void merge(forward_list& other);
template <class Compare>
void merge(forward_list& other, Compare comp);

//splice_after:将一个 forward_list 的元素插入到另一个 forward_list 中的指定位置之后。
void splice_after(const_iterator pos, forward_list& other);
void splice_after(const_iterator pos, forward_list& other, const_iterator it);
void splice_after(const_iterator pos, forward_list& other, const_iterator first, const_iterator last);

//remove:移除所有等于指定值的元素。
void remove(const T& value);

//remove_if:移除满足特定条件的所有元素。
template <class UnaryPredicate>
void remove_if(UnaryPredicate p);

//reverse:反转 forward_list 中所有元素的顺序。
void reverse();

//unique:移除连续的重复元素,仅保留一个。
void unique();
template <class BinaryPredicate>
void unique(BinaryPredicate p);

//sort:对 forward_list 中的元素进行排序。
void sort();
template <class Compare>
void sort(Compare comp);

专有函数补充说明

看到这边可能有些朋友会有疑惑,怎么list和forward_list有专有操作,vector和deque没有呢?

std::vectorstd::deque 的设计目标是提供快速的随机访问和高效的序列操作,因此它们的接口更关注基础的顺序操作(如插入、删除、访问等),而没有添加复杂的专有操作。相比之下,std::list 和 std::forward_list 基于链表结构,这使得它们天然支持一些高级操作,如合并、排序、去重等。这些操作在链表结构上可以在不移动大量数据的情况下高效实现,因此它们被设计为专有操作。

以下是 std::list 和 std::forward_list 具有这些专有操作的原因,以及 std::vector 和 std::deque 不需要这些操作的原因:

  1. std::list 和 std::forward_list 的专有操作

merge:将两个已排序的链表合并成一个,且链表的合并操作只需调整指针,而无需移动大量数据,因此链表合并非常高效。这在链表结构上可以实现 O(1) 的操作复杂度。

splice:将一个链表中的元素移动到另一个链表中,只需改变指针指向,而不必复制或移动数据,这对于链表来说是一项很自然的操作,能以 O(1) 的复杂度完成。

remove 和 remove_if:删除符合条件的节点只需调整链表指针,因此链表结构的删除操作可以高效完成,不会涉及到大量元素的移动。

unique:去除连续重复的元素,在链表结构中通过遍历实现,不需要进行大量的元素重排。

sort:链表可以通过交换指针高效排序,而无需像数组那样移动大量数据。

这些操作利用了链表节点的指针特性,使得复杂操作可以高效地实现。

  1. std::vector 和 std::deque 的设计侧重点

快速随机访问:std::vector 和 std::deque 设计上重视连续内存的快速访问特性。由于其内存是连续的,直接支持 O(1) 的随机访问,这是链表无法做到的。

简单顺序操作:std::vector 和 std::deque 的主要操作集中在顺序插入和删除,特别是 std::vector 优化了尾部操作,而 std::deque 额外支持高效的头尾操作。

高级操作不适用:由于内存是连续存储的,执行类似 merge、splice 的操作需要移动大量数据,这样的操作会非常低效;而 sort、remove 等操作,std::vector 和 std::deque 可以通过算法库中的通用函数(如 std::sort、std::remove)来完成。这样的算法函数在这些连续容器上效率很高,因为它们能利用直接访问的优势。

总结

链表容器(list、forward_list):使用指针操作节点,高效支持高级操作,因此提供了专有的成员函数。

连续内存容器(vector、deque):基于连续内存,更适合直接访问和基础顺序操作,专有操作反而会影响效率。因此这些容器专注于基础的增删查操作,不提供链表专有的高级操作。

可以通过标准算法来对 vector 和 deque 执行类似的操作。例如:

排序:

std::vector<int> vec = {4, 2, 3, 1};
std::sort(vec.begin(), vec.end());

去重:

std::vector<int> vec = {1, 2, 2, 3, 4, 4};
std::sort(vec.begin(), vec.end());           // 先排序
auto last = std::unique(vec.begin(), vec.end());
vec.erase(last, vec.end());                  // 删除重复元素

合并:

std::vector<int> vec1 = {1, 3, 5};
std::vector<int> vec2 = {2, 4, 6};
std::vector<int> result;
std::merge(vec1.begin(), vec1.end(), vec2.begin(), vec2.end(), std::back_inserter(result));

std::vectorstd::deque 的功能更偏向于高效的内存管理和随机访问,使用标准算法库可以很好地完成类似 list 的操作,但不需要专门的成员函数来实现。

list和forward_list为什么不推荐使用标准算法?

标准算法库中的大部分算法(如 std::sort、std::merge 等)假设数据结构支持 随机访问迭代器。这在连续存储的容器(如 std::vector 和 std::deque)上可以实现高效的操作,但 std::list 和 std::forward_list 只提供双向迭代器或单向迭代器,无法满足这些算法的随机访问要求。因此,尝试在链表上使用标准算法可能会导致编译错误,或效率极低。

顺序容器的选择和比较

选择顺序容器时,可以根据需求来选择:

std::vector:适合需要随机访问和尾部操作较多的场景,如动态数组。

std::deque:适合双端操作和适度随机访问的场景,如双端队列。

std::list:适合在任意位置频繁插入、删除的场景,典型的双向链表。

std::forward_list:适合单向遍历、头部插入删除频繁、资源受限的场景。

容器类型底层结构内存分配随机访问插入/删除效率适用场景
std::vector动态数组连续内存快速 O(1)插尾部 O(1),头/中部 O(n)随机访问频繁、尾部插入删除
std::deque分段连续的双端队列分块内存较快 O(1)头尾 O(1)双端插入删除,双端队列
std::list双向链表非连续分散存储慢 O(n)任意位置 O(1)插入删除频繁,无需随机访问
std::forward_list单向链表非连续分散存储慢 O(n)头部 O(1),尾部 O(n)头部操作频繁,单向遍历
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值