C++标准模板库(STL)之Set/List/Map/Priority_Queue/Queue/Stack/String/Vector
一、Set的用法
Set:集合,一个内部自动有序而且不重复元素的容器。使用set,要加头文件#include<set>和using namespace std;
1.1、Set的定义
set<typename> name;set<int> name;set<double> name;set<char> name;set<Node> name;//Node是结构体类型set<typename> Arrayname[arraySize];//set<int> a[100];a[0]~a[99]的每一个都是一个set容器
/*定义和写法和vector基本一样,同样typename可以是任何基本类型,结构体,STL容器类型。
同样,typename是容器的时候,>>后要加空格,避免编译器当成位运算出错。*/
1.2、set容器内元素的访问
set只能通过迭代器iterator访问
set<typename>::iterator it;//typename对应定义set时的类型。set<int>::iterator it;
因为除了vector和string之外的STL的容器都不支持以下标的方式访问
。
#include<stdio.h>
#include<set>using namespace std;int main()
set<int> st;
for(int i=0;i<5;i++)
st.insert(i);
for(set<int>::iterator it=st.begin();it!=st.end();it++)
printf("%d ",*it);
return 0;
set内的元素,自动递增排序,并且去重。
1.3、set常用函数
1.3.1、insert()函数
insert(x):将x插入set容器中,并且自动递增排序和去重。时间复杂度为O(logN),N为元素个数
1.3.2、find()函数
find(value):查找值为value的元素,返回它的迭代器。时间复杂度为O(logN),N为元素个数
1.3.3、erase()函数
erase(x):删除单个元素,时间复杂度为O(logN)
erase(a,b);删除左闭右开区间内[a,b)的元素,时间复杂度为O(b-a)
1.3.4、size()函数
size():用来获得set内元素的个数,时间复杂度为O(1)
1.3.5、clear()函数
clear():用来清空set所有元素,时间复杂度为O(N)
#include<stdio.h>
#include<set>using namespace std;int main()
set<int> st;
st.insert(2);
st.insert(5);
st.insert(1);
st.insert(2);
st.inert(4);
st.insert(3);
int len=st.size();//3
for(set<int>::iterator it=st.begin();it!=st.end();it++)
printf("%d ",*it);//1,2,3,4,5 }
st.erase(st.find(2));//利用find()函数先找到2,然后erase删除它
st.erase(3);//删除set中值为3的元素,时间复杂度为O(logN)
set<int>::iterator it=st.find(4);
st.erase(it,st.end());//删除元素2到set末尾之间的数,也就是4,5 st.clear();
int len_clear=st.size();//0
return 0;
1.3、set的用途
set重要的作用:自动去重,升序排序。
二、C++ STL
标准模板库(
list
)
引用头文件#include<list>
list类本身是一个类模板
list链表中的迭代器list类模板的一个内部类 这个类实现了链表元素指针的功能是一个线性链表结构,它的数据由若干个节点构成,每一个节点都包括一个信息块(即实际存储的数据)、一个前驱指针和一个后驱指针。它无需分配指定
的内存大小且可以任意伸缩,这是因为它存储在非连续的内存空间中,并且由指5针将有序的元素链接起来。
由于其结构的原因,
list
随机检索的性能非常的不好,因为它不像
vector
那样直接找到元素的地址,而是要从头一个一个的顺序查找
,这样目标元素越靠后,它的检索时间就越长。检索时间与目标元素的位置成正比。虽然随机检索的速度不够快,但是它可以迅速地在任何节点进行插入和删除操作。因为list 的每个节点保存着它在链表中的位置,插入或删除一个元素仅对最多三个元素有所影响,不像vector 会对操作点之后的所有元素的存储地址都有所影响,这一点是vector 不可比拟的。
list 的特点:
(1) 不使用连续的内存空间这样可以随意地进行动态操作;
(2) 可以在内部任何位置快速地插入或删除,当然也可以在两端进行push和pop 。
(3) 不能进行内部的随机访问,即不支持[ ] 操作符和vector.at() ;
Lists将元素按顺序储存在链表中,与向量(vectors)相比,它允许快速的插入和删除,但是随机访问却比较慢.
//list的使用
#define
_CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<list>
using namespace std;
class Student{
public:
int age;
char name[30];
void Print(){
void ProtectA(){
Student s1, s2, s3;
s1.age = 12;
strcpy(s1.name, "小米");
s2.age = 14;
strcpy(s2.name, "小红");
s3.age = 16;
strcpy(s3.name, "小刚");
list<Student *> ldata;
//从后面添加一个元素
ldata.push_back(&s1);
ldata.push_back(&s2);
ldata.push_back(&s3);
//定义迭代器
//list<Student
*>::iterator current = NULL;
//报错:error C2440: “初始化”: 无法从“int”转换为“std::_List_iterator<std::_List_val<std::_List_simple_types<Student
//说明 list<Student
*>::iterator本质上是list<Student *>类的一个内部类
//这个内部类重载了=运算符 构造函数可以接受一个指针
begin()方法返回的是链表头元素的迭代器
list<Student *>::iterator current = ldata.begin();
//
强调
current
是个内部类
但是迭代器的功能相当于链表元素的指针
//
迭代器步长是一个元素类型大小的字节
for (current; current != ldata.end(); current++)
Student *temp = *current;
//迭代器这个内部类重载了*运算符
cout << "学生姓名:" << temp->name << ";学生年龄是:" << temp->age << endl;
void ProtectB(){
Student s1, s2, s3;
s1.age = 12;
strcpy(s1.name, "小米");
s2.age = 14;
strcpy(s2.name, "小红");
s3.age = 16;
strcpy(s3.name, "小刚");
list<Student> ldata;
ldata.push_back(s1);
ldata.push_back(s2);
ldata.push_back(s3);
list<Student>::iterator current = ldata.begin();
for (current; current != ldata.end(); current++)
//Student *temp =
current;
//报错: 2 IntelliSense: 不存在从
"std::_List_iterator<std::_List_val<std::_List_simple_types<Student>>>"
到 "Student *" 的适当转换函数 g:\test\SolutionC3\C001\tec01.cpp
//简单来说没有实现=操作符重载 所以无法赋值
//2个操作数 左操作数类型是 Student * 用户没写 c++编译无法编译通过
cout << "学生姓名:" << current->name << ";学生年龄是:" << current->age << endl;
//迭代器内部类重载了->操作符
void main(){
ProtectA();
system("pause");
三、
C++标准模板库(STL)之
Map
3.0 Map的常用用法
map:映射。可以将任何基本类型,结构体,STL容器映射到任何基本类型包括容器。
使用map,需要加map的头文件,#include<map>和using namespace std;
3.1 map的定义
map<typename1,typename2> mp;
map<string,int> mp;//如果是字符串到int的映射,必须使用string不能使用char数组。
3.2、map容器元素的访问
map的两种访问方式:下标访问、迭代器访问
3.2.1、下标访问
和访问数组一样。map中键是唯一的
3.2.2、迭代器访问
map<typename1,typename2>::iterator it;
#include<stdio.h>
#include<map>
using namespace std;
int main()
map<char,int> mp;
mp['a']=5;
mp['b']=10;
mp['d']=40;
mp['c']=20;
mp['c']=30;//20被覆盖
printf("%d\n",mp['c']);
for(map<char,int>::iterator it=mp.begin();it!=mp.end();it++)
printf("%c %d\n",it->first,it->second);//it->first:当前映射的键,it->second:当前映射的值 }
//a 5
//b 10
//c 30
//d 40
//map会以键从小到大的顺序自动排序。map内部是使用红黑树实现的,set内部也是。
//建立映射的时候,会自动实现从小到大的排序功能
return 0;
3.3、map常用函数
3.3.1、find()
find(key):返回键为key的映射,时间复杂度为O(logN)
3.3.2、erase()
删除单个元素:
mp.erase(it):it为需要删除的元素的迭代器。时间复杂度为O(1)
mp.erase(key):key为删除元素的键,时间复杂度为O(logN)
删除区间内的元素,左闭右开[start,end)
3.3.3、size()
3.3.4、clear()
用来清空map,复杂度为O(N)
#include<stdio.h>
#include<map>
using namespace std;
int main()
map<char,int> mp;
mp['a']=5;
mp['b']=10;
mp['d']=40;
mp['c']=20;
mp['c']=30;//20被覆盖
printf("%d\n",mp['c']);//30
mp.erase('b');//删除键为b的映射,也就是b 10
for(map<char,int>::iterator it=mp.begin();it!=mp.end();it++)
printf("%c %d\n",it->first,it->second);
//a 5
//c 30
//d 40
map<char,int>::iterator it=mp.find("a");
mp.erase(it);//删除a 5
for(map<char,int>::iterator it=mp.begin();it!=mp.end();it++)
printf("%c %d\n",it->first,it->second);
//c 30
//d 40
mp['e']=50;
mp['f']=60;
map<char,int>::iterator it=mp.find("d");
mp.erase(it,mp.end());//删除区间, d 40 e 50
return 0;
3.4、map的常见用途
a、建立字符或者字符串与整数之间的映射的时候,使用map
b、判断大整数或者其他类型数据是否存在的时候,map可以当bool数组用
c、字符串和字符串的映射
四、C++标准模板库(STL)之Priority_Queue
4.0. Priority_Queue的常用用法
priority_queue:优先队列,底层是使用堆来实现的。优先队列中,队首元素一定是当前队列中优先级最高的哪一个。
a (优先级3),b(优先级4),c(优先级1),出队顺序是:b(4)-》a(3)-》c(1)
4.1 priority_queue的定义
使用优先队列,要加头文件#include<queue>和using namespace std;
priority_queue<typename> pq;
4.2、priority_queue容器元素访问
优先队列和队列
queu
不一样,没有
front()
和
back()
函数,只能通过
top()
函数访问队首元素(堆顶元素),优先级最高的元素。
#include<stdio.h>
#include<queue>
using namespace std;
int main()
priority_queue<int> q;
q.push(3);
q.push(4);
q.push(1);
printf("%d\n",q.top());//输出结果为4
return 0;
4.3、priority_queue的常用函数
4.3.1、push()
push(x):将x入队,时间复杂度为O(logN),N为优先队列中元素个数。
4.3.2、top()
top():获得堆顶元素,时间复杂度为O(1)
4.3.3、pop()
pop():让堆顶元素出队,时间复杂度为O(logN)
4.3.4、empty()
empty():检测优先队列是否为空,返回bool值,true为空,false非空
4.3.5、size()
size():返回优先队列中的元素个数。
4.4、priority_queue内元素优先级的设置
4.4.1、基本数据类型的优先级设置
基本数据类型:int,double,char等。
priority_queue<int> pq;
priority_queue<int,vector<int>,less<int>> pq;/*
vector<int>:承载底层数据结构堆Heap的容器
如果第一个参数是double,那么第二个也对应是double
less<int>:是对第一个参数的比较类,less<int>表示的数组大的优先级越大。
greater<int>:表示数字小的优先级越大
priority_queue<int,vector<int>,greater<int>> pq;
//优先队列总是把最小的元素放在队首。
priority_queueK<int,vector<int>,less<int>> pq;
//优先队列总是把最大的元素放在队首。
#include<stdio.h>
#include<queue>
using namespace std;
int main()
//用greater优先队列总是把最小的排在堆顶
priority_queue<int,vector<int>,greater<int>> q;
q.push(3);
q.push(4);
q.push(1);
printf("%d\n",q.top());//输出结果为1
//用less优先队列总是把最大的排在堆顶
priority_queue<int,vector<int>,less<int>> pq;
pq.push(3);
pq.push(5);
pq.push(2);
printf("%d\n",pq.top());//输出结果为5
return 0;
4.4.2、结构体的优先级设置
#include<stdio.h>
#include<queue>
using namespace std;struct fruit
string name;
int price;
friend bool operator < (fruit f1,fruit f2)
return f1.price<f2.price;
}f1,f2,f3;
int main()
priority_queue<fruit> q;
f1.name="apple";
f1.price=3;
f2.name="perl";
f2.name=4;
f3.name="banana";
f3.price=1;
q.push(f1);
q.push(f2);
q.push(f3);
cout<<q.top.name<<" "<<q.top().prince<<endl;//banana 1
return 0;
4.5、priority_queue的常见用途
可以解决贪心问题,也可以定义Dijkstra算法进行优化
使用top()函数,必须使用empty()判断优先队列是否为空。
五、C++ STL--queue 的使用方法
5.0 queue
q
ueue 模板类的定义在<queue>头文件中。
定义queue 对象的示例代码如下:
queue<int> q1;
queue<double> q2;
queue 的基本操作有:
入队,如例:q.push(x); 将x 接到队列的末端。
出队,如例:q.pop(); 弹出队列的第一个元素,注意,并不会返回被弹出元素的值。
访问队首元素,如例:q.front(),即最早被压入队列的元素。
访问队尾元素,如例:q.back(),即最后被压入队列的元素。
判断队列空,如例:q.empty(),当队列空时,返回true。
访问队列中的元素个数,如例:q.size()
#include <cstdlib>
#include <iostream>
#include <queue>
using namespace std;
int main()
int e,n,m;
queue<int> q1;
for(int i=0;i<10;i++)
q1.push(i);
if(!q1.empty())
cout<<"dui lie bu kong\n";
n=q1.size();
cout<<n<<endl;
m=q1.back();
cout<<m<<endl;
for(int j=0;j<n;j++)
e=q1.front();
cout<<e<<" ";
q1.pop();
cout<<endl;
if(q1.empty())
cout<<"dui lie bu kong\n";
system("PAUSE");
return 0;
六、C++标准模板库(STL)之Stack
6.0、Stack的常用用法
stack:栈,一个后进先出的容器。
6.1、stack的定义
加上头文件#include<stack>和using namespace std;
stack<typename> sk;
6.2、stack容器元素的访问
是一种操作受限制的线性表,只能通过
top()
来访问栈顶元素。
#include<stdio.h>
#include<stack>
using namespace std;int main()
stack<int> sk;
for(int i=1;i<=5;i++)
sk.push(i);//push(i)用来把i压入栈,入栈顺序1,2,3,4,5 }
printf("%d\n",sk.top());
return 0;
6.3、stack常用函数
6.3.1、push()
push(x):将x入栈,时间复杂度为O(1)
6.3.2、top()
top():获取栈顶元素,时间复杂度为O(1)
6.3.3、pop()
pop():出栈顶元素。
6.3.4、empty()
empty():判断栈是否为空
6.3.5、size()
size():获得栈元素个数
#include<stdio.h>
#include<stack>
using namespace std;int main()
stack<int> sk;
if(sk.empty()==true)printf("Empty\n");//判断栈空
for(int i=1;i<=5;i++)
sk.push(i);//push(i)用来把i压入栈,入栈顺序1,2,3,4,5 }
printf("%d %d\n",sk.top(),sk.size());//5 5
return 0;
6.4、stack的用途
用来模拟实现递归。程序的栈内存空间很小,如果用普通递归,可能会导致程序运行崩溃。
用栈模拟递归可以避免这种问题。
C++标准模板库(STL)之String
七、C++标准模板库(STL)之String
7.0 String的常用用法
在C语言中,使用字符数组char str[]来存字符串,字符数组操作比较麻烦,而且容易有'\0'的问题,C++在STL中加入string类型,对字符串常用的需求功能进行封装。
使用string,必须要加头文件#include<string>和using namespace std;
注意:#include<string>和#include<string.h>的区别,#inlcude<string.h>是包含了字符串常用的函数,比如strcat,strcmp。#include<string.h>和#include<cstring>等价。
7.1、string的定义
定义string的方式和基本类型定义相同。
string str;string str="abcd";
7.2、string中的内容访问
和vector一样,有两种方式:下标访问,迭代器访问
7.2.1、下标访问
可以如同字符数组一样去访问string
7.2.2、迭代器访问
string的迭代器不需要参数,直接定义string::iterator it;
#include<stdio.h>
#include<string>
using namespace std;
int main()
string str="abcd";
for(int i=0;i<str.length;i++)
printf("%c ",str[i]);//a b c d }
//通过迭代器访问string内容
for(string::iterator it=str.begin();it!=str.end();it++)
pritnf("%c ",*it);
return 0;
7.3、string常用函数
7.3.1、+,+=,字符串拼接
7.3.2、==,!=,<,<=,>=,>比较大小
7.3.3、length()/size(),字符串长度
7.3.4、insert()
7.3.5、erase()
7.3.6、clear()
7.3.7、substr()
7.3.8、replace()
#include<stdio.h>
#include<string>
using namespace std;
int main()
string str="abcd";
for(int i=0;i<str.length;i++)
printf("%c ",str[i]);//a b c d }
//通过迭代器访问string内容
for(string::iterator it=str.begin();it!=str.end();it++)
pritnf("%c ",*it);
string str1="xyz";
string str2=str+str1;
cout<<str2<<endl;//abcdxyz
if(str<str1)printf("OK\n");//字符串比较,首先比较长度,长度相同的进行字典序比较。
printf("%d %d\n",str.lenght(),str.size());//4,4//获取字符串的长度,大小
cout<<str.insert(3,str1)<<endl;//往str[3]处插入xyz,输出abcxyzd;
str.insert(str.begin()+3,str.begin(),str.end);
str.substr(0,3);//substr(pos,len),从0开始,长度为3的子串
return 0;
7.3.9、string::npos
string::npos是一个常数,本身值为-1,用来做find函数失配的返回值。
7.3.10、find()
#include<stdio.h>
#include<string>
using namespace std;
int main()
string str="abcd";
string str1="bc";
if(str.find(str1)!=string::npos)
cout<<str.find(str1)<<endl;
if(str.find(str2,2)!=string::npos)
cout<<str.find(str2,2)<<endl;
cout<<"No Find"<<endl;
return 0;
八、C++标准模板库(STL)之Vector
在C中,有很多东西需要自己实现。C++提供了标准模板库(Standard Template Libray,STL),其中封装了很多容器,不需要费力去实现它们的细节而直接调用函数来实现功能。
具体容器链接:
set
,
string
,
map
,
queue
,
priority_queue
,
stack
,
pair
8.0 vector的用法
vector:向量,这里叫“变长数组”,长度根据需要而自动改变的数组。有时会碰到普通数组会超过内存的情况,可以使用vector解决。而且,vector可以用来以邻接表的方式存储图,可以解决当节点数太多,无法使用邻接矩阵,又害怕使用指针实现邻接表的时候,使用很简单。
使用vector,需要添加头文件,#include<vector>,还要头文件下加入using namespace std;
8.1、vector的定义
vector<typename> name;
相当于定义了一个一维数组name[SIZE],只不过size可以根据需要进行变化,比较节省空间,也就是变长数组
typename:任何基本类型,int,char,double,结构体,STL容器vector,set,queue等。
如果typename是STL容器,定义的时候要在>>之后加上空格,如果不加空格,编译器就把它认为是位操作。
vector<int> stu;
vector<double> stu;
vector<char> stu;
vector<Node> stu;//Node是结构体类型
vector<vector<int>> name;
二维数组的定义:一维是一个数组的数组
vector<typename> Arrayname[arraySize]
/*Arrayname[]的每一个元素都是一个vector,可以理解为两个维都是可变长的二维数组*/
写法一:vector<int> vi[100];//一维长度已经固定为arraySize
vi[0]~vi[99]中每一个都是一个vector容器。
写法二:vector<vector<int>> vi//区别:这个两个维度是变长的
8.2、vector容器内元素的访问
vector访问方式:下标访问、迭代器访问。
8.2.1、下标访问
和访问普通数组一样,下标从0~size()-1。
比如定义的:vector<typename> vi,使用vi[index](vi[0],vi[1])。
8.2.2、通过迭代器访问
迭代器(iterator)理解为类似指针的东西。
定义:vector<typename>::iterator it;//it是一个迭代器变量。
#include<stdio.h>
#include<vector>using namespace std;int main()
vector<int> vi;
for(int i=0;i<5;i++)
vi.push_back(i);
vector<int>::iterator it=vi.begin();//vi.begin()是vi的首元素地址,用迭代器变量it指向这个地址
for(int i=0;i<5;i++)
printf("%d\n",*(it+i));//输出vi[i]; }
return 0;
注:vi[i]与*(vi.begin()+i)等价
end()函数:并不是取vi的尾元素地址,而是取尾元素的下一个地址。就相当于左闭右开区间。
#include<stdio.h>
#include<vector>using namespace std;int main()
vector<int> vi;
for(int i=0;i<5;i++)
vi.push_back(i);
vector<int>::iterator it=vi.begin();//vi.begin()是vi的首元素地址,用迭代器变量it指向这个地址
for(int i=0;i<5;i++)
printf("%d\n",*(it+i));//输出vi[i]; }
//使用begin(),end()函数,访问
for(vector<int>::iterator it=vi.begin();it!=vi.end();it++)
printf("%d\n",*it);
return 0;
注:在常用STL容器中,只有vector和string才可以使用vi.begin()+i这种迭代器加整数的写法,因为他们两个看做数组的下标的访问方式。
8.3、vector常用函数
8.3.1、push_back()函数
push_back(x)就是在vector后面添加一个元素x,时间复杂度为O(1)。
8.3.2、pop_back()函数
pop_back(x)就是删除vector的尾元素x,时间复杂度为O(1)。
8.3.3、size()函数
用来获得vector中元素的个数,时间复杂度为O(1)。
8.3.4、clear()函数
用来清空vector所有的元素,时间复杂度为O(N),N为元素总个数。
8.3.5、insert()函数
用insert(it,x)往vector的任意迭代器it初传入一个元素x。时间复杂度为O(N)。
8.3.6、erase()函数
用erase()函数删除单个元素,或者一个区间的元素
#include<stdio.h>
#include<vector>using namespace std;
int main()
vector<int> vi;
for(int i=0;i<5;i++)
vi.push_back(i);//jpush_back()函数应用 }
vi.pop_back(i);//删除vi的尾部元素4
int i=vi.size();//size()返回的unsingned类型
vi.clear();//清空vector所有元素
vi.insert(vi.begin()+2,23);//将23插入vi[2]的位置
vi.erase(vi.begin()+1);//删除单个元素vi[1];
vi.erase(vi.begin()+1,vi.begin()+3);//删除vi[1],vi[2],左闭右开区间
return 0;
8.4、vector常见用途
8.4.1、存储数据
vector本身可以作为数组使用,当元素个数不确定的时候,可以很好地节省空间。
有些时候需要把部分数据输出在同一行,用空格隔开数据。由于数据的个数不知道,
可以使用vector记录所有的需要输出的数据,然后一次性输出。
8.4.2、用邻接表存储图
可以使用vector实现邻接表,避免使用指针的邻接链表。
参考:https://blog.csdn.net/Honeycomb_1/article/details/104429740