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<T> v; //
采用模板实现类实现,默认构造函数
vector(v.begin(), v.end());//
将
v[begin(), end())
区间中的元素拷贝给本
身。
vector(n, elem);//
构造函数将
n
个
elem
拷贝给本身。
vector(const vector &vec);//
拷贝构造函数
迭代器
示例
赋值操作
本质就是
vector
中一个元素的指针
void
fun01
()
{
//
创建一个空的
vector
//vector<int> vs;
//
创建一个
vector
里面存储
5
个
10
//vector<int> 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<int> vs1(nums,nums+5);
vector<int> vs2;
//vs2.assign(vs1.begin(),vs1.end());
//vs2.assign(6,1);
//vs2 = vs1;
vs2.swap(vs1);
cout << "vs1
的内容
" << endl;
vector<int>::iterator it1 = vs1.begin();
while (it1 != vs1.end()) {
cout << *it1 << endl;
it1++;
}
cout << "vs2
的内容
" << endl;
vector<int>::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<string>
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<<it->num<<" "<<it->name<<endl;
}
}
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<int>
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
个评委分别对每一名选手打分,去除最高分,去除评
委中最