目录
1.STL简介
STLStandard Template Library
,即标准模板库,是一个具有工业强度的,高效的C++ 程序库。它被容纳于C++ 标准程序库C++ Standard Library
中,是ANSI/ISO C++
标准中最新的也是极具革命性的一部分。该库包含了诸多在计算机科学领域里所常用的基本数据结构和基本算法。为广大C++程序员们提供了一个可扩展的应用框架,高度体现了软件的可复用性。
STL的一个重要特点是数据结构和算法的分离。尽管这是个简单的概念,但这种分离确实使得STL变得非常通用。例如,由于STL的sort()
函数是完全通用的,你可以用它来操作几乎任何数据集合,包括链表,容器和数组;
STL另一个重要特性是它不是面向对象的。为了具有足够通用性,STL主要依赖于模板而不是封装,继承和虚函数(多态性)——OOP的三个要素。你在STL中找不到任何明显的类继承关系。这好像是一种倒退,但这正好是使得STL的组件具有广泛通用性的底层特征。另外,由于STL是基于模板,内联函数的使用使得生成的代码短小高效;
从逻辑层次来看,在STL中体现了泛型化程序设计的思想,引入了诸多新的名词,比如像需求requirements
,概念concept
,模型model
,容器container
,算法algorithmn
,迭代器iterator
等。与OOPobject-oriented programming
中的多态polymorphism
一样,泛型也是一种软件的复用技术;
从实现层次看,整个STL是以一种类型参数化的方式实现的,这种方式基于一个在早先C++标准中没有出现的语言特性--模板template
。
1.1 STL好处
1、节省开发时间,增加开发效率
数据结构有现成的,算法现成的,直接用就行了,我们程序猿把主要工作放到业务逻辑中就行了,什么意思呢?就是我们处理逻辑就行了。
2、高移植性
STL是C++标准库,所有的C++编译器都要支持这个。所以在有c++的地方就有STL
3、高性能
每个容器的操作,每个算法的实现,都是经过几代大师的修改,优化。所以,基本属于最好的结构了,我们自己写的东西,基本不会有这个好用
1.2 STL六大组件
容器、迭代器、算法、适配器、分配器、仿函数。以下做详细介绍
2. 顺序容器(container)
2.1 string
2.1.1 string是什么?
专门针对字符串操作的一个类,非常强大。字符串CString,QString
跟char* 的区别:
char* 呢就是指向字符数组收地址的指针,然后我们系统提供了一个string.h,这个头文件声明了很多字符串操作函数,strlen strcat strcmp strcpy...
string 则是一个类, 这个类将以上的内容封装到一起,使得字符串的操作更灵活,方式更多,管理更合理
string这个类,我们使用的时候不用考虑内存的分配与释放,不用担心越界崩溃,因为前辈在封装string的时候,已经把几乎所有情况都考虑到,并处理了。
2.1.2 string的使用
定义:构造函数 这里引用《C++Primer Plus》里的表
#include <iostream>
#include <string>
using namespace std;
// using string constructors
int main ()
{
string one("Lottery Winner!");
cout << one << endl; //输出结果:Lottery Wìnner !
string two(20 , '$' );
cout << two << endl; //输出结果:$$$$$$$$$$$$$$$$$$$$
string three(one);
cout << three << endl; //输出结果:Lottery Wìnner!
one +-="OOPS!";
cout << one << endl; //输出结果:Lottery Winner! OOPS!
two = "Sorry! That was ";
three[O] = 'P';
string four;
four = two + three;
cout << four << endl; //输出结果:Sorry! That was Pottery Winner!
char alls[] = "All's well that ends well";
string five(alls, 20);
cout << five << "!\n"; //输出结果:All's well that ends!
string six(alls+6 , alls + 10);
cout <<six<<","; //输出结果:well,
string seven(&five[6] , &f ve[10]);
cout << seven << "...\n"; //输出结果:well , well ...
str ng eight(four, 7 , 16);
cout << eight <<" in motion!" << endl; //输出结果 That was Pottery in motion!
return 0;
}
属性
容量
capacity():
默认容量大小(vs2013)申请15个容量(至少申请15个,以后多余容量就增加16个大小。vc6.0 是至少申请31个空间,以后每次增加32个
重新设置容量大小
reserve(): //修改容量不能变小,只能变大区间。
字符串长度
length():
字符个数
size():
重新设置字符个数
resize():
增删查改
//修改指定元素
[ ] //下标运算
at()
//中间插入
insert()
basic_string &insert( size_type index, const basic_string &str );
//index位置插入str
basic_string &insert( size_type index, const char *str );
//index位置插入一个字符串
basic_string &insert( size_type index1, const basic_string &str, size_type index2, size_type num );
//在index1的位置插入另一个对象的某一段
basic_string &insert( size_type index, const char *str, size_type num );
//插入前几个
basic_string &insert( size_type index, size_type num, char ch );
//插入num个ch
//尾巴插入
+= //拼接对象、拼接字符串
appand()
basic_string &append( const basic_string &str );
//尾巴通过一个对象拼接
basic_string &append( const char *str );
//尾巴通过一个字符串拼接
basic_string &append( const basic_string &str, size_type index, size_type len );
//拼接一个字对象的某一段
basic_string &append( const char *str, size_type num );
//拼接字符串前几个
basic_string &append( size_type num, char ch );
//拼接num个字符ch
//重新赋值
// = 赋值对象、字符串
assign()
basic_string &assign( const basic_string &str );
//以str赋值
basic_string &assign( const char *str );
//以字符串复制
basic_string &assign( const basic_string &str, size_type index,size_type len);
//中间几个赋值
basic_string &assign( const char *str, size_type num );
//字符串前一个赋值
basic_string &assign( size_type num, char ch );
//num个ch赋值
//删除
basic_string &erase( size_type index = 0, size_type num = npos );
//删除指定位置开始指定个数
erase(0, str2.length()); //全部清理
常用操作函数
//比较
//a < b 返回 -1, a == b 返回0, a > b 返回 1
//重载比较运算符, 结果是真和假
int compare( const basic_string &str );
//比较两个对象
int compare( const char *str );
//比较一个对象和字符串
int compare( size_type index, size_type length, const basic_string &str );
//本对象的一段,跟参数的对象比较
int compare( size_type index, size_type length, const basic_string &str, size_type index2,size_type length2 );
//两个字符串比较中间的某一段
//复制
size_type copy( char *str, size_type num, size_type index );
//将对象中的某一段复制进一个字符数组中
//查找子串
size_type find( const basic_string &str, size_type index );
//从指定位置开始查找str,找到就返回起始位置
size_type find( const char *str, size_type index );
//指定位置查找一个字符串
size_type find( char ch, size_type index );
//指定位置开始查找字符
//返回子串
substr( size_type index, size_type num = npos );
//返回指定区间范围的子串
//交换
swap( basic_string &str );
//交换两个对象的内容
2.1.3string 迭代器
定义一个string的迭代器
string::ierator ite;
怎么用
就相当于一个指向string对象元素的指针,本质相当于 一个char* 的指针,定义完了就跟指针的用法是一样的了
//通过迭代器遍历string类的元素
for (ite = str.begin();ite != str.end(); ite++)
//begin()返回一字符串头迭代器,end()返回字符串尾迭代器
{
cout << *ite;
}
for (size_t i = 0;i < str.size(); i++)
{
cout << ite[i];
}
//通过迭代器赋值
for (ite = str.begin();ite != str.end(); ite++)
{
*ite = ‘a’;
}
for (size_t i = 0;i < str.size(); i++)
{
ite[i] = 'a';
}
所以,可以看出来,这个迭代器,定义方法跟指针不一样,用法跟指针就一样了。
定义了一个指向 string 对象的 元素的 指针,为啥不定义成char*, 因为我们这个迭代器,是要跟算法链接的, 它适用于所有的容器,即一个通用类型的指针,或者类似 叫智能 指针。 都都不为过。
迭代器失效
string重新申请空间的时候,迭代器会失效的,需要重新给迭代器赋值
string成员函数涉及到迭代器的
iterator begin();
//函数返回一个迭代器,指向字符串的第一个元素.
iterator end();
//函数返回一个迭代器,指向字符串的末尾元素.(最后一个字符的下一个)
//尾后迭代器,并不指向实际元素,所以不能对它进行递增或解引用操作。
append( input_iterator start, input_iterator end );
//在字符串的末尾添加以迭代器start和end表示的字符序列.
//删除
iterator erase( iterator pos );
iterator erase( iterator start, iterator end );
//插入
void insert( iterator i, size_type num, const char &ch );
void insert( iterator i, iterator start, iterator end );
2.1.4两个算法
//头文件
#include <algorithm>
//遍历
template<class InputIterator, class Function>
Function for_each(InputIterator _First, InputIterator _Last, Function _Func );
//排序
void sort(Iterator _First, Iterator _Last );//从小到大
void sort( Iterator _First, Iterator _Last, greater<>() );//指定从大到小
2.2 vector(矢量)
2.2.1 vector定义
向量(动态数组)
内存的分配原理跟我们的string是一样的。
是连续的空间,空间不够用的,会申请一个更大的连续的空间,同时迭代器失效
头文件
#include <vector>
using namespace std;
//定义向量的对象
vector<int> vec;
容器的名字----类名
参数列表:容器的数据的类型
类型种类:基本数据类型
2.2.2 构造函数
vector();
//无参数的构造
vector(size_type _Count);
//n个元素
vector( size_type num, const TYPE &val );
//用num个val来初始化容器
vector( const vector &from );
//一定是同种类型元素的vector,用另一个vector对象初始化当前的vector对象
vector( input_iterator start, input_iterator end );
//用迭代器初始化
2.2.3属性
a. 容量capacity()
初始容量:定义对象的时候初始化几个,那么容量就是几,无参数就是0
空间不够用了,增容:vs上新空间的容量为原来空间容量的1.5倍。vc上 容量不够时增加,新增后容量为原来的2倍
b.修改容量reserve();
不能变小,只能变大。设置多大就是多大。重新分配容量后,迭代器失效
c. 元素个数
size()
d. 重新设置元素个数
resize()
缩小时候,容量不变,放大时候,容量改变
e. 对象是否有元素
empty()
2.2.4 增删查改操作
查、改
输出全部:
//循环迭代器
for(ite;ite!=end();++ite)
{
cout<<*ite;
}
//循环下标运算
for(int i=0;i<size;++i)
{
cout<<v[i];
}
//使用算法
for_each();
//改:利用输出的形式可以修改
输出单个元素:
at()
[ ] //下标运算
返回尾巴的元素:
back()
增
//尾添加
void push_back( const TYPE &val );
//中间添加
//在指定迭代器的位置加入一个数据
iterator insert( iterator loc, const TYPE &val );
//再某个迭代器后加num个值为value的元素
void insert( iterator loc, size_type num, const TYPE &val );
//再某个迭代器后加入另一个向量的中间一段
void insert( iterator loc, input_iterator start, input_iterator end );
删
//尾删除
void pop_back();
//删除指定元素
//删除一个
iterator erase( iterator loc );
//删除一段
iterator erase( iterator start, iterator end );
//删除所有
void clear();
交换两个vector内容
void swap( vector &from );
2.2.5迭代器
//定义vector的迭代器
vector<int>::iterator ite;//注意多了参数列表, string则没有
本质就是int* 指针char 就是char*指针
2.2.6两个算法
//头文件
#include <algorithm>
//遍历
template<class InputIterator, class Function>
Function for_each(InputIterator _First, InputIterator _Last, Function _Func );
//排序
void sort(Iterator _First, Iterator _Last );//从小到大
void sort( Iterator _First, Iterator _Last, greater<>() );//指定从大到小
//乱序
srand((unsigned int)time(1))
void random_shuffle(Iterator _First, Iterator _Last );//随机乱序
2.3list(双向链表)
2.3.1定义
双向链表 比单向链表多了个指向前方的指针。
与vector的区别:vector随机访问快,即下标运算,指哪打哪,尾添加,不申请空间的情况下,非常快。但vector不支持快速插入和删除,比较慢
list: 随机访问慢,支持下标支持快速插入和删除,且效率很高.
//头文件
#include <list>
using namespace std;
//定义list的对象
list<结构体> lt;
//构造函数
list();
//多个元素,初始值为0
list( size_type _Count);
//那么多个指定的值
list( size_type _Count, const Type& _Val);
//用一个list初始化当前的list
list( const _list& _Right);
//另一个对象中间的一段
list( InputIterator _First, InputIterator _Last );
2.3.2常见操作
查
//输出单个元素
back();
//返回尾巴的元素
front();
//返回第一个元素
//注意:链表不支持下标操作
//输出全部
//循环迭代器
for_each();
增
//头添加
push_front(const TYPE &val ) ;
//尾添加
void push_back( const TYPE &val );
//中间添加
//在指定迭代器的位置加入一个数据
iterator insert( iterator loc, const TYPE &val );
//再某个迭代器后加num个值为value的元素
void insert( iterator loc, size_type num, const TYPE &val );
//再某个迭代器后加入另一个向量的中间一段
void insert( iterator loc, input_iterator start, input_iterator end );
删
//尾删除
void pop_back();
//头删除
pop_front();
//删除指定元素
iterator erase( iterator loc );
//删除一段
iterator erase( iterator start, iterator end );
//清空
clear();
//删除list中重复的元素
unique() ;
// 删除所有跟参数相同的元素
void remove( const TYPE &val );//需要结构体重载==
改:利用迭代器遍历修改
其他操作
//交换两个list的内容
void swap( list &from );
//把list的元素倒转
reverse() ;
//如果容器本身自带排序,那么使用的时候,就可以不用选择算法的排序
sort();//默认从小到大排序
//合并两个list 前提:两个链表必须有序
void merge( list &lst );//合并后自动排序
//注意:需要在结构体中重载小于号
//如果链表元素是升序的,就要用<号,return true
//如果链表元素是降序序的,就要用>号,return true
2.3.3算法
遍历、排序与vector类似
查找函数
InputIterator find( InputIterator _First, InputIterator _Last, const Type& _Val );
//在一个容器中查找一个成员,返回这个成员的迭代器
//没找到,迭代器无效,使用崩溃
3.1 deque(双端队列)
deque 常见操作和以上容器一样,不过多介绍了。
说下不同点:
内存比较
vector 连续空间
list 不连续空间
deque 段连续空间
功能比较
vector
随机位置插入/删除效率低
随机访问效率高(下标运算) a[i]
不支持头添加,支持尾添加
list
随机位置插入/删除效率高
不支持随机访问
支持头添加,支持尾添加
deque
随机位置插入/删除效率不高
数据量512
支持随机访问[比vector慢,因为要做堆跳转]
迭代器结构复杂,这会降低访问效率
支持头添加,支持尾添加
使用选择
随机访问操作频率高,就选vector
插入删除频率高,头尾添加,就选list
随机访问+头添加,就选deque
支持随机访问,即支持[]以及at(),但是性能没有vector好。
可以在内部进行插入和删除操作,但性能不及list。
函数对比
对比vector
没有capacity和reserve
多了push_Front, pop_Front
其他函数一样