快速入门C++第九天——STL库
Vector
Vector说明
- vector是向量类型,可以容纳许多类型的数据,因此也被称为容器
- 可以理解为动态数组,是封装好了的类
- 进行vector操作前应添加头文件
#include <vector>
vector初始化
方法一
//定义具有10个整型元素的向量(尖括号为元素类型名,它可以是任何合法的数据类型),不具有初值,其值不确定
vector<int>a(10);
方法二
//定义具有10个整型元素的向量,且给出的每个元素初值为1
vector<int>a(10,1);
方法三
//用向量b给向量a赋值,a的值完全等价于b的值
vector<int>a(b);
方法四
//将向量b中从0-2(共三个)的元素赋值给a,a的类型为int型
vector<int>a(b.begin(),b.begin+3);
方法五
//从数组中获得初值
int b[7]={1,2,3,4,5,6,7};
vector<int> a(b,b+7);
vector对象的常用内置函数使用
#include<vector>
vector<int> a,b;
//b为向量,将b的0-2个元素赋值给向量a
a.assign(b.begin(),b.begin()+3);
//a含有4个值为2的元素
a.assign(4,2);
//返回a的最后一个元素
a.back();
//返回a的第一个元素
a.front();
//返回a的第i元素,当且仅当a存在
a[i];
//清空a中的元素
a.clear();
//判断a是否为空,空则返回true,非空则返回false
a.empty();
//删除a向量的最后一个元素
a.pop_back();
//删除a中第一个(从第0个算起)到第二个元素,也就是说删除的元素从a.begin()+1算起(包括它)一直到a.begin()+3(不包括它)结束
a.erase(a.begin()+1,a.begin()+3);
//在a的最后一个向量后插入一个元素,其值为5
a.push_back(5);
//在a的第一个元素(从第0个算起)位置插入数值5,
a.insert(a.begin()+1,5);
//在a的第一个元素(从第0个算起)位置插入3个数,其值都为5
a.insert(a.begin()+1,3,5);
//b为数组,在a的第一个元素(从第0个元素算起)的位置插入b的第三个元素到第5个元素(不包括b+6)
a.insert(a.begin()+1,b+3,b+6);
//返回a中元素的个数
a.size();
//返回a在内存中总共可以容纳的元素个数
a.capacity();
//将a的现有元素个数调整至10个,多则删,少则补,其值随机
a.resize(10);
//将a的现有元素个数调整至10个,多则删,少则补,其值为2
a.resize(10,2);
//将a的容量扩充至100,
a.reserve(100);
//b为向量,将a中的元素和b中的元素整体交换
a.swap(b);
//b为向量,向量的比较操作还有 != >= > <= <
a==b;
顺序访问vector的几种方式
对向量a添加元素的几种方式
向向量a中添加元素
vector<int>a;
for(int i=0;i<10;++i){a.push_back(i);}
从数组中选择元素向向量中添加
int a[6]={1,2,3,4,5,6};
vector<int> b;
for(int i=0;i<=4;++i){b.push_back(a[i]);}
从现有向量中选择元素向向量中添加
int a[6]={1,2,3,4,5,6};
vector<int>b;
vector<int>c(a,a+4);
for(vector<int>::iterator it=c.begin();it<c.end();++it)
{
b.push_back(*it);
}
从文件中读取元素向向量中添加
ifstream in("data.txt");
vector<int>a;
for(int i;in>>i){a.push_back(i);}
常见错误赋值方式
vector<int>a;
for(int i=0;i<10;++i){a[i]=i;}//下标只能用来获取已经存在的元素
从向量中读取元素
通过下标方式获取
int a[6]={1,2,3,4,5,6};
vector<int>b(a,a+4);
for(int i=0;i<=b.size()-1;++i){
cout<<b[i]<<endl;
}
通过迭代器方式读取
int a[6]={1,2,3,4,5,6};
vector<int>b(a,a+4);
for(vector<int>::iterator it=b.begin();it!=b.end();it++){
cout<<*it<<" ";
}
几个常用的算法
#include<algorithm>
//对a中的从a.begin()(包括它)到a.end()(不包括它)的元素进行从小到大排列
sort(a.begin(),a.end());
//对a中的从a.begin()(包括它)到a.end()(不包括它)的元素倒置,但不排列,如a中元素为1,3,2,4,倒置后为4,2,3,1
reverse(a.begin(),a.end());
//把a中的从a.begin()(包括它)到a.end()(不包括它)的元素复制到b中,从b.begin()+1的位置(包括它)开始复制,覆盖掉原有元素
copy(a.begin(),a.end(),b.begin()+1);
//在a中的从a.begin()(包括它)到a.end()(不包括它)的元素中查找10,若存在返回其在向量中的位置
find(a.begin(),a.end(),10);
List
简介
list 也是顺序容器的一种。只是list 是一个双向链表。使用 list 需要包含头文件 list。双向链表的每个元素中都有一个指针指向后一个元素,也有一个指针指向前一个元素,如下图所示。
当然,list的用法和vector很类似,也拥有顺序容器中的常用方法,需要注意的是list不支持使用下标随机存取元素。
List的成员函数
void push_front(const T & val) 将 val 插入链表最前面
void pop_front() 删除链表最前面的元素
void sort() 将链表从小到大排序
void remove (const T & val) 删除和 val 相等的元素
remove_if 删除符合某种条件的元素
void unique() 删除所有和前一个元素相等的元素
void merge(list <T> & x) 将链表 x 合并进来并清空 x。要求链表自身和 x 都是有序的
void splice(iterator i, list <T> & x, iterator first, iterator last)
在位置 i 前面插入链表 x 中的区间 [first, last),并在链表 x 中删除该区间。链表自身和链表 x 可以是同一个链表,只要 i 不在 [first, last) 中即可
list的用法实例
#include <iostream>
#include <list>
using namespace std;
int main(){
int a[6] = {1,3 ,2, 5,2,3};
int b[5] = {1,3,2,4,6};
list<int> L(a,a+6);
list<int> Lb(b,b+5);
list<int>::iterator pl;
cout<< "element in L : " ;
for(pl = L.begin(); pl != L.end();++pl){
cout << *pl << " " ;
}
cout << endl;
cout<< "element in Lb : " ;
for(pl = Lb.begin(); pl != Lb.end();++pl){
cout << *pl << " " ;
}
cout << endl;
L.sort();
cout<< "1) sort L: " ;
for(pl = L.begin(); pl != L.end();++pl){
cout << *pl << " " ;
}
cout << endl;
cout <<"2) after delete element 2: ";
L.remove(2);
for(pl = L.begin(); pl != L.end();++pl){
cout << *pl << " " ;
}
cout << endl;
cout << "3) delete first element in Lb: ";
Lb.pop_front();
for(pl = Lb.begin(); pl != Lb.end();++pl){
cout << *pl << " " ;
}
cout << endl;
cout << "4) delete all same element in L: ";
L.unique();
for(pl = L.begin(); pl != L.end();++pl){
cout << *pl << " " ;
}
cout << endl;
//使用merge
Lb.sort();
L.merge(Lb);
cout << "5) merge L with Lb: ";
L.unique();
for(pl = L.begin(); pl != L.end();++pl){
cout << *pl << " " ;
}
cout << endl;
cout << " size of Lb: " << Lb.size()<<endl;
L.reverse();
cout << "6) reverse L ";
for(pl = L.begin(); pl != L.end();++pl){
cout << *pl << " " ;
}
cout << endl;
return 0;
}
stack
stack简介
stack是一种先进先出的数据结构,被称为栈,它只有一端可以出入。
栈中进入数据称为——入栈(push)
栈中弹出数据称为——出栈(pop)
注意:
- 栈可以判断是否为空,也可以返回栈中元素个数,但栈不允许有遍历行为
- 使用stack容器必须包含头文件
#include<stack>
stack的常用接口
构造函数
stack<T> stk; //stack采用模板类实现,默认构造,T为数据类型,如int等
stack(const stack &stk); //拷贝构造
赋值操作
stack& operator=(const stack& stk);//重载赋值运算符
数据存取
push(elem); //入栈,向栈顶添加元素
pop(); //出栈,删除栈顶元素
top(); //返回栈顶元素
大小操作
empty(); //判断栈是否为空
size(); //返回栈的大小
用法举例
void text()
{
stack<int> stk1;
for (int i = 0; i < 5; ++i)
{
stk1.push(i+10);
}
stack<int> stk2(stk1);
cout << "stk1的大小为:" << stk1.size() << endl;
cout << "stk2的大小为:" << stk2.size() << endl;
//打印栈顶元素并出栈
while (!stk1.empty())//栈非空时
{
cout << "stk1栈顶元素为:" << stk1.top() << endl;
stk1.pop();
}
cout << "stk1的大小为:" << stk1.size() << endl;
stk2 = stk1;
cout << "stk2的大小为:" << stk2.size() << endl;
}
queue
queue的简介
queue是一种容器转换器模板,调用#include< queue>
即可使用队列类。
queue<Type, Container> (<数据类型,容器类型>)
初始化时必须要有数据类型,容器可省略,省略时则默认为 deque 类型
queue<char, list<char>>q1;
//用list容器实现的queue
queue<int, deque<int>>q2;
//用deque容器实现的queue
注意:不能用vector容器初始化queue
因为queue转换器要求容器支持front()、back()、push_back()及 pop_front(),说明queue的数据从容器后端入栈而从前端出栈。所以可以使用deque(double-ended queue,双端队列)和list对queue初始化,而vector因其缺少pop_front(),不能用于queue。
常用函数
- push() 在队尾插入一个元素
- pop() 删除队列第一个元素
- size() 返回队列中元素个数
- empty() 如果队列空则返回true
- front() 返回队列中的第一个元素
- back() 返回队列中最后一个元素
deque
deque简介
“deque” 是简写形式, 其原意为 “double-ended queue”。 deque 模板类提供了对序列随机访问的功能,可以实现在序列两端快速插入和删除操作 的功能, 在需要时修改自身大小。 deque 型容器是典型的双端队列, 可以完成标准C++ 数据 结构中队列的所有功能。
deque 是动态数组,在 STL 库的头文件 < deque >中
deque 型容器和 vector 型容器的对比:
- deque 可以在两端迅速插入和删除元素, 而 vector 只提供了成员函数 push_back()和 pop_back()。
- 存取元素时, deque 型容器会稍慢一些。
- deque 型容器的迭代器是智能型指针。
- 在内存区块受限制的系统中, deque 型容器可以包含更多元素, 因为它使用了多块 内存。
- deque 型容器不支持对容器和内存重分配时机的控制。
- deque 的内存区块不使用时, 会被释放。
- 在序列中间插入和删除元素时, deque 的速度很慢, 需要移动相关的所有元素。
- deque 型容器的迭代器属于随机存取迭代器。
deque 的定义和构造函数
无参,创建一个空双向队列
deque();
size - 创建一个大小为size的双向队列
deque( size_type size );
num and val - 放置num个val的拷贝到队列中
deque( size_type num, const TYPE &val );
from - 从from创建一个内容一样的双向队列
deque( const deque &from );
start 和 end - 创建一个队列,保存从start到end的元素
deque( input_iterator start, input_iterator end );
deque元素的存取和访问
pop_front()删除双向队列头部的元素
void pop_front();
pop_back()删除双向队列尾部的元素
void pop_back();
push_front()函数在双向队列的头部加入一个值为val的元素
void push_front( const TYPE &val );
push_back()函数在双向队列的尾部加入一个值为val的元素
void push_back( const TYPE &val );
顺序索引
- 使用[]操作符访问双向队列中单个的元素
- at()函数返回一个引用,指向双向队列中位置pos上的元素
reference at( size_type pos );
元素引用
- front()函数返回一个引用,指向双向队列的头部
- back()返回一个引用,指向双向队列中最后一个元素
迭代器相关
- begin()函数返回一个迭代器,指向双向队列的第一个元素
- end()函数返回一个迭代器,指向双向队列的尾部
- rbegin()返回一个指向双向队列尾部的逆向迭代器
- rend()返回一个指向双向队列头部的逆向迭代器
deque容器的容量
- empty()返回真如果双向队列为空,否则返回假
- size()函数返回双向队列中的元素个数
- resize()改变双向队列的大小为num,另加入的元素都被填充为val
deque基本操作
队列赋值
- assign()函数用start和end指示的范围为双向队列赋值
void assign( input_iterator start, input_iterator end);
- assign()函数设置成num个val
void assign( Size num, const TYPE &val );
清空队列
- clear()函数删除双向队列中所有元素
删除元素
- erase()函数删除pos位置上的元素,返回值是一个iterator,指向被删除元素的后一个元素
iterator erase( iterator pos );
- erase()函数删除start和end之间的所有元素,返回值是一个iterator,指向被删除元素的后一个元素
iterator erase( iterator start, iterator end );
插入元素
- insert()在pos前插入num个val值,该函数返回一个迭代器,该迭代器指向新插入的元素中的第一个
iterator insert( iterator pos, size_type num, const TYPE &val );
- insert()插入从start到end范围内的元素到pos前面
void insert( iterator pos, input_iterator start, input_iterator end );
交换队列
- swap()函数交换target和现双向队列中元素
void swap( deque &target );
set
set的简介
set就是集合,STL的set用二叉树实现,集合中的每个元素只出现一次(参照数学中集合的互斥性),并且是排好序的(默认按键值升序排列)
常用操作
set<int> q; //以int型为例 默认按键值升序
set<int,greater<int>> p; //降序排列
int x;
q.insert(x); //将x插入q中
q.erase(x); //删除q中的x元素,返回0或1,0表示set中不存在x
q.clear(); //清空q
q.empty(); //判断q是否为空,若是返回1,否则返回0
q.size(); //返回q中元素的个数
q.find(x); //在q中查找x,返回x的迭代器,若x不存在,则返回指向q尾部的迭代器即 q.end()
q.lower_bound(x); //返回一个迭代器,指向第一个键值不小于x的元素
q.upper_bound(x); //返回一个迭代器,指向第一个键值大于x的元素
q.rend(); //返回第一个元素的的前一个元素迭代器
q.begin(); //返回指向q中第一个元素的迭代器
q.end(); //返回指向q最后一个元素下一个位置的迭代器
q.rbegin(); //返回最后一个元素
map
map简介
map是STL的一个关联容器,以键值对存储的数据,其类型可以自己定义,每个关键字在map中只能出现一次,关键字不能修改,值可以修改;map同set、multiset、multimap(与map的差别仅在于multimap允许一个键对应多个值)内部数据结构都是红黑树,而java中的hashmap是以hash table实现的。
map<string,int> my_map;
也可以使用
typedef map<string,int> My_Map;
My_Map my_map;
常用方法
函数名 | 功能 |
---|---|
my_map.insert() | 或按照数组直接赋值 插入 |
my_map.find() | 擦查找一个元素 |
my_map.clear() | 清空 |
my_map.erase() | 删除一个元素 |
my_map.size() | map的长度大小 |
my_map.begin() | 返回指向map头部的迭代器 |
my_map.end() | 返回指向map末尾的迭代器 |
my_map.rbegin() | 返回一个指向map尾部的逆向迭代器 |
my_map.rend() | 返回一个指向map头部的逆向迭代器 |
my_map.empty() | map为空时返回true |
swap() | 交换两个map,两个map中所有元素都交换 |
map插入数据的几种方法
第一种:用insert函数插入pair数据:
map<int,string> my_map;
my_map.insert(pair<int,string>(1,"first"));
my_map.insert(pair<int,string>(2,"second"));
第二种:用insert函数插入value_type数据:
map<int,string> my_map;
my_map.insert(map<int,string>::value_type(1,"first"));
my_map.insert(map<int,string>::value_type(2,"second"));
map<int,string>::iterator it; //迭代器遍历
for(it=my_map.begin();it!=my_map.end();it++)
cout<<it->first<<it->second<<endl;
第三种:用数组的方式直接赋值:
map<int,string> my_map;
my_map[1]="first";
my_map[2]="second";
map<int,string>::iterator it;
for(it=my_map.begin();it!=my_map.end();it++)
cout<<it->first<<it->second<<endl;
查找元素(判定这个关键字是否在map中出现)
第一种:用count函数来判断关键字是否出现,其缺点是无法定位元素出现的位置。由于map一对一的映射关系,count函数的返回值要么是0,要么是1。
map<string,int> my_map;
my_map["first"]=1;
cout<<my_map.count("first")<<endl; //输出1;
第二种:用find函数来定位元素出现的位置,它返回一个迭代器,当数据出现时,返回的是数据所在位置的迭代器;若map中没有要查找的数据,返回的迭代器等于end函数返回的迭代器。
#include <map>
#include <string>
#include <iostream>
using namespace std;
int main()
{
map<int, string> my_map;
my_map.insert(pair<int, string>(1, "student_one"));
my_map.insert(pair<int, string>(2, "student_two"));
my_map.insert(pair<int, string>(3, "student_three"));
map<int, string>::iterator it;
it = my_map.find(1);
if(it != my_map.end())
cout<<"Find, the value is "<<it->second<<endl;
else
cout<<"Do not Find"<<endl;
return 0;
}
//通过map对象的方法获取的iterator数据类型是一个std::pair对象,包括两个数据iterator->first和iterator->second,分别代表关键字和value值。
删除元素
#include <map>
#include <string>
#include <iostream>
using namespace std;
int main()
{
map<int, string> my_map;
my_map.insert(pair<int, string>(1, "one"));
my_map.insert(pair<int, string>(2, "two"));
my_map.insert(pair<int, string>(3, "three"));
//如果你要演示输出效果,请选择以下的一种,你看到的效果会比较好
//如果要删除1,用迭代器删除
map<int, string>::iterator it;
it = my_map.find(1);
my_map.erase(it); //如果要删除1,用关键字删除
int n = my_map.erase(1); //如果删除了会返回1,否则返回0
//用迭代器,成片的删除
//一下代码把整个map清空
my_map.erase( my_map.begin(), my_map.end() );
//成片删除要注意的是,也是STL的特性,删除区间是一个前闭后开的集合
//自个加上遍历代码,打印输出吧
return 0;
}
排序,按value排序
map中元素是自动按key升序排序(从小到大)的;按照value排序时,想直接使用sort函数是做不到的,sort函数只支持数组、vector、list、queue等的排序,无法对map排序,那么就需要把map放在vector中,再对vector进行排序。
#include <iostream>
#include <string>
#include <map>
#include <algorithm>
#include <vector>
using namespace std;
bool cmp(pair<string,int> a, pair<string,int> b) {
return a.second < b.second;
}
int main()
{
map<string, int> ma;
ma["Alice"] = 86;
ma["Bob"] = 78;
ma["Zip"] = 92;
ma["Stdevn"] = 88;
vector< pair<string,int> > vec(ma.begin(),ma.end());
//或者:
//vector< pair<string,int> > vec;
//for(map<string,int>::iterator it = ma.begin(); it != ma.end(); it++)
// vec.push_back( pair<string,int>(it->first,it->second) );
sort(vec.begin(),vec.end(),cmp);
for (vector< pair<string,int> >::iterator it = vec.begin(); it != vec.end(); ++it)
{
cout << it->first << " " << it->second << endl;
}
return 0;
}
espace std;
bool cmp(pair<string,int> a, pair<string,int> b) {
return a.second < b.second;
}
int main()
{
map<string, int> ma;
ma["Alice"] = 86;
ma["Bob"] = 78;
ma["Zip"] = 92;
ma["Stdevn"] = 88;
vector< pair<string,int> > vec(ma.begin(),ma.end());
//或者:
//vector< pair<string,int> > vec;
//for(map<string,int>::iterator it = ma.begin(); it != ma.end(); it++)
// vec.push_back( pair<string,int>(it->first,it->second) );
sort(vec.begin(),vec.end(),cmp);
for (vector< pair<string,int> >::iterator it = vec.begin(); it != vec.end(); ++it)
{
cout << it->first << " " << it->second << endl;
}
return 0;
}