文章目录
- 一、string容器
- 二、vector容器
- 三、list容器
- 1.构造函数
- 2.特性操作
- 3.元素操作
- 4.赋值操作
- 5.交换、反转、排序、归并
- 6.比较操作
- 7.插入和删除
- 五、pair键值对
- 四、map容器
- 1.红黑树(平衡二叉排序树)
- 2.构造函数
- 3.特性操作
- 4.元素操作
- 5.赋值操作
- 6.交换操作
- 7.比较操作
- 8.查找操作
- 9.插入和删除
- 五、unordered_map容器
- 六、queue容器
- 七、
一、string容器
二、vector容器
三、list容器
1.构造函数
- 本质是双向链表
1)list(); // 创建一个空的list容器。
2)list(initializer_list<T> il); // 使用统一初始化列表。
3)list(const list<T>& l); // 拷贝构造函数。
4)list(Iterator first, Iterator last); // 用迭代器创建list容器。
5)list(list<T>&& l); // 移动构造函数(C++11标准)。
不常用:
6)explicit list(const size_t n); // 创建list容器,元素个数为n。
7)list(const size_t n, const T& value); // 创建list容器,元素个数为n,值均为value。
- eg:
#include <iostream>
#include <vector>
#include <list>
using namespace std;
int main()
{
// 1)list(); // 创建一个空的list容器。
list<int> l1;
// cout << "li.capacity()=" << l1.capacity() << endl; // 链表没有容量说法。不需要提前分配内存
cout << "li.size()=" << l1.size() << endl;
// 2)list(initializer_list<T> il); // 使用统一初始化列表。
list<int> l2({ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });
// list<int> l2={ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
// list<int> l2 { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
for (int value : l2) // 用基于范围的for循环遍历容器。
cout << value << " ";
cout << endl;
// 3)list(const list<T>& l); // 拷贝构造函数。
list<int> l3(l2);
// list<int> l3=l2;
for (int value : l3)
cout << value << " ";
cout << endl;
// 4)list(Iterator first, Iterator last); // 用迭代器创建list容器。
//list<int> l4(l3.begin(), l3.end()-3); error,不支持随机访问:
list<int> l4(l3.begin(), l3.end()); // 用list容器的迭代器。
for (int value : l4)
cout << value << " ";
cout << endl;
vector<int> v1 = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; // 创建vector容器。
list<int> l5(v1.begin() + 2, v1.end() - 3); // 用vector容器的迭代器创建list容器。
for (int value : l5)
cout << value << " ";
cout << endl;
int a1[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; // 创建数组。数组的指针是天然的随机访问迭代器
// list<int> l6(std::begin(a1) + 2, std::end(a1) + 10 - 3);
list<int> l6(a1 + 2, a1 + 10 - 3); // 用数组的指针作为迭代器创建list容器。
for (int value : l6)
cout << value << " ";
cout << endl;
char str[] = "hello world"; // 定义C风格字符串。
string s1(str + 1, str + 7); // 用C风格字符串创建string容器。
for (auto value : s1) // 遍历string容器。
cout << value << " ";
cout << endl;
cout << s1 << endl; // 以字符串的方式显示string容器。
vector<int> v2(l3.begin(), l3.end()); // 用list迭代器创建vector容器。
for (auto value : v2) // 遍历vector容器。
cout << value << " ";
cout << endl;
}
2.特性操作
size_t size() const; // 返回容器的实际大小(已使用的空间)。
bool empty() const; // 判断容器是否为空。
void clear(); // 清空容器。
void resize(size_t size); // 把容器的实际大小置为size。
不常用:
size_t max_size() const; // 返回容器的最大长度,此函数意义不大。
void resize(size_t size,const T &value); // 把容器的实际大小置为size,如果size<实际大小,会截断多出的部分;如果size>实际大小,就用value填充。
3.元素操作
T &front(); // 第一个元素。
const T &front(); // 第一个元素,只读。
const T &back(); // 最后一个元素,只读。
T &back(); // 最后一个元素。
4.赋值操作
给已存在的容器赋值,将覆盖容器中原有的内容。
1)list &operator=(const list<T> &l); // 把容器l赋值给当前容器。
2)list &operator=(initializer_list<T> il); // 用统一初始化列表给当前容器赋值。
3)list assign(initializer_list<T> il); // 使用统一初始化列表赋值。
4)list assign(Iterator first, Iterator last); // 用迭代器赋值。
不常用:
5)void assign(const size_t n, const T& value); // 把n个value给容器赋值。
5.交换、反转、排序、归并
void swap(list<T> &l); // 把当前容器与l交换,交换的是链表结点的地址。
void reverse(); // 反转链表。
void sort(); // 对容器中的元素进行升序排序。
void sort(_Pr2 _Pred); // 对容器中的元素进行排序,排序的方法由_Pred决定(二元函数)。
void merge(list<T> &l); // 采用归并法合并两个已排序的list容器,合并后的list容器仍是有序的。
- eg:
#include <iostream>
#include <vector>
#include <list>
using namespace std;
int main()
{
list<int> la = { 8,2,6,4,5 };
for (auto &val : la)
cout << val << " ";
cout << endl;
la.reverse(); // 反转链表。
for (auto& val : la)
cout << val << " ";
cout << endl;
la.sort(); // 链表排序。
for (auto& val : la)
cout << val << " ";
cout << endl;
list<int> lb = { 3,7,9,10,1 };
lb.sort(); // 链表排序。
la.merge(lb); // 归并链表。
for (auto& val : la)
cout << val << " ";
cout << endl;
}
6.比较操作
bool operator == (const vector<T> & l) const;
bool operator != (const vector<T> & l) const;
7.插入和删除
1)void push_back(const T& value); // 在链表的尾部追加一个元素。
2)void emplace_back(…); // 在链表的尾部追加一个元素,…用于构造元素。C++11
3)iterator insert(iterator pos, const T& value); // 在指定位置插入一个元素,返回指向插入元素的迭代器。
4)iterator emplace (iterator pos, …); // 在指定位置插入一个元素,…用于构造元素,返回指向插入元素的迭代器。C++11
5)iterator insert(iterator pos, iterator first, iterator last); // 在指定位置插入一个区间的元素,返回指向第一个插入元素的迭代器。
6)void pop_back(); // 从链表尾部删除一个元素。
7)iterator erase(iterator pos); // 删除指定位置的元素,返回下一个有效的迭代器。
8)iterator erase(iterator first, iterator last); // 删除指定区间的元素,返回下一个有效的迭代器。
9)push_front(const T& value); // 在链表的头部插入一个元素。
10)emplace_front(…); // 在链表的头部插入一个元素,…用于构造元素。C++11
11)splice(iterator pos, const list<T> & l); // 把另一个链表连接到当前链表。
12)splice(iterator pos, const list<T> & l, iterator first, iterator last); // 把另一个链表指定的区间连接到当前链表。
13)splice(iterator pos, const list<T> & l, iterator first); // 把另一个链表从first开始的结点连接到当前链表。
14)void remove(const T& value); // 删除链表中所有值等于value的元素。
15)void remove_if(_Pr1 _Pred); // 删除链表中满足条件的元素,参数_Pred是一元函数。
16)void unique(); // 删除链表中相邻的重复元素,只保留一个。
17)void pop_front(); // 从链表头部删除一个元素。
- eg:
#include <iostream>
#include <vector>
#include <list>
using namespace std;
int main()
{
list<int> la = { 8,2,6,4,5 };
for (auto& val : la) cout << val << " ";
cout << endl;
list<int> lb = { 3,7,9,10,1 };
for (auto& val : lb) cout << val << " ";
cout << endl;
auto first = lb.begin();
first++;
auto last = lb.end();
last--;
la.splice(la.begin(), lb, first, last);
for (auto& val : la) cout << val << " ";
cout << endl;
cout << "lb.size()=" << lb.size() << endl;
for (auto& val : lb) cout << val << " ";
cout << endl;
}
五、pair键值对
pair是类模板,一般用于表示key/value数据,其实现是结构体。
- pair结构模板的定义如下:
template <class T1, class T2>
struct pair
{
T1 first; // 第一个成员,一般表示key。
T2 second; // 第二个成员,一般表示value。
pair(); // 默认构造函数。
pair(const T1 &val1,const T2 &val2); // 有两个参数的构造函数。
pair(const pair<T1,T2> &p); // 拷贝构造函数。
void swap(pair<T1,T2> &p); // 交换两个pair。
};
make_pair函数模板的定义如下:
template <class T1, class T2>
make_pair(const T1 &first,const T2 &second)
{
return pair<T1,T2>(first, second);
}
- eg:
#include <iostream>
using namespace std;
template <class T1, class T2>
struct Pair
{
T1 first; // 第一个成员,一般表示key。
T2 second; // 第二个成员,一般表示value。
Pair() {
cout << "调用了有默认的构造函数。\n";
}
Pair(const T1& val1, const T2& val2) :first(val1), second(val2) {
cout << "调用了有两个参数的构造函数。\n";
}
Pair(const Pair<T1, T2>& p) : first(p.first),second(p.second) {
cout << "调用了拷贝构造函数。\n";
}
};
template <class T1, class T2>
Pair<T1, T2> make_Pair(const T1& first, const T2& second)
{
//下面两种写法,Linux平台都不会多调用一次拷贝,都是RVO优化,直接移动
// Pair<T1, T2> p(first, second);
// return p; // 返回局部对象。
return Pair<T1, T2>(first, second); // 返回临时对象。
}
int main()
{
//pair<int, string> p0;
//cout << "p0 first=" << p0.first << ",second=" << p0.second << endl;
//pair<int, string> p1(1, "西施1"); // 两个参数的构造函数。
//cout << "p1 first=" << p1.first << ",second=" << p1.second << endl;
//pair<int, string> p2 = p1; // 隐式构造。
//cout << "p2 first=" << p2.first << ",second=" << p2.second << endl;
//pair<int, string> p3 = { 3, "西施3" }; //隐式构造。
pair<int, string> p3 { 3, "西施3" }; // 两个参数的构造函数,省略了等于号。
//cout << "p3 first=" << p3.first << ",second=" << p3.second << endl;
auto p4 = Pair<int, string>(4, "西施4"); // 匿名对象(隐式构造)。
cout << "p4 first=" << p4.first << ",second=" << p4.second << endl;
auto p5 = make_Pair<int, string>(5, "西施5"); // make_pair()返回的临时对象。(隐式构造)
cout << "p5 first=" << p5.first << ",second=" << p5.second << endl;
//pair<int, string> p6 = make_pair(6, "西施6"); //隐式构造, 让make_pair()函数自动推导,再调用拷贝构造,再隐式转换。
//cout << "p6 first=" << p6.first << ",second=" << p6.second << endl;
//auto p7 = make_pair(7, "西施7"); // 隐式构造,让make_pair()函数自动推导。
//cout << "p7 first=" << p7.first << ",second=" << p7.second << endl;
//p5.swap(p4); // 交换两个pair。
//cout << "p4 first=" << p4.first << ",second=" << p4.second << endl;
//cout << "p5 first=" << p5.first << ",second=" << p5.second << endl;
//struct st_girl
//{
// string name;
// int age;
// double height;
//};
用pair存放结构体数据。
//pair<int, st_girl> p = { 3,{"西施",23,48.6} };
//cout << "p first=" << p.first << endl;
//cout << "p second.name=" << p.second.name << endl;
//cout << "p second.age=" << p.second.age << endl;
//cout << "p second.height=" << p.second.height << endl;
}
四、map容器
1.红黑树(平衡二叉排序树)
红黑树:左边节点比自己小,右边的节点比自己大
-
红黑树查找元素的方法,又称之为二分查找
-
eg:跟节点比左子树的任意一个节点都大,比右子树的任意一个节点都小
-
h:高度
-
物理结构:二叉链表
struct BTNode{
pair<K,V> p;//键值对
BTNode* parent;//父节点
BTNOde* lchirld;//左子树
BTNode* * rchild;//右子树
};
2.构造函数
1)map(); // 创建一个空的map容器。
2)map(initializer_list<pair<K,V>> il); // 使用统一初始化列表。
3)map(const map<K,V>& m); // 拷贝构造函数。
4)map(Iterator first, Iterator last); // 用迭代器创建map容器。
5)map(map<K,V>&& m); // 移动构造函数(C++11标准)。
- eg:
#include <iostream>
#include <map>
using namespace std;
int main()
{
// 1)map(); // 创建一个空的map容器。
map<int, string> m1;
// 2)map(initializer_list<pair<K, V>> il); // 使用统一初始化列表。
map<int, string> m2( { { 8,"冰冰" }, { 3,"西施" }, { 1,"幂幂" }, { 7,"金莲" }, { 5,"西瓜" } } );
// map<int, string> m2={ { 8,"冰冰" }, { 3,"西施" }, { 1,"幂幂" }, { 7,"金莲" }, { 5,"西瓜" } };
// map<int, string> m2 { { 8,"冰冰" }, { 3,"西施" }, { 1,"幂幂" }, { 7,"金莲" }, { 5,"西瓜" } };
for (auto& val : m2)
cout << val.first << "," << val.second << " ";
cout << endl;
// 3)map(const map<K, V>&m); // 拷贝构造函数。
map<int, string> m3 = m2;
for (auto& val : m3)
cout << val.first << "," << val.second << " ";
cout << endl;
// 4)map(Iterator first, Iterator last); // 用迭代器创建map容器。
auto first = m3.begin(); first++;
auto last = m3.end(); last--;
map<int, string> m4(first,last);
for (auto& val : m4)
cout << val.first << "," << val.second << " ";
cout << endl;
// 5)map(map<K, V> && m); // 移动构造函数(C++11标准)。
}
3.特性操作
size_t size() const; // 返回容器的实际大小(已使用的空间)。
bool empty() const; // 判断容器是否为空。
void clear(); // 清空容器。
4.元素操作
V &operator[](K key); // 用给定的key访问元素。
const V &operator[](K key) const; // 用给定的key访问元素,只读。
V &at(K key); // 用给定的key访问元素。
const V &at(K key) const; // 用给定的key访问元素,只读。
注意:
1)[ ]运算符:如果指定键不存在,会向容器中添加新的键值对;如果指定键存在,则读取或修改容器中指定键的值。
2)at()成员函数:如果指定键不存在,不会向容器中添加新的键值对,而是直接抛出out_of_range 异常。
- eg:
#include <iostream>
#include <map>
using namespace std;
int main()
{
map<string, string> m( { { "08","冰冰" }, { "03","西施" }, { "01","幂幂" }, { "07","金莲" }, { "05","西瓜" } } );
cout << "m[08]=" << m["08"] << endl; // 显示key为08的元素的value。
cout << "m[09]=" << m["09"] << endl; // 显示key为09的元素的value。key为09的元素不存在,将添加新的键值对。
m["07"] = "花花"; // 把key为07的元素的value修改为花花。
m["12"] = "小乔"; // 将添加新的键值对。
for (auto& val : m)
cout << val.first << "," << val.second << " ";
cout << endl;
}
5.赋值操作
给已存在的容器赋值,将覆盖容器中原有的内容。
1)map<K,V> &operator=(const map<K,V>& m); // 把容器m赋值给当前容器。
2)map<K,V> &operator=(initializer_list<pair<K,V>> il); // 用统一初始化列表给当前容器赋值。
6.交换操作
交换的是树的根结点。
void swap(map<K,V>& m); // 把当前容器与m交换。
7.比较操作
bool operator == (const map<K,V>& m) const;
bool operator != (const map<K,V>& m) const;
8.查找操作
1)查找键值为key的键值对
在map容器中查找键值为key的键值对,如果成功找到,则返回指向该键值对的迭代器;失败返回end()。
iterator find(const K &key);
const_iterator find(const K &key) const; // 只读。
2)查找键值>=key的键值对
在map容器中查找第一个键值>=key的键值对,成功返回迭代器;失败返回end()。
iterator lower_bound(const K &key);
const_iterator lower_bound(const K &key) const; // 只读。
3)查找键>key的键值对
在map容器中查找第一个键值>key的键值对,成功返回迭代器;失败返回end()。
iterator upper_bound(const K &key);
const_iterator upper_bound(const K &key) const; // 只读。
4)统计键值对的个数
统计map容器中键值为key的键值对的个数。
size_t count(const K &key) const;
- eg:
#include <iostream>
#include <map>
using namespace std;
int main()
{
map<string, string> m( { { "08","冰冰" }, { "03","西施" }, { "01","幂幂" }, { "07","金莲" }, { "05","西瓜" } } );
for (auto& val : m)
cout << val.first << "," << val.second << " ";
cout << endl;
// 在map容器中查找键值为key的键值对,如果成功找到,则返回指向该键值对的迭代器;失败返回end()。
auto it1 = m.find("05");
if (it1 != m.end())
cout << "查找成功:" << it1->first << "," << it1->second << endl;
else
cout << "查找失败。\n";
// 在map容器中查找第一个键值 >= key的键值对,成功返回迭代器;失败返回end()。
auto it2 = m.lower_bound("05");
if (it2 != m.end())
cout << "查找成功:" << it2->first << "," << it2->second << endl;
else
cout << "查找失败。\n";
// 在map容器中查找第一个键值 > key的键值对,成功返回迭代器;失败返回end()。
auto it3 = m.upper_bound("05");
if (it3 != m.end())
cout << "查找成功:" << it3->first << "," << it3->second << endl;
else
cout << "查找失败。\n";
// 统计map容器中键值为key的键值对的个数。
cout << "count(05)=" << m.count("05") << endl; // 返回1。
cout << "count(06)=" << m.count("06") << endl; // 返回0。
}
9.插入和删除
1)void insert(initializer_list<pair<K,V>> il); // 用统一初始化列表在容器中插入多个元素。
2)pair<iterator,bool> insert(const pair<K,V> &value); // 在容器中插入一个元素,返回值pair:first是已插入元素的迭代器,second是插入结果。
3)void insert(iterator first,iterator last); // 用迭代器插入一个区间的元素。
4)pair<iterator,bool> emplace (...); // 将创建新键值对所需的数据作为参数直接传入,map容器将直接构造元素。返回值pair:first是已插入元素的迭代器,second是插入结果。
例:mm.emplace(piecewise_construct, forward_as_tuple(8), forward_as_tuple("冰冰", 18));
5)iterator emplace_hint (const_iterator pos,...); // 功能与第4)个函数相同,第一个参数提示插入位置,该参数只有参考意义,如果提示的位置是正确的,对性能有提升,如果提示的位置不正确,性能反而略有下降,但是,插入是否成功与该参数元关。该参数常用end()和begin()。成功返回新插入元素的迭代器;如果元素已经存在,则插入失败,返回现有元素的迭代器。
6)size_t erase(const K & key); // 从容器中删除指定key的元素,返回已删除元素的个数。
7)iterator erase(iterator pos); // 用迭代器删除元素,返回下一个有效的迭代器。
8)iterator erase(iterator first,iterator last); // 用迭代器删除一个区间的元素,返回下一个有效的迭代器。
- eg:
#include <iostream>
#include <map>
using namespace std;
class CGirl // 超女类。
{
public:
string m_name; // 超女姓名。
int m_age; // 超女年龄。
/*CGirl() : m_age(0) {
cout << "默认构造函数。\n";
}*/
CGirl(const string name, const int age) : m_name(name), m_age(age) {
cout << "两个参数的构造函数。\n";
}
CGirl(const CGirl & g) : m_name(g.m_name), m_age(g.m_age) {
cout << "拷贝构造函数。\n";
}
};
int main()
{
//map<int, CGirl> mm;
//mm.insert (pair<int, CGirl>(8, CGirl("冰冰", 18))); // 一次构造函数,两次拷贝构造函数。
//mm.insert (make_pair<int, CGirl>(8, CGirl("冰冰", 18))); // 一次构造函数,两次拷贝构造函数。
//mm.emplace(pair<int, CGirl>(8, CGirl("冰冰", 18))); // 一次构造函数,两次拷贝构造函数。
//mm.emplace(make_pair<int, CGirl>(8, CGirl("冰冰", 18))); // 一次构造函数,两次拷贝构造函数。
//mm.emplace(8, CGirl("冰冰", 18)); // 一次构造函数,一次拷贝构造函数。
//mm.emplace(8, "冰冰", 18); // 错误。
//mm.emplace(piecewise_construct, forward_as_tuple(8), forward_as_tuple("冰冰", 18)); // 一次构造函数。
//for (const auto& val : mm)
// cout << val.first << "," << val.second.m_name << "," << val.second.m_name << " ";
//cout << endl;
//return 0;
map<int, string> m;
// 1)void insert(initializer_list<pair<K,V>> il); // 用统一初始化列表在容器中插入多个元素。
m.insert({ { 8,"冰冰" }, { 3,"西施" }});
m.insert({ pair<int,string>(1,"幂幂"), make_pair<int,string>(7,"金莲"), {5,"西瓜"}});
m.insert({ { 18,"冰冰" }, { 3,"西施" } });
// 2)pair<iterator,bool> insert(const pair<K,V> &value);
// 在容器中插入一个元素,返回值pair:first是已插入元素的迭代器,second是插入结果。
auto ret = m.insert(pair<int, string>(18, "花花"));
if (ret.second == true) cout << "插入成功:" << ret.first->first << "," << ret.first->second << endl;
else cout << "插入失败。\n";
// 3)void insert(iterator first, iterator last); // 用迭代器插入一个区间的元素。
// 4)pair<iterator, bool> emplace(...);
// 将创建新键值对所需的数据作为参数直接传入,map容器将直接构造元素。
// 返回值pair:first是已插入元素的迭代器,second是插入结果。
auto ret1 = m.emplace(20, "花花");
if (ret1.second == true) cout << "插入成功:" << ret1.first->first << "," << ret1.first->second << endl;
else cout << "插入失败。\n";
// 5)iterator emplace_hint(const_iterator pos, ...);
// 功能与第4)个函数相同,第一个参数提示插入位置,该参数只有参考意义,如果提示的位置是正确的,
// 对性能有提升,如果提示的位置不正确,性能反而略有下降,但是,插入是否成功与该参数元关。
// 该参数常用end()和begin()。成功返回新插入元素的迭代器;如果元素已经存在,则插入失败,返回现
// 有元素的迭代器。
m.emplace_hint(m.begin(), piecewise_construct, forward_as_tuple(23), forward_as_tuple("冰棒"));
for (auto& val : m)
cout << val.first << "," << val.second << " ";
cout << endl;
}
五、unordered_map容器
六、queue容器
七、
- ref:从0基础系统化学习C++,不可能学不会,https://gitee.com/jiwangreal/code_bbs_code