C++之顺序容器

-
-
2026-05-18 17:46

本文内容为《C++ Primer(第五版)》相关章节整理而得。

一、顺序容器类型

vector可变大小数组
deque双端队列
list双向链表
forward_list单向链表(C语言中最传统的那种链表封装过来的)
array固定大小数组,不能添加或删除元素。
string与vector相似,专门用于保存字符。(就是常用的字符串类。)
  • array

    #include <iostream>
    #include <array>
    
    int main()
    {
    	std::array<int, 3> arr = { 1, 2, 3 };
    	std::cout << arr[0] << std::endl;
    	return 0;
    }
  • 容器可以套容器,例如:std::vector<std::vector<int>> v;,但是在较旧的编译器中,可能需要在两个>之间输入空格。
  • 当容器套一个没有默认构造函数的类型时,需要传初始值,格式如下:

     std::vector<noDefault> v(10, init); // 正确
     std::vector<noDefault> v1(10); // 错误,缺少初始值
    • eg

      #include <iostream>
      #include <vector>
      
      class A
      {
      public:
      	A(int x, int y) {};
      	~A() {};
      
      private:
      
      };
      
      int main()
      {
      	std::vector<A> v(10, A(1, 2)); // 这是正确的
      	return 0;
      }

二、关系运算符

  • 每个容器类型都支持相等运算符(==和!=)。
  • 除了无序关联容器外所有容器都支持关系运算符(>、>=、<、<=)。
  • 比较两个容器实际上是逐个元素比较的(注意,顺序会影响比较结果),例如:

    std::vector<int> v = { 1, 2, 3 };
    std::vector<int> v1 = { 1, 3, 2 };
    bool b = v == v1; /// 结果为false,因为v[1] != v1[1],虽然所有元素都相同,但是顺序不同。大小比较也是如此。

三、顺序容器的操作

操作

作用

用法示例

适用范围

备注

swap交换两个同类型容器的元素swap(c1,  c2)或者c1.swap(c2)  
assign从不同但相容的类型赋值或者从容器的子序列赋值
std::vector<int> v = { 1, 2, 3 };
std::list<int> l;
l.assign(v.begin(), v.end()); /// l的值也是{1, 2, 3}

///或者 
std::list<std::string> l(1);
l.assign(10, "qy"); /// l将被填充10个“qy”
除array外 
push_back向容器末尾追加元素 除array和forward_list之外放入容器的对象是原对象的拷贝,有额外开销
push_from向容器头部追加元素 list、forward_list、deque同push_back
insert在容器任意位置插入新元素
std::vector<int> v = { 0, 1, 2 };
v.insert(v.begin(), 3); /// 在v的开头插入一个3,最终v为:{3, 0, 1, 2}

/// 也可以插入范围内的元素,例如:
v.insert(v.end(), {3, 4, 5});
v.insert(v.end(), 10, 6); /// 在末尾插入10个6
 

1、放入的元素在迭代器所指定位置之前。

2、将元素插入到vector、string、deque的任意位置也是合法的,但是这个操作可能会很耗时。

3、该操作会返回指向第一个新插入元素的迭代器。如果未加入任何元素,则返回第一个参数对应的迭代器。

emplace/emplace_from/emplace_back在任意位置/头部/末尾插入新元素
std::vector<int> v = { 0, 1, 2 };
v.emplace(v.begin(), 3);
 

1、与insert/push_front/push_back用法类似,但是它是 构造 元素,而不是拷贝元素,因此性能更好。

2、传给emplace的参数必须与元素类型的构造函数相匹配。

front/back返回首元素/尾元素的引用。
 std::vector<int> v = { 0, 1, 2 };
 int nFirst = v.front();
 作用与调用begin/end并解引用相同。
at访问指定下标的元素  会增加对边界溢出的检查,代价是会额外消耗性能。
erase删除元素  forward_list比较特殊,叫erase_after,不叫erase
pop_back 不支持forward_list 
pop_front 不支持vector和string 

容器操作使用示例

使用下面代码定义的ia,将ia拷贝到一个vector和一个1ist中。使用单迭代器版本的erase从list中删除奇数元素,从vector中删除偶数元素。
int ia[]={ 0,1,1,2,3,5,8,13,21,55,89 };

(1)拷贝元素

  • 方法一

    std::vector<int> v(ia, ia + sizeof(ia) / sizeof(ia[0]));
  • 方法二

    v.assign(ia, ia + sizeof(ia) / sizeof(ia[0]));
  • 方法三

    #include <iterator>
    
    std::vector<int> v(std::begin(ia), std::end(ia));

(2)删除元素

  • 方法一:根据题目要求的做法

    for (std::vector<int>::iterator it = v.begin(); it != v.end();)
    {
    	if (*it % 2 == 0)
    	{
    		it = v.erase(it);
    	}
    	else
    	{
    		++it;
    	}
    }
  • 方法二:比方法一效率更高,实际项目中更推荐使用这种方法

    #include <algorithm>
    
    
    // C++11之前
    bool isEven(int n) {
        return n % 2 == 0;
    }
    
    v.erase(std::remove_if(v.begin(), v.end(), isEven), v.end());
    
    // C++11之后(Lambda表达式)
    v.erase(std::remove_if(v.begin(), v.end(), [](int n) {return n % 2 == 0; }), v.end());

     


目录