C++-STL01- 容器
引入
我们想存储多个学员的信息 , 现在学员数量不定
通过以前学习的知识 , 我们可以创建一个数组存储学员的信息
但是这个数组大小是多少呢 ?
过大会导致空间浪费 , 小了又需要扩容
对其中的数据进行操作也较为复杂
每次删除数据后还要对其进行回收等操作
这样我们在编写代码时将大量的时间在这种无关业务的事情上被浪费
为了我们能更好的关心业务操作
程序人员从函数 (functions) ,类别 (classes), 函数库 (function libraries), 类别库
(classlibraries) 、各种组件,从模块化设计,到面向对象 (object oriented ) ,进行设计 , 提供
了为了建立数据结构和算法的一套标准,并且降低他们之间的耦合关系,以提升各自的独
立性、弹性、交互操作性 ( 相互合作性 ,interoperability), 诞生了 STL
概述
STL(Standard Template Library, 标准模板库 ), 是惠普实验室开发的一系列软件的统称。
STL 六大组件
容器 :
作用 : 容纳存储数据
分类 :
序列式容器:
强调值的排序,每个元素均有固定的位置, 除非用删除或插入的操作改
变这个位置,
如 vector, deque/queue, list;
关联式容器 :
非线性,更准确的说是二叉树结构,各元素之间没有严格的物理上的顺
序关系 ;
在数据中选择一个关键字 key ,这个 key 对数据起到索引的作用,方便查
找。
如: Set/multiset , Map/multimap 容器
注意 : 容器可以嵌套容器
算法 :
作用 : 操作数据 , 如插入数据、删除数据、修改数据、排序等
分类 :
质变算法:是指运算过程中会更改区间内的元素的内容。例如拷贝,替换,删
除等等 优点
常用容器
string
作用 :
存储字符的容器
常用操作
构造函数
非质变算法:是指运算过程中不会更改区间内的元素内容,例如查找、计数、
遍历、寻找极值等等
迭代器
作用 : 容器与算法之间的粘合剂
注意 : 每个容器都有自己的迭代器
分类 :
输入迭代器 提供对数据的只读访问 只读,支持 ++ 、 == 、! =
输出迭代器 提供对数据的只写访问 只写,支持 ++
前向迭代器 提供读写操作,并能向前推进迭代器 读写,支持 ++ 、 == 、! =
双向迭代器 提供读写操作,并能向前和向后操作 读写,支持 ++ 、 -- ,
随机访问迭代器 提供读写操作,并能以跳跃的方式访问容器的任意数据,是
功能最强的迭代器读写,支持 ++ 、 -- [n] 、 - n 、 < 、 <= 、 > 、 >=
仿函数
作用 : 为算法提供策略
适配器
作用 : 为算法提供更多的参数接口
空间配置器
作用 : 为容器和算法管理空间
有高可重用性
高性能
高移植性
跨平台
string();// 创建一个空的字符串 例如 : string str;
string(const string& str);// 使用一个 string 对象初始化另一个 string 对象
string(const char* s);// 使用字符串 s 初始化
string(int n, char c);// 使用 n 个字符 c 初始化 v 基本赋值操作
获取字符串长度
存取字符操作
示例
拼接操作
string& operator=(const char* s);//char 类型字符串赋值给当前的字符串
string& operator=(const string &s);// 把字符串 s 赋给当前的字符串
string& operator=(char c);// 字符赋值给当前的字符串
string& assign(const char *s);// 把字符串 s 赋给当前的字符串
string& assign(const char *s, int n);// 把字符串 s 的前 n 个字符赋给当前的字符
串
string& assign(const string &s);// 把字符串 s 赋给当前字符串
string& assign(int n, char c);// 用 n 个字符 c 赋给当前字符串
string& assign(const string &s, int start, int n);// 将 s 从 start 开始 n 个
字符赋值给字符串
int size();
int length();
char& operator[](int n);// 通过 [] 方式取字符 , 下标越界不会抛出异常
char& at(int n);// 通过 at 方法获取字符 , 下标越界会抛出异常
string str13 = "abcdefg" ;
char c1 = str13 [ 2 ];
cout << " 获取单个字符 1:" << c1 << endl ;
char c2 = str13 . at ( 5 );
cout << " 获取单个字符 2:" << c2 << endl ;
str13 [ 0 ] = '1' ;
cout << str13 << endl ;
str13 . at ( 1 ) = '2' ;
cout << str13 << endl ;
string& operator+=(const string& str);// 重载 += 操作符
string& operator+=(const char* str);// 重载 += 操作符
string& operator+=(const char c);// 重载 += 操作符 查找和替换
比较操作
string& append(const char *s);// 把字符串 s 连接到当前字符串结尾
string& append(const char *s, int n);// 把字符串 s 的前 n 个字符连接到当前字符
串结尾
string& append(const string &s);// 同 operator+=()
string& append(const string &s, int pos, int n);// 把字符串 s 中从 pos 开始的
n 个字符连接到当前字符串结尾
string& append(int n, char c);// 在当前字符串结尾添加 n 个字符 c
int find(const string& str, int pos = 0) const; // 查找 str 第一次出现位置 ,
从 pos 开始查找
int find(const char* s, int pos = 0) const; // 查找 s 第一次出现位置 , 从 pos
开始查找
int find(const char* s, int pos, int n) const; // 从 pos 位置查找 s 的前 n 个字
符第一次位置
int find(const char c, int pos = 0) const; // 查找字符 c 第一次出现位置
int rfind(const string& str, int pos = npos) const;// 查找 str 最后一次位
置 , 从 pos 开始查找
int rfind(const char* s, int pos = npos) const;// 查找 s 最后一次出现位置 ,
从 pos 开始查找
int rfind(const char* s, int pos, int n) const;// 从 pos 查找 s 的前 n 个字符最
后一次位置
int rfind(const char c, int pos = 0) const; // 查找字符 c 最后一次出现位置
string& replace(int pos, int n, const string& str); // 替换从 pos 开始 n 个
字符为字符串 str
string& replace(int pos, int n, const char* s); // 替换从 pos 开始的 n 个字符
为字符串 s
/**
*compare 函数在 > 时返回 1 , < 时返回 -1 , == 时返回 0 。
* 比较区分大小写,比较时参考字典顺序,排越前面的越小。大写的 A 比小写的 a 小。
**/
int compare(const string &s) const;// 与字符串 s 比较
int compare(const char *s) const;// 与字符串 s 比较 截取
插入和删除
string* 和 c-style 字符串转换
vector
特点 :
与数组的区别
api
构造函数
string substr(int pos = 0, int n = npos) const;// 返回由 pos 开始的 n 个字符
组成的字符串
string& insert(int pos, const char* s); // 插入字符串
string& insert(int pos, const string& str); // 插入字符串
string& insert(int pos, int n, char c);// 在指定位置插入 n 个字符 c
string& erase(int pos, int n = npos);// 删除从 Pos 开始的 n 个字符
//string 转 char*
string str = "itcast";
const char* cstr = str.c_str();
//char* 转 string
char* s = "itcast";
string str(s);
连续开辟 , 单向开口 , 随机访问迭代器 , 有容量 , 每次扩容是原来的 2 倍
底层数据结构 : 数组
vector 的结构类同于数组,数组是静态的,在定义时确定的数组的大小;
而 vector 是动态的,添加元素时如果空间不足时,则会自动扩容器( 2^n); 这被称为
vector 的未雨绸缪机制
整体来说, vector 比较灵活的,而且 vector 是类模板,可以存放任意类型的元素。
vector v; // 采用模板实现类实现,默认构造函数
vector(v.begin(), v.end());// 将 v[begin(), end()) 区间中的元素拷贝给本
身。
vector(n, elem);// 构造函数将 n 个 elem 拷贝给本身。
vector(const vector &vec);// 拷贝构造函数 迭代器
示例
赋值操作
本质就是 vector 中一个元素的指针
void fun01 ()
{
// 创建一个空的 vector
//vector vs;
// 创建一个 vector 里面存储 5 个 10
//vector vs(5,10);
int nums [ 5 ] = { 1 , 3 , 5 , 7 , 9 };
// 将数组下标为 0~4 的 5 个元素存储到 vs 中
vector < int > vs ( nums , nums + 5 );
// 获取 vs 中收个元素的地址赋值给其迭代器
vector < int > :: iterator it = vs . begin ();
// 判断迭代器是否已经移动到最后一位
while ( it != vs . end ()) {
// 获取迭代器指向的值
cout << * it << endl ;
// 迭代器后移一位
it ++ ;
}
cout << "--------------------" << endl ;
// 将 vs 的值赋值给 vs2
vector < int > vs2 ( vs );
vector < int > :: iterator it2 = vs2 . begin ();
while ( it2 != vs2 . end ()) {
cout << * it2 << endl ;
it2 ++ ;
}
}
assign(beg, end);// 将 [beg, end) 区间中的数据拷贝赋值给本身。
assign(n, elem);// 将 n 个 elem 拷贝赋值给本身。
vector& operator=(const vector &vec);// 重载等号操作符
swap(vec);// 将 vec 与本身的元素互换 示例
插入与删除
示例
void fun02()
{
int nums[5] = {1,3,5,7,9};
vector vs1(nums,nums+5);
vector vs2;
//vs2.assign(vs1.begin(),vs1.end());
//vs2.assign(6,1);
//vs2 = vs1;
vs2.swap(vs1);
cout << "vs1 的内容 " << endl;
vector::iterator it1 = vs1.begin();
while (it1 != vs1.end()) {
cout << *it1 << endl;
it1++;
}
cout << "vs2 的内容 " << endl;
vector::iterator it2 = vs2.begin();
while (it2 != vs2.end()) {
cout << *it2 << endl;
it2++;
}
}
push_back(ele); // 尾部插入元素 ele
insert(const_iterator pos, int count, T ele); // 迭代器指向位置 pos 插入
count 个元素 ele.
pop_back();// 删除最后一个元素
erase(const_iterator start, const_iterator end); // 删除迭代器从 start
到 end 之间的元素 , 删除 [start, end) 区间的所有元素
erase(const_iterator pos); // 删除迭代器指向的元素
clear(); // 删除容器中所有元素
void print_vector ( vector < int >& v )
{
vector < int > :: iterator it = v . begin ();
while ( it != v . end ()) {
cout << * it << "\t" ;
it ++ ;
}
cout << endl ; 取值操作
示例
}
void fun03 ()
{
vector < int > vs ;
// 尾部添加
vs . push_back ( 2 );
vs . push_back ( 4 );
vs . push_back ( 6 );
vs . push_back ( 8 );
vs . push_back ( 10 );
print_vector ( vs );
// 插入
vs . insert ( vs . begin (), 1 , 1 );
print_vector ( vs );
// 删除最后一个
vs . pop_back ();
print_vector ( vs );
// 删除指定区间 , 包含开始位置 , 不包含结束位置
vs . erase ( vs . begin () + 2 , vs . begin () + 4 );
print_vector ( vs );
// 删除指定位置的元素
vs . erase ( vs . begin () + 1 );
print_vector ( vs );
// 清空
vs . clear ();
print_vector ( vs );
}
at(int idx); // 返回索引 idx 所指的数据,如果 idx 越界,抛出 out_of_range
异常。
operator[](int idx); // 返回索引 idx 所指的数据,越界时,运行直接报错
front(); // 返回容器中第一个数据元素
back(); // 返回容器中最后一个数据元素
void fun04 ()
{
vector < int > vs ;
// 尾部添加
vs . push_back ( 2 );
vs . push_back ( 4 );
vs . push_back ( 6 );
vs . push_back ( 8 );
vs . push_back ( 10 ); 大小相关
示例
cout << vs . at ( 1 ) << endl ;
cout << vs [ 2 ] << endl ;
cout << vs . front () << endl ;
cout << vs . back () << endl ;
}
int size(); // 返回容器中元素的个数
bool empty(); // 判断容器是否为空, 返回 bool 值( 0 , 1 )
void resize(int num); // 重新指定容器的长度为 num ,若容器变长,则以默认值填
充新位置。如果容器变短,则末尾超出容器长度的元素被删除。
void resize(int num, elem); // 重新指定容器的长度为 num ,若容器变长,则以
elem 值填充新位置。如果容器变短,则末尾超出容器长度的元素被删除。
int capacity(); // 容器的容量
void reserve(int len); // 容器预留 len 个元素长度
void fun05 ()
{
vector < int > vs ;
// 预留空间
//vs.reserve(10);
cout << " 元素个数: " << vs . size () << endl ;
cout << " 是否为空: " << vs . empty () << endl ;
cout << " 容量大小: " << vs . capacity () << endl << endl ;
vs . resize ( 3 );
print_vector ( vs );
cout << " 元素个数: " << vs . size () << endl ;
cout << " 是否为空: " << vs . empty () << endl ;
cout << " 容量大小: " << vs . capacity () << endl << endl ;
vs . resize ( 5 , 10 );
print_vector ( vs );
cout << " 元素个数: " << vs . size () << endl ;
cout << " 是否为空: " << vs . empty () << endl ;
cout << " 容量大小: " << vs . capacity () << endl << endl ;
vs . reserve ( 3 );
print_vector ( vs );
cout << " 元素个数: " << vs . size () << endl ;
cout << " 是否为空: " << vs . empty () << endl ; 存放自定义对象
容器嵌套
cout << " 容量大小: " << vs . capacity () << endl << endl ;
}
#include
class Person
{
friend void printVectorPerson ( vector < Person > & v );
private :
int num ;
string name ;
public :
Person (){}
Person ( int num , string name )
{
this -> num = num ;
this -> name = name ;
}
};
void printVectorPerson ( vector < Person > & v )
{
vector < Person > :: iterator it = v . begin ();
for (; it != v . end (); it ++ )
{
//*it==Person
cout << ( * it ). num << " " << ( * it ). name << endl ;
//cout<num<<" "<name<
}
}
void fun06 ()
{
vector < Person > v1 ;
v1 . push_back ( Person ( 100 , "lucy" ));
v1 . push_back ( Person ( 101 , "bob" ));
v1 . push_back ( Person ( 102 , "tom" ));
v1 . push_back ( Person ( 103 , " 德玛 " ));
printVectorPerson ( v1 );
}
void fun07 ()
{
vector < int > v1 ;
v1 . push_back ( 10 );
v1 . push_back ( 20 );
v1 . push_back ( 30 );
v1 . push_back ( 40 );
v1 . push_back ( 50 ); 小技巧
使用 swap 缩小空间
vector < int > v2 ;
v2 . push_back ( 100 );
v2 . push_back ( 200 );
v2 . push_back ( 300 );
v2 . push_back ( 400 );
v2 . push_back ( 500 );
vector < int > v3 ;
v3 . push_back ( 1000 );
v3 . push_back ( 2000 );
v3 . push_back ( 3000 );
v3 . push_back ( 4000 );
v3 . push_back ( 5000 );
vector < vector < int >> v ;
v . push_back ( v1 );
v . push_back ( v2 );
v . push_back ( v3 );
vector < vector < int >> :: iterator it = v . begin ();
for (; it != v . end (); it ++ )
{
//*it == vector
vector < int > :: iterator mit = ( * it ). begin ();
for (; mit != ( * it ). end (); mit ++ )
{
//*mit==int
cout <<* mit << " " ;
}
cout << endl ;
}
}
void fun08 ()
{
// 收缩空间
vector < int > vs ;
vs . push_back ( 1 );
vs . push_back ( 2 );
vs . push_back ( 3 );
vs . push_back ( 4 );
vs . push_back ( 5 );
print_vector ( vs );
cout << " 元素个数: " << vs . size () << endl ;
cout << " 容量大小: " << vs . capacity () << endl << endl ; deque
特点
与 vector 的区别
vector < int > ( vs ). swap ( vs );
print_vector ( vs );
cout << " 元素个数: " << vs . size () << endl ;
cout << " 容量大小: " << vs . capacity () << endl << endl ;
}
deque 则是一种双向开口的连续线性空间。所谓的双向开口,意思是可以在头尾两端分
别做元素的插入和删除操作
一在于 deque 允许使用常数项时间对头端进行元素的插入和删除操作。
二在于 deque 没有容量的概念,因为它是动态的以分段连续空间组合而成,随时可以
增加一段新的空间并链接起来 api
示例
题目
// 构造函数
deque < T > deqT ; // 默认构造形式
deque ( beg , end ); // 构造函数将 [beg, end) 区间中的元素拷贝给本身。
deque ( n , elem ); // 构造函数将 n 个 elem 拷贝给本身。
deque ( const deque & deq ); // 拷贝构造函数
// 赋值操作
assign ( beg , end ); // 将 [beg, end) 区间中的数据拷贝赋值给本身。
assign ( n , elem ); // 将 n 个 elem 拷贝赋值给本身。
deque & operator = ( const deque & deq ); // 重载等号操作符
swap ( deq ); // 将 deq 与本身的元素互换
// 大小操作
deque . size (); // 返回容器中元素的个数
deque . empty (); // 判断容器是否为空
deque . resize ( num ); // 重新指定容器的长度为 num, 若容器变长,则以默认值填充新
位置。如果容器变短,则末尾超出容器长度的元素被删除。
deque . resize ( num , elem ); // 重新指定容器的长度为 num, 若容器变长,则以 elem
值填充新位置 , 如果容器变短,则末尾超出容器长度的元素被删除。
// 双端插入和删除操作
push_back ( elem ); // 在容器尾部添加一个数据
push_front ( elem ); // 在容器头部插入一个数据
pop_back (); // 删除容器最后一个数据
pop_front (); // 删除容器第一个数据
// 数据存取
at ( idx ); // 返回索引 idx 所指的数据,如果 idx 越界,抛出 out_of_range 。
operator []; // 返回索引 idx 所指的数据,如果 idx 越界,不抛出异常,直接出
错。
front (); // 返回第一个数据。
back (); // 返回最后一个数据
// 插入操作
insert ( pos , elem ); // 在 pos 位置插入一个 elem 元素的拷贝,返回新数据的位置。
insert ( pos , n , elem ); // 在 pos 位置插入 n 个 elem 数据,无返回值。
insert ( pos , beg , end ); // 在 pos 位置插入 [beg,end) 区间的数据,无返回值。
// 删除操作
clear (); // 移除容器的所有数据
erase ( beg , end ); // 删除 [beg,end) 区间的数据,返回下一个数据的位置。
erase ( pos ); // 删除 pos 位置的数据,返回下一个数据的位置。 有 5 名选手:选手 ABCDE , 10 个评委分别对每一名选手打分,去除最高分,去除评
委中最低分,取平均分。
1. 创建五名选手,放到 vector 中
2. 遍历 vector 容器,取出来每一个选手,执行 for 循环,可以把 10 个评分
打分存到 deque 容器中
3. sort 算法对 deque 容器中分数排序, pop_back pop_front 去除最高和最低
分
4. deque 容器遍历一遍,累加分数,累加分数 /d.size()
5. person.score = 平均分
代码
#include
using namespace std ;
#include
#include
#include
#include
#include
class Person {
friend void printInfo ( vector < Person > & v );
friend void startGame ( vector < Person > & v );
string name ;
double score ;
public :
Person (){}
Person ( string name , double score )
{
this -> name = name ;
this -> score = score ;
}
};
void createPerson ( vector < Person > & v )
{
string str = "ABCDE" ;
for ( int i = 0 ; i < str . size (); i ++ )
{
string name = " 选手 " ;
name += str [ i ];
Person p ( name , 0 );
v . push_back ( p );
}
}
void printInfo ( vector < Person > & v )
{
vector < Person > :: iterator it = v . begin ();
while ( it != v . end ()) {
cout << ( * it ). name << "\t" << ( * it ). score << endl ;
it ++ ; }
}
void startGame ( vector < Person > & v )
{
srand ( time ( NULL ));
vector < Person > :: iterator it = v . begin ();
while ( it != v . end ())
{
deque < int > scores ;
for ( int i = 0 ; i < 10 ; i ++ )
{
int s = rand () % 41 + 60 ;
scores . push_back ( s );
}
cout << " 开始给 " << ( * it ). name << " 打分 " << endl ;
for ( int i = 0 ; i < scores . size (); i ++ )
{
cout << " 评委 " << i << " 给出的分数为 :" << scores [ i ] << endl ;
}
// 排序 默认从小到大
sort ( scores . begin (), scores . end ());
// 从大到小
//sort(scores.begin(),scores.end(),greater());
// 去掉一个最低分
scores . pop_front ();
// 去掉一个最高分
scores . pop_back ();
// 计算总分
int score = accumulate ( scores . begin (), scores . end (), 0 );
double s = score * 1.0 / scores . size ();
cout << ( * it ). name << " 的平均分为 :" << s << endl ;
( * it ). score = s ;
it ++ ;
}
}
int main ( int argc , char * argv [])
{
vector < Person > persons ;
createPerson ( persons );
startGame ( persons );
printInfo ( persons );
return 0 ;
} stack
特点
常用函数
示例
先进后出 , 单向开口 , 没有迭代器
构造函数
stack stkT;//stack 采用模板类实现, stack 对象的默认构造形式:
stack(const stack &stk);// 拷贝构造函数
赋值操作
stack& operator=(const stack &stk);// 重载等号操作符
数据存取操作
push(elem);// 向栈顶添加元素
pop();// 从栈顶移除第一个元素
top();// 返回栈顶元素
大小操作
empty();// 判断堆栈是否为空
size();// 返回堆栈的大小
#include
void test01 ()
{
stack < int > s1 ;
s1 . push ( 10 );
s1 . push ( 20 ); queue
特点
常用函数
示例
s1 . push ( 30 );
s1 . push ( 40 );
s1 . push ( 50 );
cout << " 栈容器大小 :" << s1 . size () << endl ;
while ( ! s1 . empty ())
{
cout << s1 . top () << " " ;
s1 . pop (); // 出栈
}
}
先进先出 , 双向开口 , 没有迭代器
队头 : 出数据
队尾 : 入数据
构造函数
queue queT;//queue 采用模板类实现, queue 对象的默认构造形式:
queue(const queue &que);// 拷贝构造函数
存取、插入和删除操作
push(elem);// 往队尾添加元素
pop();// 从队头移除第一个元素
back();// 返回最后一个元素
front();// 返回第一个元素
赋值操作
queue& operator=(const queue &que);// 重载等号操作符
大小操作
empty();// 判断队列是否为空
size();// 返回队列的大小
#include
void test02 ()
{
queue < int > q1 ;
q1 . push ( 10 );
q1 . push ( 20 );
q1 . push ( 30 );
q1 . push ( 40 );
q1 . push ( 50 ); list
特点
常用函数
cout << " 队容器大小 :" << q1 . size () << endl ;
while ( ! q1 . empty ())
{
cout << q1 . front () << " " ;
q1 . pop (); // 出队
}
}
双向链表 , 双向迭代器 , 元素可重复
注意 :
双向迭代器不支持 +1, 或 +2 等操作
构造函数
list lstT;//list 采用采用模板类实现 , 对象的默认构造形式:
list(beg,end);// 构造函数将 [beg, end) 区间中的元素拷贝给本身。
list(n,elem);// 构造函数将 n 个 elem 拷贝给本身。
list(const list &lst);// 拷贝构造函数。
数据元素插入和删除操作
push_back(elem);// 在容器尾部加入一个元素
pop_back();// 删除容器中最后一个元素
push_front(elem);// 在容器开头插入一个元素
pop_front();// 从容器开头移除第一个元素
insert(pos,elem);// 在 pos 位置插 elem 元素的拷贝,返回新数据的位置。
insert(pos,n,elem);// 在 pos 位置插入 n 个 elem 数据,无返回值。
insert(pos,beg,end);// 在 pos 位置插入 [beg,end) 区间的数据,无返回值。
clear();// 移除容器的所有数据
erase(beg,end);// 删除 [beg,end) 区间的数据,返回下一个数据的位置。
erase(pos);// 删除 pos 位置的数据,返回下一个数据的位置。
remove(elem);// 删除容器中所有与 elem 值匹配的元素。
大小操作 示例
size();// 返回容器中元素的个数
empty();// 判断容器是否为空
resize(num);// 重新指定容器的长度为 num ,若容器变长,则以默认值填充新位
置。如果容器变短,则末尾超出容器长度的元素被删除。
resize(num, elem);// 重新指定容器的长度为 num, 若容器变长,则以 elem 值
填充新位置。如果容器变短,则末尾超出容器长度的元素被删除。
赋值操作
assign(beg, end);// 将 [beg, end) 区间中的数据拷贝赋值给本身。
assign(n, elem);// 将 n 个 elem 拷贝赋值给本身。
list& operator=(const list &lst);// 重载等号操作符
swap(lst);// 将 lst 与本身的元素互换。
数据的存取
front();// 返回第一个元素。
back();// 返回最后一个元素。
反转排序
reverse();// 反转链表,比如 lst 包含 1,3,5 元素,运行此方法后, lst 就包
含 5,3,1 元素。
sort(); //list 排序
#include
void printListInt ( list < int > & l )
{
list < int > :: iterator it = l . begin ();
for (; it != l . end (); it ++ )
{
cout <<* it << " " ;
}
cout << endl ;
}
void test03 ()
{
list < int > l1 ;
l1 . push_back ( 10 );
l1 . push_back ( 20 );
l1 . push_back ( 30 );
l1 . push_front ( 40 );
l1 . push_front ( 50 );
l1 . push_front ( 60 ); //60 50 40 10 20 30
cout << " 大小 :" << l1 . size () << endl ;
printListInt ( l1 );
list < int > :: iterator it = l1 . begin ();
// 双向迭代器不支持 +1
//it+2;//err set/multiset
set 特点
multiset 特点
常用函数
it ++ ;
it ++ ;
l1 . insert ( it , 3 , 100 );
printListInt ( l1 );
// 删除所有 100 数据
l1 . remove ( 100 );
printListInt ( l1 );
// 链表反转
l1 . reverse ();
printListInt ( l1 );
// 链表排序
// 标准 STL 算法 不能操作双向迭代器
//sort(l1.begin(), l1.end());//err
l1 . sort ();
printListInt ( l1 );
}
Set 的特性是。所有元素都会根据元素的键值自动被排序。
set 容器的键值和实值 是同一个值。
Set 不允许两个元素 有相同的键值。
Set 容器的迭代器 是只读迭代器。 插入数据后 不允许修改 set 的键值。
multiset 特性及用法和 set 完全相同,唯一的差别在于它允许键值重复。
set 和 multiset 的底层实现是红黑树,红黑树为平衡二叉树的一种。
构造函数
set st;//set 默认构造函数:
mulitset mst; //multiset 默认构造函数 :
set(const set &st);// 拷贝构造函数
赋值操作
set& operator=(const set &st);// 重载等号操作符
swap(st);// 交换两个集合容器
大小操作
size();// 返回容器中元素的数目
empty();// 判断容器是否为空
插入和删除操作 示例
1, 基本使用
insert(elem);// 在容器中插入元素。
clear();// 清除所有元素
erase(pos);// 删除 pos 迭代器所指的元素,返回下一个元素的迭代器。
erase(beg, end);// 删除区间 [beg,end) 的所有元素 ,返回下一个元素的迭代
器。
erase(elem);// 删除容器中值为 elem 的元素。
查找操作
find(key);// 查找键 key 是否存在 , 若存在,返回该键的元素的迭代器;若不存
在,返回 set.end();
count(key);// 查找键 key 的元素个数
lower_bound(keyElem);// 下限返回第一个 key>=keyElem 元素的迭代器。
upper_bound(keyElem);// 上限返回第一个 key>keyElem 元素的迭代器。
equal_range(keyElem);// 返回容器中 key 与 keyElem 相等的上下限的两个迭
代器。
void printSetInt ( set < int > & s )
{
set < int > :: const_iterator it = s . begin ();
for (; it != s . end (); it ++ )
{
cout <<* it << " " ;
}
cout << endl ;
}
void test01 ()
{
set < int > s1 ;
s1 . insert ( 20 );
s1 . insert ( 50 );
s1 . insert ( 10 );
s1 . insert ( 40 );
s1 . insert ( 30 );
printSetInt ( s1 );
//count(key);// 查找键 key 的元素个数 ( 结果只能是 0 或 1)
cout << s1 . count ( 30 ) << endl ;
//find(key);// 查找键 key 是否存在 , 若存在,返回该键的元素的迭代器;若不存
在,返回 set.end();
set < int > :: const_iterator ret ;
ret = s1 . find ( 20 );
if ( ret == s1 . end ())
{
cout << " 未找到 " << endl ;
}
else {
cout << " 找到的数据为 :" <<* ret << endl ;
}
}
2,set 容器根据键值排序
#include
using namespace std ;
void printSetInt ( set < int > & s )
{
set < int > :: const_iterator it = s . begin ();
for (; it != s . end (); it ++ )
{
cout <<* it << " " ;
}
cout << endl ;
}
void test01 ()
{
set < int > s1 ;
s1 . insert ( 30 );
s1 . insert ( 20 );
s1 . insert ( 10 );
s1 . insert ( 50 );
s1 . insert ( 40 );
printSetInt ( s1 );
}
3, 修改 set 容器的排序规则
#include
#include
using namespace std ;
class MyGreater
{
public :
bool operator ()( int v1 , int v2 )
{
return v1 > v2 ;
}
};
void printSetInt ( set < int , MyGreater > & s )
{
set < int , MyGreater > :: const_iterator it = s . begin ();
for (; it != s . end (); it ++ )
{
cout <<* it << " " ;
} cout << endl ;
}
void test01 ()
{
set < int , MyGreater > s1 ;
s1 . insert ( 30 );
s1 . insert ( 20 );
s1 . insert ( 10 );
s1 . insert ( 50 );
s1 . insert ( 40 );
printSetInt ( s1 );
}
int main ( int argc , char * argv [])
{
test01 ();
return 0 ;
}
4:set 容器存放自定义数据 必须实现排序规则
#include
class Person ;
class GreaterPerson
{
public :
bool operator ()( Person ob1 , Person ob2 );
};
class Person
{
friend class GreaterPerson ;
friend void printSetPerson ( set < Person , GreaterPerson > & s );
private :
int num ;
string name ;
public :
Person (){}
Person ( int num , string name )
{
this -> num = num ;
this -> name = name ;
}
};
void printSetPerson ( set < Person , GreaterPerson > & s )
{
set < Person , GreaterPerson > :: const_iterator it = s . begin ();
for (; it != s . end (); it ++ ) {
cout << ( * it ). num << " " << ( * it ). name << endl ;
}
}
void test02 ()
{
set < Person , GreaterPerson > s1 ;
s1 . insert ( Person ( 101 , "lucy" ));
s1 . insert ( Person ( 103 , "bob" ));
s1 . insert ( Person ( 102 , "tom" ));
s1 . insert ( Person ( 105 , " 小炮 " ));
s1 . insert ( Person ( 106 , " 小法 " ));
printSetPerson ( s1 );
}
int main ( int argc , char * argv [])
{
test02 ();
return 0 ;
}
bool GreaterPerson::operator ()( Person ob1 , Person ob2 )
{
return ob1 . num < ob2 . num ;
}
5,multiset 值可以重复
#include
void test02 ()
{
multiset < int > mset ;
mset . insert ( 10 );
mset . insert ( 10 );
mset . insert ( 10 );
multiset < int > :: const_iterator it = mset . begin ();
while ( it != mset . end ())
{
cout << * it << endl ;
it ++ ;
}
}
6, 上下限
void test03 ()
{
set < int > s1 ;
s1 . insert ( 20 );
s1 . insert ( 50 ); map/multimap
前置知识 : 对组
示例
s1 . insert ( 10 );
s1 . insert ( 40 );
s1 . insert ( 30 );
printSetInt ( s1 );
// 寻找下限
set < int > :: const_iterator ret ;
ret = s1 . lower_bound ( 30 );
if ( ret != s1 . end ())
{
cout << " 下限值为 :" <<* ret << endl ;
}
// 寻找上限
ret = s1 . upper_bound ( 30 );
if ( ret != s1 . end ())
{
cout << " 上限值为 :" <<* ret << endl ;
}
// 寻找上下限 ,pair 对组 , 本质是一个结构体 , 其中一个成员存放上限 , 一个成员存储下
限
pair < set < int > :: const_iterator , set < int > :: const_iterator > pr ;
pr = s1 . equal_range ( 30 );
if ( pr . first != s1 . end ())
{
cout << " 下限值为 :" <<* ( pr . first ) << endl ;
}
if ( pr . second != s1 . end ())
{
cout << " 上限值为 :" <<* ( pr . second ) << endl ;
}
}
int main ( int argc , char * argv [])
{
test03 ();
return 0 ;
}
对组 (pair) 将一对值组合成一个值,这一对值可以具有不同的数据类型,两个值可以分
别用 pair 的两个公有属性 first 和 second 访问。 map 特点
示例
示例 1: 存储基本数据类型
示例 2: 存储自定义类型
pair < int , string > p1 ( 1 , " 小翠 " ); // 创建方式 1
pair < int , string > p2 = make_pair ( 2 , " 酸菜 " ); // 创建方式 2
//first: 键值
//second: 实值
cout << p1 . first << " " << p1 . second << endl ;
cout << p2 . first << " " << p2 . second << endl ;
所有元素都会根据元素的键值自动排序。
Map 所有的元素都是 pair, 同时拥有实值和键值, pair 的第一元素被视为键值,第二
元素被视为实值。
map 容器的迭代器是只读迭代器。键值不允许修改,不能重复。
void test01 ()
{
map < int , string > m1 ;
// 方式一:
m1 . insert ( pair < int , string > ( 10086 , " 移动 " ));
// 方式二 : 推荐
m1 . insert ( make_pair ( 10010 , " 联通 " ));
// 方式三:
m1 . insert ( map < int , string > :: value_type ( 10000 , " 电信 " ));
// 方式四 :
m1 [ 9527 ] = " 星爷 " ;
map < int , string > :: const_iterator it = m1 . begin ();
for (; it != m1 . end (); it ++ )
{
//*it ==pair
cout << " 键值 :" << ( * it ). first << " 实值 :" << ( * it ). second << endl ;
}
}
class Person
{
friend void printMapIntPerson ( map < int , Person > & m );
private :
int num ;
string name ;
float score ;
public :
Person (){}
Person ( int num , string name , float score ) multimap 特点
综合案例
{
this -> num = num ;
this -> name = name ;
this -> score = score ;
}
};
void printMapIntPerson ( map < int , Person > & m )
{
map < int , Person > :: const_iterator it = m . begin ();
for (; it != m . end (); it ++ )
{
//*it ==
cout << " 学号 :" << ( * it ). first << " 姓名 :" << ( * it ). second . name << " 分数 :"
<< ( * it ). second . score << endl ;
}
}
void test02 ()
{
map < int , Person > m ;
m . insert ( make_pair ( 103 , Person ( 103 , "lucy" , 77.7f )));
m . insert ( make_pair ( 101 , Person ( 101 , "bob" , 77.7f )));
m . insert ( make_pair ( 104 , Person ( 104 , "tom" , 77.7f )));
m . insert ( make_pair ( 102 , Person ( 102 , " 德玛 " , 77.7f )));
printMapIntPerson ( m );
}
允许键值重复
#define SALE_DEPATMENT 1 // 销售部门
#define DEVELOP_DEPATMENT 2 // 研发部门
#define FINACIAL_DEPATMENT 3 // 财务部门
#include
#include
#include
#include
#include
using namespace std ;
class Person
{
friend void showPersonOfDepartment ( multimap < int , Person > & m , int
& op );
friend void personJoinDepartment ( vector < Person > & v , multimap < int ,
Person > & m );
private : string name ;
int age ;
int money ;
string tel ;
public :
Person (){}
Person ( string name , int age , int money , string tel )
{
this -> name = name ;
this -> age = age ;
this -> money = money ;
this -> tel = tel ;
}
};
void createPerson ( vector < Person > & v )
{
// 设置随机数种子
srand ( time ( NULL ));
int i = 0 ;
string tmpName = "ABCDE" ;
for ( i = 0 ; i < 5 ; i ++ )
{
string name = " 员工 " ;
name += tmpName [ i ];
int age = rand () % 5 + 16 ;
int money = rand () % 10000 + 20000 ;
string tel = to_string ( rand ());
v . push_back ( Person ( name , age , money , tel ));
}
}
void personJoinDepartment ( vector < Person > & v , multimap < int , Person > & m )
{
// 逐个员工加入部门
vector < Person > :: iterator it = v . begin ();
for (; it != v . end (); it ++ )
{
//*it==Person
cout << " 请输入 " << ( * it ). name << " 加入的部门 :1( 销售 ) 、 2( 研发 ) 、 3( 财
务 ):" ;
int op = 0 ;
cin >> op ;
// 加入部门
m . insert ( make_pair ( op , * it ));
}
}
void showPersonOfDepartment ( multimap < int , Person > & m , int & op )
{
//1 1 2 2 3
// 寻找 key 的位置
multimap < int , Person > :: const_iterator ret ; ret = m . find ( op );
if ( ret == m . end ())
{
cout << " 未找到相关部门员工信息 " << endl ;
return ;
}
// 统计部门员工个数
int count = m . count ( op );
// 显示部门员工信息
switch ( op ) {
case 1 :
cout << "---------------- 销售部门 ------------------" << endl ;
break ;
case 2 :
cout << "---------------- 研发部门 ------------------" << endl ;
break ;
case 3 :
cout << "---------------- 财务部门 ------------------" << endl ;
break ;
}
int i = 0 ;
for ( i = 0 ; i < count ; i ++ , ret ++ )
{
//(*ret)==< 部门 , 员工 >
cout << "\t" << ( * ret ). second . name << " " << ( * ret ). second . age << \
" " << ( * ret ). second . money << " " << ( * ret ). second . tel << endl ;
}
}
int main ( int argc , char * argv [])
{
multimap < int , Person > m ;
// 创建 vector 存放员工
vector < Person > v ;
createPerson ( v );
// 将 5 名员工加入部门
personJoinDepartment ( v , m );
// 显示部门员工
cout << " 请输入你要显示的部门 1( 销售 ) 、 2( 研发 ) 、 3( 财务 ):" ;
int op = 0 ;
cin >> op ;
showPersonOfDepartment ( m , op );
return 0 ;
} 总结
vector 单端动态数组 随机访问迭代器
比如软件历史操作记录的存储,我们经常要查看历史记录,比如上一次的记录,上上次
的记录,但却不会去删除记录,因为记录是事实的描述。
数据结构 : 数组
deque :双端动态数组 随机访问迭代器
deque 的使用场景:比如排队购票系统,对排队者的存储可以采用 deque ,支持头端
的快速移除,尾端的快速添加
stack 栈容器 没有迭代器 先进后出
queue 队列容器 没有迭代器 先进先出
list 链表容器 双向迭代器
比如公交车乘客的存储,随时可能有乘客下车,支持频繁的不确实位置元素的移除插入
数据结构 : 双链表
set 容器 只有键值 键值不能重复 自动排序 只读迭代器
比如对手机游戏的个人得分记录的存储,存储要求从高 分到低分的顺序排列。
数据结构 : 红黑树
map 容器: 键值 - 实值成对出现 键值不能重复 自动排序 只读迭代器
比如按 ID 号存储十万个用户,想要快速要通过 ID 查找对应的用户。
数据结构 :红黑树
C++-STL01- 容器
引入
我们想存储多个学员的信息 , 现在学员数量不定
通过以前学习的知识 , 我们可以创建一个数组存储学员的信息
但是这个数组大小是多少呢 ?
过大会导致空间浪费 , 小了又需要扩容
对其中的数据进行操作也较为复杂
每次删除数据后还要对其进行回收等操作
这样我们在编写代码时将大量的时间在这种无关业务的事情上被浪费
为了我们能更好的关心业务操作
程序人员从函数 (functions) ,类别 (classes), 函数库 (function libraries), 类别库
(classlibraries) 、各种组件,从模块化设计,到面向对象 (object oriented ) ,进行设计 , 提供
了为了建立数据结构和算法的一套标准,并且降低他们之间的耦合关系,以提升各自的独
立性、弹性、交互操作性 ( 相互合作性 ,interoperability), 诞生了 STL
概述
STL(Standard Template Library, 标准模板库 ), 是惠普实验室开发的一系列软件的统称。
STL 六大组件
容器 :
作用 : 容纳存储数据
分类 :
序列式容器:
强调值的排序,每个元素均有固定的位置, 除非用删除或插入的操作改
变这个位置,
如 vector, deque/queue, list;
关联式容器 :
非线性,更准确的说是二叉树结构,各元素之间没有严格的物理上的顺
序关系 ;
在数据中选择一个关键字 key ,这个 key 对数据起到索引的作用,方便查
找。
如: Set/multiset , Map/multimap 容器
注意 : 容器可以嵌套容器
算法 :
作用 : 操作数据 , 如插入数据、删除数据、修改数据、排序等
分类 :
质变算法:是指运算过程中会更改区间内的元素的内容。例如拷贝,替换,删
除等等 优点
常用容器
string
作用 :
存储字符的容器
常用操作
构造函数
非质变算法:是指运算过程中不会更改区间内的元素内容,例如查找、计数、
遍历、寻找极值等等
迭代器
作用 : 容器与算法之间的粘合剂
注意 : 每个容器都有自己的迭代器
分类 :
输入迭代器 提供对数据的只读访问 只读,支持 ++ 、 == 、! =
输出迭代器 提供对数据的只写访问 只写,支持 ++
前向迭代器 提供读写操作,并能向前推进迭代器 读写,支持 ++ 、 == 、! =
双向迭代器 提供读写操作,并能向前和向后操作 读写,支持 ++ 、 -- ,
随机访问迭代器 提供读写操作,并能以跳跃的方式访问容器的任意数据,是
功能最强的迭代器读写,支持 ++ 、 -- [n] 、 - n 、 < 、 <= 、 > 、 >=
仿函数
作用 : 为算法提供策略
适配器
作用 : 为算法提供更多的参数接口
空间配置器
作用 : 为容器和算法管理空间
有高可重用性
高性能
高移植性
跨平台
string();// 创建一个空的字符串 例如 : string str;
string(const string& str);// 使用一个 string 对象初始化另一个 string 对象
string(const char* s);// 使用字符串 s 初始化
string(int n, char c);// 使用 n 个字符 c 初始化 v 基本赋值操作
获取字符串长度
存取字符操作
示例
拼接操作
string& operator=(const char* s);//char 类型字符串赋值给当前的字符串
string& operator=(const string &s);// 把字符串 s 赋给当前的字符串
string& operator=(char c);// 字符赋值给当前的字符串
string& assign(const char *s);// 把字符串 s 赋给当前的字符串
string& assign(const char *s, int n);// 把字符串 s 的前 n 个字符赋给当前的字符
串
string& assign(const string &s);// 把字符串 s 赋给当前字符串
string& assign(int n, char c);// 用 n 个字符 c 赋给当前字符串
string& assign(const string &s, int start, int n);// 将 s 从 start 开始 n 个
字符赋值给字符串
int size();
int length();
char& operator[](int n);// 通过 [] 方式取字符 , 下标越界不会抛出异常
char& at(int n);// 通过 at 方法获取字符 , 下标越界会抛出异常
string str13 = "abcdefg" ;
char c1 = str13 [ 2 ];
cout << " 获取单个字符 1:" << c1 << endl ;
char c2 = str13 . at ( 5 );
cout << " 获取单个字符 2:" << c2 << endl ;
str13 [ 0 ] = '1' ;
cout << str13 << endl ;
str13 . at ( 1 ) = '2' ;
cout << str13 << endl ;
string& operator+=(const string& str);// 重载 += 操作符
string& operator+=(const char* str);// 重载 += 操作符
string& operator+=(const char c);// 重载 += 操作符 查找和替换
比较操作
string& append(const char *s);// 把字符串 s 连接到当前字符串结尾
string& append(const char *s, int n);// 把字符串 s 的前 n 个字符连接到当前字符
串结尾
string& append(const string &s);// 同 operator+=()
string& append(const string &s, int pos, int n);// 把字符串 s 中从 pos 开始的
n 个字符连接到当前字符串结尾
string& append(int n, char c);// 在当前字符串结尾添加 n 个字符 c
int find(const string& str, int pos = 0) const; // 查找 str 第一次出现位置 ,
从 pos 开始查找
int find(const char* s, int pos = 0) const; // 查找 s 第一次出现位置 , 从 pos
开始查找
int find(const char* s, int pos, int n) const; // 从 pos 位置查找 s 的前 n 个字
符第一次位置
int find(const char c, int pos = 0) const; // 查找字符 c 第一次出现位置
int rfind(const string& str, int pos = npos) const;// 查找 str 最后一次位
置 , 从 pos 开始查找
int rfind(const char* s, int pos = npos) const;// 查找 s 最后一次出现位置 ,
从 pos 开始查找
int rfind(const char* s, int pos, int n) const;// 从 pos 查找 s 的前 n 个字符最
后一次位置
int rfind(const char c, int pos = 0) const; // 查找字符 c 最后一次出现位置
string& replace(int pos, int n, const string& str); // 替换从 pos 开始 n 个
字符为字符串 str
string& replace(int pos, int n, const char* s); // 替换从 pos 开始的 n 个字符
为字符串 s
/**
*compare 函数在 > 时返回 1 , < 时返回 -1 , == 时返回 0 。
* 比较区分大小写,比较时参考字典顺序,排越前面的越小。大写的 A 比小写的 a 小。
**/
int compare(const string &s) const;// 与字符串 s 比较
int compare(const char *s) const;// 与字符串 s 比较 截取
插入和删除
string* 和 c-style 字符串转换
vector
特点 :
与数组的区别
api
构造函数
string substr(int pos = 0, int n = npos) const;// 返回由 pos 开始的 n 个字符
组成的字符串
string& insert(int pos, const char* s); // 插入字符串
string& insert(int pos, const string& str); // 插入字符串
string& insert(int pos, int n, char c);// 在指定位置插入 n 个字符 c
string& erase(int pos, int n = npos);// 删除从 Pos 开始的 n 个字符
//string 转 char*
string str = "itcast";
const char* cstr = str.c_str();
//char* 转 string
char* s = "itcast";
string str(s);
连续开辟 , 单向开口 , 随机访问迭代器 , 有容量 , 每次扩容是原来的 2 倍
底层数据结构 : 数组
vector 的结构类同于数组,数组是静态的,在定义时确定的数组的大小;
而 vector 是动态的,添加元素时如果空间不足时,则会自动扩容器( 2^n); 这被称为
vector 的未雨绸缪机制
整体来说, vector 比较灵活的,而且 vector 是类模板,可以存放任意类型的元素。
vector v; // 采用模板实现类实现,默认构造函数
vector(v.begin(), v.end());// 将 v[begin(), end()) 区间中的元素拷贝给本
身。
vector(n, elem);// 构造函数将 n 个 elem 拷贝给本身。
vector(const vector &vec);// 拷贝构造函数 迭代器
示例
赋值操作
本质就是 vector 中一个元素的指针
void fun01 ()
{
// 创建一个空的 vector
//vector vs;
// 创建一个 vector 里面存储 5 个 10
//vector vs(5,10);
int nums [ 5 ] = { 1 , 3 , 5 , 7 , 9 };
// 将数组下标为 0~4 的 5 个元素存储到 vs 中
vector < int > vs ( nums , nums + 5 );
// 获取 vs 中收个元素的地址赋值给其迭代器
vector < int > :: iterator it = vs . begin ();
// 判断迭代器是否已经移动到最后一位
while ( it != vs . end ()) {
// 获取迭代器指向的值
cout << * it << endl ;
// 迭代器后移一位
it ++ ;
}
cout << "--------------------" << endl ;
// 将 vs 的值赋值给 vs2
vector < int > vs2 ( vs );
vector < int > :: iterator it2 = vs2 . begin ();
while ( it2 != vs2 . end ()) {
cout << * it2 << endl ;
it2 ++ ;
}
}
assign(beg, end);// 将 [beg, end) 区间中的数据拷贝赋值给本身。
assign(n, elem);// 将 n 个 elem 拷贝赋值给本身。
vector& operator=(const vector &vec);// 重载等号操作符
swap(vec);// 将 vec 与本身的元素互换 示例
插入与删除
示例
void fun02()
{
int nums[5] = {1,3,5,7,9};
vector vs1(nums,nums+5);
vector vs2;
//vs2.assign(vs1.begin(),vs1.end());
//vs2.assign(6,1);
//vs2 = vs1;
vs2.swap(vs1);
cout << "vs1 的内容 " << endl;
vector::iterator it1 = vs1.begin();
while (it1 != vs1.end()) {
cout << *it1 << endl;
it1++;
}
cout << "vs2 的内容 " << endl;
vector::iterator it2 = vs2.begin();
while (it2 != vs2.end()) {
cout << *it2 << endl;
it2++;
}
}
push_back(ele); // 尾部插入元素 ele
insert(const_iterator pos, int count, T ele); // 迭代器指向位置 pos 插入
count 个元素 ele.
pop_back();// 删除最后一个元素
erase(const_iterator start, const_iterator end); // 删除迭代器从 start
到 end 之间的元素 , 删除 [start, end) 区间的所有元素
erase(const_iterator pos); // 删除迭代器指向的元素
clear(); // 删除容器中所有元素
void print_vector ( vector < int >& v )
{
vector < int > :: iterator it = v . begin ();
while ( it != v . end ()) {
cout << * it << "\t" ;
it ++ ;
}
cout << endl ; 取值操作
示例
}
void fun03 ()
{
vector < int > vs ;
// 尾部添加
vs . push_back ( 2 );
vs . push_back ( 4 );
vs . push_back ( 6 );
vs . push_back ( 8 );
vs . push_back ( 10 );
print_vector ( vs );
// 插入
vs . insert ( vs . begin (), 1 , 1 );
print_vector ( vs );
// 删除最后一个
vs . pop_back ();
print_vector ( vs );
// 删除指定区间 , 包含开始位置 , 不包含结束位置
vs . erase ( vs . begin () + 2 , vs . begin () + 4 );
print_vector ( vs );
// 删除指定位置的元素
vs . erase ( vs . begin () + 1 );
print_vector ( vs );
// 清空
vs . clear ();
print_vector ( vs );
}
at(int idx); // 返回索引 idx 所指的数据,如果 idx 越界,抛出 out_of_range
异常。
operator[](int idx); // 返回索引 idx 所指的数据,越界时,运行直接报错
front(); // 返回容器中第一个数据元素
back(); // 返回容器中最后一个数据元素
void fun04 ()
{
vector < int > vs ;
// 尾部添加
vs . push_back ( 2 );
vs . push_back ( 4 );
vs . push_back ( 6 );
vs . push_back ( 8 );
vs . push_back ( 10 ); 大小相关
示例
cout << vs . at ( 1 ) << endl ;
cout << vs [ 2 ] << endl ;
cout << vs . front () << endl ;
cout << vs . back () << endl ;
}
int size(); // 返回容器中元素的个数
bool empty(); // 判断容器是否为空, 返回 bool 值( 0 , 1 )
void resize(int num); // 重新指定容器的长度为 num ,若容器变长,则以默认值填
充新位置。如果容器变短,则末尾超出容器长度的元素被删除。
void resize(int num, elem); // 重新指定容器的长度为 num ,若容器变长,则以
elem 值填充新位置。如果容器变短,则末尾超出容器长度的元素被删除。
int capacity(); // 容器的容量
void reserve(int len); // 容器预留 len 个元素长度
void fun05 ()
{
vector < int > vs ;
// 预留空间
//vs.reserve(10);
cout << " 元素个数: " << vs . size () << endl ;
cout << " 是否为空: " << vs . empty () << endl ;
cout << " 容量大小: " << vs . capacity () << endl << endl ;
vs . resize ( 3 );
print_vector ( vs );
cout << " 元素个数: " << vs . size () << endl ;
cout << " 是否为空: " << vs . empty () << endl ;
cout << " 容量大小: " << vs . capacity () << endl << endl ;
vs . resize ( 5 , 10 );
print_vector ( vs );
cout << " 元素个数: " << vs . size () << endl ;
cout << " 是否为空: " << vs . empty () << endl ;
cout << " 容量大小: " << vs . capacity () << endl << endl ;
vs . reserve ( 3 );
print_vector ( vs );
cout << " 元素个数: " << vs . size () << endl ;
cout << " 是否为空: " << vs . empty () << endl ; 存放自定义对象
容器嵌套
cout << " 容量大小: " << vs . capacity () << endl << endl ;
}
#include
class Person
{
friend void printVectorPerson ( vector < Person > & v );
private :
int num ;
string name ;
public :
Person (){}
Person ( int num , string name )
{
this -> num = num ;
this -> name = name ;
}
};
void printVectorPerson ( vector < Person > & v )
{
vector < Person > :: iterator it = v . begin ();
for (; it != v . end (); it ++ )
{
//*it==Person
cout << ( * it ). num << " " << ( * it ). name << endl ;
//cout<num<<" "<name<
}
}
void fun06 ()
{
vector < Person > v1 ;
v1 . push_back ( Person ( 100 , "lucy" ));
v1 . push_back ( Person ( 101 , "bob" ));
v1 . push_back ( Person ( 102 , "tom" ));
v1 . push_back ( Person ( 103 , " 德玛 " ));
printVectorPerson ( v1 );
}
void fun07 ()
{
vector < int > v1 ;
v1 . push_back ( 10 );
v1 . push_back ( 20 );
v1 . push_back ( 30 );
v1 . push_back ( 40 );
v1 . push_back ( 50 ); 小技巧
使用 swap 缩小空间
vector < int > v2 ;
v2 . push_back ( 100 );
v2 . push_back ( 200 );
v2 . push_back ( 300 );
v2 . push_back ( 400 );
v2 . push_back ( 500 );
vector < int > v3 ;
v3 . push_back ( 1000 );
v3 . push_back ( 2000 );
v3 . push_back ( 3000 );
v3 . push_back ( 4000 );
v3 . push_back ( 5000 );
vector < vector < int >> v ;
v . push_back ( v1 );
v . push_back ( v2 );
v . push_back ( v3 );
vector < vector < int >> :: iterator it = v . begin ();
for (; it != v . end (); it ++ )
{
//*it == vector
vector < int > :: iterator mit = ( * it ). begin ();
for (; mit != ( * it ). end (); mit ++ )
{
//*mit==int
cout <<* mit << " " ;
}
cout << endl ;
}
}
void fun08 ()
{
// 收缩空间
vector < int > vs ;
vs . push_back ( 1 );
vs . push_back ( 2 );
vs . push_back ( 3 );
vs . push_back ( 4 );
vs . push_back ( 5 );
print_vector ( vs );
cout << " 元素个数: " << vs . size () << endl ;
cout << " 容量大小: " << vs . capacity () << endl << endl ; deque
特点
与 vector 的区别
vector < int > ( vs ). swap ( vs );
print_vector ( vs );
cout << " 元素个数: " << vs . size () << endl ;
cout << " 容量大小: " << vs . capacity () << endl << endl ;
}
deque 则是一种双向开口的连续线性空间。所谓的双向开口,意思是可以在头尾两端分
别做元素的插入和删除操作
一在于 deque 允许使用常数项时间对头端进行元素的插入和删除操作。
二在于 deque 没有容量的概念,因为它是动态的以分段连续空间组合而成,随时可以
增加一段新的空间并链接起来 api
示例
题目
// 构造函数
deque < T > deqT ; // 默认构造形式
deque ( beg , end ); // 构造函数将 [beg, end) 区间中的元素拷贝给本身。
deque ( n , elem ); // 构造函数将 n 个 elem 拷贝给本身。
deque ( const deque & deq ); // 拷贝构造函数
// 赋值操作
assign ( beg , end ); // 将 [beg, end) 区间中的数据拷贝赋值给本身。
assign ( n , elem ); // 将 n 个 elem 拷贝赋值给本身。
deque & operator = ( const deque & deq ); // 重载等号操作符
swap ( deq ); // 将 deq 与本身的元素互换
// 大小操作
deque . size (); // 返回容器中元素的个数
deque . empty (); // 判断容器是否为空
deque . resize ( num ); // 重新指定容器的长度为 num, 若容器变长,则以默认值填充新
位置。如果容器变短,则末尾超出容器长度的元素被删除。
deque . resize ( num , elem ); // 重新指定容器的长度为 num, 若容器变长,则以 elem
值填充新位置 , 如果容器变短,则末尾超出容器长度的元素被删除。
// 双端插入和删除操作
push_back ( elem ); // 在容器尾部添加一个数据
push_front ( elem ); // 在容器头部插入一个数据
pop_back (); // 删除容器最后一个数据
pop_front (); // 删除容器第一个数据
// 数据存取
at ( idx ); // 返回索引 idx 所指的数据,如果 idx 越界,抛出 out_of_range 。
operator []; // 返回索引 idx 所指的数据,如果 idx 越界,不抛出异常,直接出
错。
front (); // 返回第一个数据。
back (); // 返回最后一个数据
// 插入操作
insert ( pos , elem ); // 在 pos 位置插入一个 elem 元素的拷贝,返回新数据的位置。
insert ( pos , n , elem ); // 在 pos 位置插入 n 个 elem 数据,无返回值。
insert ( pos , beg , end ); // 在 pos 位置插入 [beg,end) 区间的数据,无返回值。
// 删除操作
clear (); // 移除容器的所有数据
erase ( beg , end ); // 删除 [beg,end) 区间的数据,返回下一个数据的位置。
erase ( pos ); // 删除 pos 位置的数据,返回下一个数据的位置。 有 5 名选手:选手 ABCDE , 10 个评委分别对每一名选手打分,去除最高分,去除评
委中最低分,取平均分。
1. 创建五名选手,放到 vector 中
2. 遍历 vector 容器,取出来每一个选手,执行 for 循环,可以把 10 个评分
打分存到 deque 容器中
3. sort 算法对 deque 容器中分数排序, pop_back pop_front 去除最高和最低
分
4. deque 容器遍历一遍,累加分数,累加分数 /d.size()
5. person.score = 平均分
代码
#include
using namespace std ;
#include
#include
#include
#include
#include
class Person {
friend void printInfo ( vector < Person > & v );
friend void startGame ( vector < Person > & v );
string name ;
double score ;
public :
Person (){}
Person ( string name , double score )
{
this -> name = name ;
this -> score = score ;
}
};
void createPerson ( vector < Person > & v )
{
string str = "ABCDE" ;
for ( int i = 0 ; i < str . size (); i ++ )
{
string name = " 选手 " ;
name += str [ i ];
Person p ( name , 0 );
v . push_back ( p );
}
}
void printInfo ( vector < Person > & v )
{
vector < Person > :: iterator it = v . begin ();
while ( it != v . end ()) {
cout << ( * it ). name << "\t" << ( * it ). score << endl ;
it ++ ; }
}
void startGame ( vector < Person > & v )
{
srand ( time ( NULL ));
vector < Person > :: iterator it = v . begin ();
while ( it != v . end ())
{
deque < int > scores ;
for ( int i = 0 ; i < 10 ; i ++ )
{
int s = rand () % 41 + 60 ;
scores . push_back ( s );
}
cout << " 开始给 " << ( * it ). name << " 打分 " << endl ;
for ( int i = 0 ; i < scores . size (); i ++ )
{
cout << " 评委 " << i << " 给出的分数为 :" << scores [ i ] << endl ;
}
// 排序 默认从小到大
sort ( scores . begin (), scores . end ());
// 从大到小
//sort(scores.begin(),scores.end(),greater());
// 去掉一个最低分
scores . pop_front ();
// 去掉一个最高分
scores . pop_back ();
// 计算总分
int score = accumulate ( scores . begin (), scores . end (), 0 );
double s = score * 1.0 / scores . size ();
cout << ( * it ). name << " 的平均分为 :" << s << endl ;
( * it ). score = s ;
it ++ ;
}
}
int main ( int argc , char * argv [])
{
vector < Person > persons ;
createPerson ( persons );
startGame ( persons );
printInfo ( persons );
return 0 ;
} stack
特点
常用函数
示例
先进后出 , 单向开口 , 没有迭代器
构造函数
stack stkT;//stack 采用模板类实现, stack 对象的默认构造形式:
stack(const stack &stk);// 拷贝构造函数
赋值操作
stack& operator=(const stack &stk);// 重载等号操作符
数据存取操作
push(elem);// 向栈顶添加元素
pop();// 从栈顶移除第一个元素
top();// 返回栈顶元素
大小操作
empty();// 判断堆栈是否为空
size();// 返回堆栈的大小
#include
void test01 ()
{
stack < int > s1 ;
s1 . push ( 10 );
s1 . push ( 20 ); queue
特点
常用函数
示例
s1 . push ( 30 );
s1 . push ( 40 );
s1 . push ( 50 );
cout << " 栈容器大小 :" << s1 . size () << endl ;
while ( ! s1 . empty ())
{
cout << s1 . top () << " " ;
s1 . pop (); // 出栈
}
}
先进先出 , 双向开口 , 没有迭代器
队头 : 出数据
队尾 : 入数据
构造函数
queue queT;//queue 采用模板类实现, queue 对象的默认构造形式:
queue(const queue &que);// 拷贝构造函数
存取、插入和删除操作
push(elem);// 往队尾添加元素
pop();// 从队头移除第一个元素
back();// 返回最后一个元素
front();// 返回第一个元素
赋值操作
queue& operator=(const queue &que);// 重载等号操作符
大小操作
empty();// 判断队列是否为空
size();// 返回队列的大小
#include
void test02 ()
{
queue < int > q1 ;
q1 . push ( 10 );
q1 . push ( 20 );
q1 . push ( 30 );
q1 . push ( 40 );
q1 . push ( 50 ); list
特点
常用函数
cout << " 队容器大小 :" << q1 . size () << endl ;
while ( ! q1 . empty ())
{
cout << q1 . front () << " " ;
q1 . pop (); // 出队
}
}
双向链表 , 双向迭代器 , 元素可重复
注意 :
双向迭代器不支持 +1, 或 +2 等操作
构造函数
list lstT;//list 采用采用模板类实现 , 对象的默认构造形式:
list(beg,end);// 构造函数将 [beg, end) 区间中的元素拷贝给本身。
list(n,elem);// 构造函数将 n 个 elem 拷贝给本身。
list(const list &lst);// 拷贝构造函数。
数据元素插入和删除操作
push_back(elem);// 在容器尾部加入一个元素
pop_back();// 删除容器中最后一个元素
push_front(elem);// 在容器开头插入一个元素
pop_front();// 从容器开头移除第一个元素
insert(pos,elem);// 在 pos 位置插 elem 元素的拷贝,返回新数据的位置。
insert(pos,n,elem);// 在 pos 位置插入 n 个 elem 数据,无返回值。
insert(pos,beg,end);// 在 pos 位置插入 [beg,end) 区间的数据,无返回值。
clear();// 移除容器的所有数据
erase(beg,end);// 删除 [beg,end) 区间的数据,返回下一个数据的位置。
erase(pos);// 删除 pos 位置的数据,返回下一个数据的位置。
remove(elem);// 删除容器中所有与 elem 值匹配的元素。
大小操作 示例
size();// 返回容器中元素的个数
empty();// 判断容器是否为空
resize(num);// 重新指定容器的长度为 num ,若容器变长,则以默认值填充新位
置。如果容器变短,则末尾超出容器长度的元素被删除。
resize(num, elem);// 重新指定容器的长度为 num, 若容器变长,则以 elem 值
填充新位置。如果容器变短,则末尾超出容器长度的元素被删除。
赋值操作
assign(beg, end);// 将 [beg, end) 区间中的数据拷贝赋值给本身。
assign(n, elem);// 将 n 个 elem 拷贝赋值给本身。
list& operator=(const list &lst);// 重载等号操作符
swap(lst);// 将 lst 与本身的元素互换。
数据的存取
front();// 返回第一个元素。
back();// 返回最后一个元素。
反转排序
reverse();// 反转链表,比如 lst 包含 1,3,5 元素,运行此方法后, lst 就包
含 5,3,1 元素。
sort(); //list 排序
#include
void printListInt ( list < int > & l )
{
list < int > :: iterator it = l . begin ();
for (; it != l . end (); it ++ )
{
cout <<* it << " " ;
}
cout << endl ;
}
void test03 ()
{
list < int > l1 ;
l1 . push_back ( 10 );
l1 . push_back ( 20 );
l1 . push_back ( 30 );
l1 . push_front ( 40 );
l1 . push_front ( 50 );
l1 . push_front ( 60 ); //60 50 40 10 20 30
cout << " 大小 :" << l1 . size () << endl ;
printListInt ( l1 );
list < int > :: iterator it = l1 . begin ();
// 双向迭代器不支持 +1
//it+2;//err set/multiset
set 特点
multiset 特点
常用函数
it ++ ;
it ++ ;
l1 . insert ( it , 3 , 100 );
printListInt ( l1 );
// 删除所有 100 数据
l1 . remove ( 100 );
printListInt ( l1 );
// 链表反转
l1 . reverse ();
printListInt ( l1 );
// 链表排序
// 标准 STL 算法 不能操作双向迭代器
//sort(l1.begin(), l1.end());//err
l1 . sort ();
printListInt ( l1 );
}
Set 的特性是。所有元素都会根据元素的键值自动被排序。
set 容器的键值和实值 是同一个值。
Set 不允许两个元素 有相同的键值。
Set 容器的迭代器 是只读迭代器。 插入数据后 不允许修改 set 的键值。
multiset 特性及用法和 set 完全相同,唯一的差别在于它允许键值重复。
set 和 multiset 的底层实现是红黑树,红黑树为平衡二叉树的一种。
构造函数
set st;//set 默认构造函数:
mulitset mst; //multiset 默认构造函数 :
set(const set &st);// 拷贝构造函数
赋值操作
set& operator=(const set &st);// 重载等号操作符
swap(st);// 交换两个集合容器
大小操作
size();// 返回容器中元素的数目
empty();// 判断容器是否为空
插入和删除操作 示例
1, 基本使用
insert(elem);// 在容器中插入元素。
clear();// 清除所有元素
erase(pos);// 删除 pos 迭代器所指的元素,返回下一个元素的迭代器。
erase(beg, end);// 删除区间 [beg,end) 的所有元素 ,返回下一个元素的迭代
器。
erase(elem);// 删除容器中值为 elem 的元素。
查找操作
find(key);// 查找键 key 是否存在 , 若存在,返回该键的元素的迭代器;若不存
在,返回 set.end();
count(key);// 查找键 key 的元素个数
lower_bound(keyElem);// 下限返回第一个 key>=keyElem 元素的迭代器。
upper_bound(keyElem);// 上限返回第一个 key>keyElem 元素的迭代器。
equal_range(keyElem);// 返回容器中 key 与 keyElem 相等的上下限的两个迭
代器。
void printSetInt ( set < int > & s )
{
set < int > :: const_iterator it = s . begin ();
for (; it != s . end (); it ++ )
{
cout <<* it << " " ;
}
cout << endl ;
}
void test01 ()
{
set < int > s1 ;
s1 . insert ( 20 );
s1 . insert ( 50 );
s1 . insert ( 10 );
s1 . insert ( 40 );
s1 . insert ( 30 );
printSetInt ( s1 );
//count(key);// 查找键 key 的元素个数 ( 结果只能是 0 或 1)
cout << s1 . count ( 30 ) << endl ;
//find(key);// 查找键 key 是否存在 , 若存在,返回该键的元素的迭代器;若不存
在,返回 set.end();
set < int > :: const_iterator ret ;
ret = s1 . find ( 20 );
if ( ret == s1 . end ())
{
cout << " 未找到 " << endl ;
}
else {
cout << " 找到的数据为 :" <<* ret << endl ;
}
}
2,set 容器根据键值排序
#include
using namespace std ;
void printSetInt ( set < int > & s )
{
set < int > :: const_iterator it = s . begin ();
for (; it != s . end (); it ++ )
{
cout <<* it << " " ;
}
cout << endl ;
}
void test01 ()
{
set < int > s1 ;
s1 . insert ( 30 );
s1 . insert ( 20 );
s1 . insert ( 10 );
s1 . insert ( 50 );
s1 . insert ( 40 );
printSetInt ( s1 );
}
3, 修改 set 容器的排序规则
#include
#include
using namespace std ;
class MyGreater
{
public :
bool operator ()( int v1 , int v2 )
{
return v1 > v2 ;
}
};
void printSetInt ( set < int , MyGreater > & s )
{
set < int , MyGreater > :: const_iterator it = s . begin ();
for (; it != s . end (); it ++ )
{
cout <<* it << " " ;
} cout << endl ;
}
void test01 ()
{
set < int , MyGreater > s1 ;
s1 . insert ( 30 );
s1 . insert ( 20 );
s1 . insert ( 10 );
s1 . insert ( 50 );
s1 . insert ( 40 );
printSetInt ( s1 );
}
int main ( int argc , char * argv [])
{
test01 ();
return 0 ;
}
4:set 容器存放自定义数据 必须实现排序规则
#include
class Person ;
class GreaterPerson
{
public :
bool operator ()( Person ob1 , Person ob2 );
};
class Person
{
friend class GreaterPerson ;
friend void printSetPerson ( set < Person , GreaterPerson > & s );
private :
int num ;
string name ;
public :
Person (){}
Person ( int num , string name )
{
this -> num = num ;
this -> name = name ;
}
};
void printSetPerson ( set < Person , GreaterPerson > & s )
{
set < Person , GreaterPerson > :: const_iterator it = s . begin ();
for (; it != s . end (); it ++ ) {
cout << ( * it ). num << " " << ( * it ). name << endl ;
}
}
void test02 ()
{
set < Person , GreaterPerson > s1 ;
s1 . insert ( Person ( 101 , "lucy" ));
s1 . insert ( Person ( 103 , "bob" ));
s1 . insert ( Person ( 102 , "tom" ));
s1 . insert ( Person ( 105 , " 小炮 " ));
s1 . insert ( Person ( 106 , " 小法 " ));
printSetPerson ( s1 );
}
int main ( int argc , char * argv [])
{
test02 ();
return 0 ;
}
bool GreaterPerson::operator ()( Person ob1 , Person ob2 )
{
return ob1 . num < ob2 . num ;
}
5,multiset 值可以重复
#include
void test02 ()
{
multiset < int > mset ;
mset . insert ( 10 );
mset . insert ( 10 );
mset . insert ( 10 );
multiset < int > :: const_iterator it = mset . begin ();
while ( it != mset . end ())
{
cout << * it << endl ;
it ++ ;
}
}
6, 上下限
void test03 ()
{
set < int > s1 ;
s1 . insert ( 20 );
s1 . insert ( 50 ); map/multimap
前置知识 : 对组
示例
s1 . insert ( 10 );
s1 . insert ( 40 );
s1 . insert ( 30 );
printSetInt ( s1 );
// 寻找下限
set < int > :: const_iterator ret ;
ret = s1 . lower_bound ( 30 );
if ( ret != s1 . end ())
{
cout << " 下限值为 :" <<* ret << endl ;
}
// 寻找上限
ret = s1 . upper_bound ( 30 );
if ( ret != s1 . end ())
{
cout << " 上限值为 :" <<* ret << endl ;
}
// 寻找上下限 ,pair 对组 , 本质是一个结构体 , 其中一个成员存放上限 , 一个成员存储下
限
pair < set < int > :: const_iterator , set < int > :: const_iterator > pr ;
pr = s1 . equal_range ( 30 );
if ( pr . first != s1 . end ())
{
cout << " 下限值为 :" <<* ( pr . first ) << endl ;
}
if ( pr . second != s1 . end ())
{
cout << " 上限值为 :" <<* ( pr . second ) << endl ;
}
}
int main ( int argc , char * argv [])
{
test03 ();
return 0 ;
}
对组 (pair) 将一对值组合成一个值,这一对值可以具有不同的数据类型,两个值可以分
别用 pair 的两个公有属性 first 和 second 访问。 map 特点
示例
示例 1: 存储基本数据类型
示例 2: 存储自定义类型
pair < int , string > p1 ( 1 , " 小翠 " ); // 创建方式 1
pair < int , string > p2 = make_pair ( 2 , " 酸菜 " ); // 创建方式 2
//first: 键值
//second: 实值
cout << p1 . first << " " << p1 . second << endl ;
cout << p2 . first << " " << p2 . second << endl ;
所有元素都会根据元素的键值自动排序。
Map 所有的元素都是 pair, 同时拥有实值和键值, pair 的第一元素被视为键值,第二
元素被视为实值。
map 容器的迭代器是只读迭代器。键值不允许修改,不能重复。
void test01 ()
{
map < int , string > m1 ;
// 方式一:
m1 . insert ( pair < int , string > ( 10086 , " 移动 " ));
// 方式二 : 推荐
m1 . insert ( make_pair ( 10010 , " 联通 " ));
// 方式三:
m1 . insert ( map < int , string > :: value_type ( 10000 , " 电信 " ));
// 方式四 :
m1 [ 9527 ] = " 星爷 " ;
map < int , string > :: const_iterator it = m1 . begin ();
for (; it != m1 . end (); it ++ )
{
//*it ==pair
cout << " 键值 :" << ( * it ). first << " 实值 :" << ( * it ). second << endl ;
}
}
class Person
{
friend void printMapIntPerson ( map < int , Person > & m );
private :
int num ;
string name ;
float score ;
public :
Person (){}
Person ( int num , string name , float score ) multimap 特点
综合案例
{
this -> num = num ;
this -> name = name ;
this -> score = score ;
}
};
void printMapIntPerson ( map < int , Person > & m )
{
map < int , Person > :: const_iterator it = m . begin ();
for (; it != m . end (); it ++ )
{
//*it ==
cout << " 学号 :" << ( * it ). first << " 姓名 :" << ( * it ). second . name << " 分数 :"
<< ( * it ). second . score << endl ;
}
}
void test02 ()
{
map < int , Person > m ;
m . insert ( make_pair ( 103 , Person ( 103 , "lucy" , 77.7f )));
m . insert ( make_pair ( 101 , Person ( 101 , "bob" , 77.7f )));
m . insert ( make_pair ( 104 , Person ( 104 , "tom" , 77.7f )));
m . insert ( make_pair ( 102 , Person ( 102 , " 德玛 " , 77.7f )));
printMapIntPerson ( m );
}
允许键值重复
#define SALE_DEPATMENT 1 // 销售部门
#define DEVELOP_DEPATMENT 2 // 研发部门
#define FINACIAL_DEPATMENT 3 // 财务部门
#include
#include
#include
#include
#include
using namespace std ;
class Person
{
friend void showPersonOfDepartment ( multimap < int , Person > & m , int
& op );
friend void personJoinDepartment ( vector < Person > & v , multimap < int ,
Person > & m );
private : string name ;
int age ;
int money ;
string tel ;
public :
Person (){}
Person ( string name , int age , int money , string tel )
{
this -> name = name ;
this -> age = age ;
this -> money = money ;
this -> tel = tel ;
}
};
void createPerson ( vector < Person > & v )
{
// 设置随机数种子
srand ( time ( NULL ));
int i = 0 ;
string tmpName = "ABCDE" ;
for ( i = 0 ; i < 5 ; i ++ )
{
string name = " 员工 " ;
name += tmpName [ i ];
int age = rand () % 5 + 16 ;
int money = rand () % 10000 + 20000 ;
string tel = to_string ( rand ());
v . push_back ( Person ( name , age , money , tel ));
}
}
void personJoinDepartment ( vector < Person > & v , multimap < int , Person > & m )
{
// 逐个员工加入部门
vector < Person > :: iterator it = v . begin ();
for (; it != v . end (); it ++ )
{
//*it==Person
cout << " 请输入 " << ( * it ). name << " 加入的部门 :1( 销售 ) 、 2( 研发 ) 、 3( 财
务 ):" ;
int op = 0 ;
cin >> op ;
// 加入部门
m . insert ( make_pair ( op , * it ));
}
}
void showPersonOfDepartment ( multimap < int , Person > & m , int & op )
{
//1 1 2 2 3
// 寻找 key 的位置
multimap < int , Person > :: const_iterator ret ; ret = m . find ( op );
if ( ret == m . end ())
{
cout << " 未找到相关部门员工信息 " << endl ;
return ;
}
// 统计部门员工个数
int count = m . count ( op );
// 显示部门员工信息
switch ( op ) {
case 1 :
cout << "---------------- 销售部门 ------------------" << endl ;
break ;
case 2 :
cout << "---------------- 研发部门 ------------------" << endl ;
break ;
case 3 :
cout << "---------------- 财务部门 ------------------" << endl ;
break ;
}
int i = 0 ;
for ( i = 0 ; i < count ; i ++ , ret ++ )
{
//(*ret)==< 部门 , 员工 >
cout << "\t" << ( * ret ). second . name << " " << ( * ret ). second . age << \
" " << ( * ret ). second . money << " " << ( * ret ). second . tel << endl ;
}
}
int main ( int argc , char * argv [])
{
multimap < int , Person > m ;
// 创建 vector 存放员工
vector < Person > v ;
createPerson ( v );
// 将 5 名员工加入部门
personJoinDepartment ( v , m );
// 显示部门员工
cout << " 请输入你要显示的部门 1( 销售 ) 、 2( 研发 ) 、 3( 财务 ):" ;
int op = 0 ;
cin >> op ;
showPersonOfDepartment ( m , op );
return 0 ;
} 总结
vector 单端动态数组 随机访问迭代器
比如软件历史操作记录的存储,我们经常要查看历史记录,比如上一次的记录,上上次
的记录,但却不会去删除记录,因为记录是事实的描述。
数据结构 : 数组
deque :双端动态数组 随机访问迭代器
deque 的使用场景:比如排队购票系统,对排队者的存储可以采用 deque ,支持头端
的快速移除,尾端的快速添加
stack 栈容器 没有迭代器 先进后出
queue 队列容器 没有迭代器 先进先出
list 链表容器 双向迭代器
比如公交车乘客的存储,随时可能有乘客下车,支持频繁的不确实位置元素的移除插入
数据结构 : 双链表
set 容器 只有键值 键值不能重复 自动排序 只读迭代器
比如对手机游戏的个人得分记录的存储,存储要求从高 分到低分的顺序排列。
数据结构 : 红黑树
map 容器: 键值 - 实值成对出现 键值不能重复 自动排序 只读迭代器
比如按 ID 号存储十万个用户,想要快速要通过 ID 查找对应的用户。
数据结构 : 红黑树