容器

顺序容器

数据结构

vector<T>

可变大小向量

list<T>

双向链表

forward_list<T>

单向链表

deque<T>

双端队列

forward_list 是一种专为空链表和极短链表优化过的数据结构,一个空forward_list只占用一个内存字。不提供insert()、erase()、emplace(),而提供 *_after 系列操作;不提供back()、push_back()、pop_back()、emplace_back();不提供reverse_iterator、const_reverse_iterator、rbegin()、crbegin()、crend()、size()

有序关联容器

数据结构

map<K,V>

关联数组

multimap<K,V>

允许重复关键字的map

set<T>

集合

multiset<T>

允许重复值的集合

multi*系列关联容器或集合不提供 [] 和 at()

无序关联容器

数据结构

unordered_map<K,V>

采用哈希搜索的map

unordered_multimap<K,V>

采用哈希搜索的multimap

unordered_set<T>

采用哈希搜索的set

unordered_multiset<T>

采用哈希搜搜的multiset

unordered_* 系列关联容器不提供 <、<=、>、>=

容器适配器

数据结构

priority_queue<T,C,Cmp>

T 的优先队列;Cmp是优先级函数类型,默认 std::less<T>

queue<T,C>

T 的队列;支持 push() 和 pop() 操作;容器类型C默认std::deque<T>

stack<T,C>

T的栈;支持 push() 和 pop() 操作;容器类型C默认std::deque<T>

T:value_type

一、vector

1.一个vector就是一个给定类型元素的序列,元素在内存中是连续存储的,进行元素的删除插入操作时其他元素可能会移动

基础容器 Alpine_基础容器 Alpine


2.用一组值来初始化vector(值的类型必须与vector元素类型符合)

//Entry代表“电话簿”结构体,包含string型名字,int型号码
vector<Entry> phone_book = {
    {"David Hume",123456},
    {"Karl Poper",234567},
    {"Bertrand Arthur William Russell",345678}
};

可以通过下标运算符访问元素,如phone_book[0]
可以返回元素的数目,如phone_book.size()
遍历vector元素,for(const auto& x : phone_book)
定义vector时可设置初始大小:

vector<int> v1 = {1, 2, 3,4};   //size为4
vector<string> v2;              //size为0
vector<Shape> v3(23);           //显示给出size为23;元素初值是nulptr
vector<double> v4(32, 9.9);     //显示size为32,元素初值是9.9(32个元素全部初始为9.9)

vector的初始大小随着程序的执行可以被改变
在赋值和初始化时,vector可以被拷贝,如vector<Entry> book2 = phone_book;
拷贝和移动vector是通过构造函数和赋值运算符实现的,vector的赋值过程包括拷贝其中的元素
4.方法1:vector.push_back(),它向vector末尾追加一个新元素
5.元素
vector<T>中,元素T可为:内置数据类型(char、int、double)、用户自定义类型(string、Entry、list<int>、Matrix<double,2>)、指针类型
6.范围检查
标准库vector不进行范围检查(可能越界),可以自定义范围检查

二、list

1.list是一个双向链表

基础容器 Alpine_搜索_02


如果希望在一个序列中添加和删除元素的同时无须移动其他元素,则应使用list,电话簿插入删除频繁可使用list

//Entry代表“电话簿”结构体,包含string型名字name,int型号码number
list<Entry> phone_book = {
    {"David Hume",123456},
    {"Karl Poper",234567},
    {"Bertrand Arthur William Russell",345678}
};

2.一般不用下标操作来访问链表元素
3.遍历链表list,for(const auto& x : phone_book):

int get_number(const string& s){
    for(const auto& x : phone_book)
        if(x.name == s)
            return x.number;
    return 0;
}

每个标准库容器都提供begin()和end()函数,显示地使用迭代器遍历list(p为指针)

int get_number(const string& s){
    for(auto p=phone_book.begin();p!=phone_book.end();++p)
        if(p->name == s)
            return p->number;
    return 0;
}

4.方法1,添加元素:

phone_book.insert(p,ee);    //将ee添加到p指向的元素之前

5.方法2,删除元素:

phone_book.erase(q);    //删除q指向的元素

6.当只需要一个元素序列,数据量较小时,应该使用vector(vector无论遍历如find()和count()、排序sort()、搜索binary_search()都优于list)

三、map

1.map是一个搜索树(红黑树),也称为关联数组或字典,通常用平衡二叉树实现

//map是值对的容器,(key,value)
map<string,int> phone_book {
    {"David Hume",123456},
    {"Karl Poper",234567},
    {"Bertrand Arthur William Russell",345678}
};

2.map支持下标操作(本质上是一次搜索),下标值应为map的第一个类型key,得到与关键字关联的值value,若key值不存在则向map插入一个新元素,复杂度O(log(n))

int get_number(const string& s){
    return phone_book[s];
}

四、unordered_map 无序容器

1.初始化

unordered_map<string,int> phone_book {
    {"David Hume",123456},
    {"Karl Poper",234567},
    {"Bertrand Arthur William Russell",345678}
};

2.下标操作

int get_number(const string& s){
    return phone_book[s];
}

五、set 集合:每个元素只出现一次,且自动由小到大排列

set<string> dict;

五、容器的大小和容量

大小是指容器中的元素数目;容器是指在重新分配更多内存之前容器能够保存的元素数目

方法

含义

x = c.size()

x 是 c 的元素数目

c.empty()

c为空吗

x = c.max_size()

x 是 c 的最大可能元素数目

x = c.capacity()

x 是为 c 分配的空间大小;只适用于 vector 和 string

c.reserve(n)

为 c 预留 n 个元素的空间;只适用于 vector 和 string

c.resize(n)

将 c 的大小改变为 n;将增加的元素初始化为默认元素值;只适用于顺序容器和string

c.resize(n,v)

将 c 的大小改变为 n;将增加的元素初始化为 v;只适用于顺序容器和string

c.shrink_to_fit()

令 c.capacity() 等于 c.size();只适用于 vector、deque、string

c.clear()

删除 c 的所有元素

在改变大小或容量时,元素可能会被移动到新的存储位置。这意味着指向元素的迭代器、指针、引用,可能会失效(即,指向旧元素的位置)

六、栈操作

标准 vector、deque、list(不包括 forward_list 和关联容器)提供了高效的元素序列尾部操作:

栈操作

含义

c.push_back(x)

将 x 添加到 c 的尾元素之后(使用拷贝或移动)

c.pop_back()

删除 c 的尾元素

c.emplace_back(args)

用 args 构造一个对象,将它添加到 c 的尾元素之后