目录
语法:容器类型 <容器数据类型> :: iterator 对象 ;
vector < int > :: iterator it ;
经典遍历:for( it = p.begin() ; it != p.end() ; it++ )
一、STL库的说明
C++ STL (Standard Template Library标准模板库) 是通用类模板和算法的集合,它提供给程序员一些标准的数据结构的实现如 queues(队列), lists(链表), 和 stacks(栈)等。
C++ STL 提供给程序员以下三类数据结构的实现:
1、顺序结构 。
C++ Vectors ,C++ Lists ,C++ Double-Ended Queues 。
2、容器适配器。
C++ Stacks ,C++ Queues ,C++ Priority Queues 。
3、联合容器。
C++ Bitsets ,C++ Maps ,C++ Multimaps ,C++ Sets ,C++ Multisets 。
程序员使用复杂数据结构的最困难的部分已经由STL完成。
二、STL迭代器
迭代器就相当于每种容器的专用指针! 每一个容器都有唯一的一个迭代器。
语法:容器类型 <容器数据类型> :: iterator 对象 ;
vector < int > :: iterator it ;
例子:
//整型容器
vector<int> p(2,789); //容器装了2个int型的789
vector<int>::iterator it; //声明迭代器it,类型必须一致
for(it = p.begin();it!=p.end();it++){
cout << *it << endl;
}
经典遍历:for( it = p.begin() ; it != p.end() ; it++ )
逆迭代器 : 操作与迭代器是相反的!! 如:it++ 则指针向前偏移。
rbegin() 函数
语法:
reverse_iterator rbegin();
例子:p.rbegin();
rend() 返回Vector起始的逆迭代器
三、Vectors容器
Vectors 包含着一系列连续存储的元素,其行为和数组类似,特点:数据的操作都是从尾巴开始。
1、构造函数
vector();//默认构造
vector( size_type num, const TYPE &val ); //把num 个 val 放入vector 容器中
vector( const vector &from ); //拷贝构造函数
vector( input_iterator start, input_iterator end ); //利用迭代器初始化区间的值
2、函数接口
TYPE back(); //获取最后一个元素
TYPE front();//获取第一个元素
void clear();//删除所有数据
void pop_back(); //删除最后一个元素
void push_back( const TYPE &val );//插入一个元素
insert 函数插入函数
语法:
iterator insert( iterator it, const TYPE &val );//it 的位置上 插入一个 val
void insert( iterator it, size_type num, const TYPE &val );//it 的位置上插入num个 val
void insert( iterator it, input_iterator start, input_iterator end );
//it 位置上插入 [start , end] 区间的值
iterator erase( iterator it ); //删除迭代器所指向的元素
iterator erase( iterator start, iterator end );//删除迭代器,所指向的区间
使用例子:
#include<iostream>
#include <vector> //添加向量容器的头文件
using namespace std;
//封装删除代码
void del_data(vector<int> &p,int data){
for(auto it=p.begin();it!=p.end();it++){ //auto:自动识别数据类型并转换
if(*it == data){
p.erase(it);
return;
}
}
}
//迭代器遍历
int main()
{
//整型容器
vector<int> p(2,789); //容器装了2个int型的789
vector<int>::iterator it; //声明迭代器it,类型必须一致
for(it = p.begin();it!=p.end();it++){
cout << *it << endl;
}
//向p里面插入三个数据
p.push_back(11);
p.push_back(22);
p.push_back(33);
vector<int>::iterator it2; //声明迭代器it2
it2 = p.end(); //迭代器指向p末尾的下一个地址
cout << *(it2-1) << endl; //获取容器p的末尾数值,打印元素33
p.erase(it2-1); //删掉末尾的元素,剩下元素(789,789,11,22)
it2 = p.begin(); //指向开头元素
p.erase(it2); //删除开头元素,剩下(789,11,22)
cout << "删除后剩下" << endl;
for(it2 = p.begin();it2!=p.end();it2++){ //打印剩下的(789,11,22)
cout << *it2 << endl;
}
//调用封装函数
del_data(p,789);
cout << "调用封装函数删除789" << endl;
for(it2 = p.begin();it2!=p.end();it2++){ //打印剩下的(789,11,22)
cout << *it2 << endl;
}
//字符串容器
vector<string> v1(2,"helloworld2");
vector<string>::iterator it3;
// for(it3=v1.begin();it3!=v1.end();it3++){}
// cout << *it3 << endl;
it3 = v1.begin();
cout << *it3 << endl;
// v1.push_back("good");
}
四、Lists 链表容器
1、构造函数
list<int> first; // 定义一个空链表
list<int> second (4,100); // 往链表中放入4个100
list<int> third (second.begin(),second.end()); // 利用迭代器初始化
list<int> fourth (third); // 拷贝构造函数
支持的运算符
=,==,!=,>=,<=,> ,<
注意:list容器不支持下标操作 [ ]
2、函数接口
void push_back( const TYPE &val ); //尾插法
void push_front( const TYPE &val );//头插法
void pop_back(); //尾插
void pop_front();//头删
iterator erase( iterator loc ); //删除 loc 位置上的数据
iterator insert( iterator pos, const TYPE &val );//在pos的位置插入 val
//直接删除数据
void remove( const TYPE &val );
//链表翻转
void reverse();
//排序
void sort();
void sort( Comp compfunction );
//在pos位置插入lst链表
void splice( iterator pos, list &lst );
//合并链表
void merge( list &lst );
void merge( list &lst, Comp compfunction );
//compfunction 指定合并的算法
bool mycomparison (int first, int second)
{return first<second;}
//demo:
merge(lst,mycomparison);
demo
#include<iostream>
#include<list>
using namespace std;
//设计通用模板,传递任何数据都能打印,返回值要是void型,不然会段错误!!!
template <class T>
void show(T &f0){
for(auto p=f0.begin();p!=f0.end();p++){
cout << *p << endl;
}
}
int main()
{
list<string> t; //创建一个链表容器
t.push_back("你好");
t.push_back("我好");
t.push_front("大家好");
list<string>::iterator lt=t.begin();
lt++;
t.insert(lt,"hello"); //在指定位置插入字符串
lt++;
t.insert(lt,"well"); //在指定位置插入字符串
t.insert(lt,"well2"); //在指定位置插入字符串
// t.erase(lt); //删除迭代器lt上的数据
t.insert(lt,t.begin(),t.end()); //插入开始到结束的值(可自定义区间,用t指向)
t.erase(t.begin(),t.end()); //删除开始到结束的区间(可自定义区间,用t指向)
t.push_front("嗯");
t.pop_front(); //头删法
t.reverse(); //链表翻转.niu
t.sort(); //链表排序
t.remove("hello"); //直接删除数据
t.clear(); //清空所有的值
show(t);
}
五、配置器
作用:作类型的转换。 例如: 电压 220V ->(电源适配器,转换) 手机的充电电压5V-1A 。
// list::get_allocator
#include <iostream>
#include <list>
using namespace std;
int main ()
{
//链表容器
list<int> mylist;
int * p;
unsigned int i;
//利用适配器提取,链表的5个空间
p=mylist.get_allocator().allocate(5);
// assign some values to array
for (i=0; i<5; i++) p[i]=i;
cout << "The allocated array contains:";
for (i=0; i<5; i++) cout << " " << p[i];
cout << endl;
//利用适配器提,释放刚刚提取的 5 个空间
mylist.get_allocator().deallocate(p,5);
return 0;
}
六、双向队列(deque)
双向队列:与vectors向量一样,但是支持头尾操作(双向的可++和--)。
构造函数:其实就是重载。
deque();
deque( size_type size );
deque( size_type num, const TYPE &val );
deque( const deque &from );
deque( input_iterator start, input_iterator end );
七、栈(stacks)
C++ Stack(堆栈) 是一个容器类的改编,为程序员提供了堆栈的全部功能。
函数语法:
void pop();
pop() 函数移除堆栈中最顶层元素。
void push( const TYPE &val );
push() 函数将 val 值压栈,使其成为栈顶的第一个元素
size_type size();
size() 函数返当前堆栈中的元素数目。
TYPE &top();
top() 函数返回对栈顶元素的引用.
例子:
#include <iostream>
using namespace std;
//添加栈的头文件
#include <stack>
int main()
{
stack<int> s;
//入栈
s.push(10);
s.push(20);
s.push(30);
s.push(40);
//出栈
while (!s.empty())
{
cout << s.top() << endl; //访问栈的元素
s.pop(); //出元素
}
}
八、队列
C++队列是一种容器适配器,它给予程序员一种先进先出(FIFO)的数据结构。
#include<iostream>
//添加队列头文件
#include<queue>
using namespace std;
int main(int argc, char const *argv[])
{
//定义一个队列
queue<int> l1;
//入队
for(int i = 10; i < 80; i+=10)
l1.push(i);
//判断队列是否为空
while(!l1.empty())
{
cout << l1.front() << endl; //访问队头元素
l1.pop(); //出队
}
return 0;
}
九、Priority Queues(优先队列)
C++优先队列类似队列,特点:插入的数据会自动排序。
栈和队列和优先队列的例子:
#include<iostream>
#include<queue>
#include<stack>
using namespace std;
int main()
{
cout << "队列:先进先出" << endl;
queue<int> q;
q.push(11); //入队
q.push(21);
q.push(3);
q.push(7);
while(!q.empty()){
cout << q.front() << endl; //打印队头元素
q.pop(); //出队
}
cout << "****************" << endl;
cout << "栈:先进后出" << endl;
stack<int> s;
s.push(233); //入栈
s.push(111);
s.push(444);
s.push(777);
while(!s.empty()){
cout << s.top() << endl; //打印栈顶元素
s.pop(); //出栈
}
cout << "****************" << endl;
cout << "优先队列:由大到小排序" << endl; //可以自动排序,存储在堆空间
priority_queue<int> pq; //默认由大到小排序
pq.push(456);
pq.push(123);
pq.push(888);
while(!pq.empty()){
cout << pq.top() << endl; //打印队头元素
pq.pop(); //出队
}
}
十、bitset位操作容器
C++ Bitsets给程序员提供一种位集合的数据结构。Bitsets使用许多二元操作符,比如逻辑和,或等。
构造函数:
bitset(); //默认构造函数
bitset( unsigned long val ); //把val转换为二进制数,存储到bitset中
函数接口和例子:将131转换成123
#include<iostream>
#include<bitset>
using namespace std;
int main()
{
bitset<8> bs((long) 131); //通过位操作修改为123
for(int i=(int)bs.size()-1; i>=0; i--){ //0-7,从最高位开始打印,最低位是0
cout << bs[i] ; //输出 1000 0011
}
cout<<endl<< "--------------"<<endl;
//将 131 转换成 123 , 即,1000 0011(131) -> 0111 1011(123)
//取反,全部取反,如果指定位,就从右到左第几位取反,最开始是0
bs.flip(3); //第4位取反,即0111 1011
//清0,全部清0,如果指定位,就从右往左数第几位清0
bs.reset(7); //第8位清0
//置1,全部置1,如果指定位,就从右往左数第几位置1
bs.set(4);
bs.set(5);
bs.set(6);
// for(int i=(int)bs.size()-1; i>=0; i--)
// cout << bs[i] ; //输出 0111 1011
cout << bs.to_string(); //直接字符串输出 0111 1011
cout << endl;
//转换为无符号整形输出
cout << bs.to_ulong() << endl;
}
运算符:
语法:
!=, ==, &=, ^=, |=, ~, <<=, >>=, []
这些操作符都可以和bitsets一起工作。它们被这样定义:
!= 返回真如果两个bitset不相等。
== 返回真如果两个bitset相等。
&= 完成两个bitset间的与运算。
^= 完成两个bitset间的异或运算。
|= 完成两个
~ 反置bitset (和调用 flip()类似)
<<= 把bitset向左移动
>>= 把bitset向右移动
[x] 返回第x个位的引用
十一、set容器
set:集合是一种关联容器,它存储唯一的元素,其中元素本身就是键key。其实内部的数据结构是二叉搜索树 BST。
特点:不允许插入相同的数据,快速查找!。
构造函数 ( 重载 ):
set<int> first; // 默认构造
set<int> third (second); // 拷贝构造函数
set<int> fourth (second.begin(), second.end()); // 利用迭代器赋值
set<int,classcomp> fifth; //默认构造,并设置比较函数
//比较方法的设计
struct classcomp {
bool operator() (const int& lhs, const int& rhs) const
{return lhs<rhs;}
};
函数接口:
//插入数据
pair insert( const TYPE &val );
返回值:是一个pair 对组,数据是成对存在。
//直接删除
size_type erase( const key_type &key );
//直接查找
iterator find( const key_type &key );
MultiSets:多元集合(MultiSets)和集合(Sets)相像,支持重复对象!。
set和Multisets例子(不支持重复和支持重复数据):
#include<iostream>
#include<set>
using namespace std;
int main()
{
set<int> s; //set联合容器,可自动排序,由小到大
set<int>::iterator it;
s.insert(11); //插入
s.insert(15);
s.insert(21);
s.insert(566);
s.insert(1);
s.insert(5);
// s.insert(5); //不支持重复对象
for(it=s.begin();it!=s.end();it++){
cout << *it << " " ; //遍历
}
cout << endl;
it = s.find(15); //查找数据
cout << "find:" <<*it << endl;
s.erase(11); //删除数据
cout << "erase:11" << endl;
for(it=s.begin();it!=s.end();it++){
cout << *it << " " ; //遍历
}
cout << endl;
//MultiSets:多元集合(MultiSets)和集合(Sets)相似,支持重复对象。
multiset<string> m;
multiset<string>::iterator it2;
m.insert("33");
m.insert("32");
m.insert("32");
for(it2=m.begin();it2!=m.end();it2++){
cout << *it2 << endl;
}
}
十二、map映射容器
C++ Maps是一种关联式容器,包含“关键字/值”对,利用一个key 映射一个 value ,map 容器中所有数据都是 pair ,不允许出现重复的KEY数据!
pair对组:
#include <iostream>
using namespace std;
int main()
{
//定义一个对组,姓名+学号
pair<string,int> a;
a.first = "小明"; //第一项数据 = 小明
a.second = 123; //第二项数据 = 123
cout << a.first << endl;
cout << a.second << endl;
}
函数接口:
//在pos 位置插入
iterator insert( iterator pos, const pair<KEY_TYPE,VALUE_TYPE> &val );
//插入区间
void insert( input_iterator start, input_iterator end );
//插入一个 pair
pair<iterator, bool> insert( const pair<KEY_TYPE,VALUE_TYPE> &val );
//通过 key 快删除数据
size_type erase( const KEY_TYPE &key );
//通过key 快速查找 value
iterator find( const KEY_TYPE &key );
例子:
// C++ Maps是一种关联式容器,包含“关键字/值”对,利用一个key 映射一个 value
// map 容器中所有数据都是pair ,不允许出现重复的**KEY**数据!
#include<iostream>
#include<map>
using namespace std;
int main()
{
//定义一个对组pair,姓名+学号
pair<string,int> p; //第一个是字符串型,第二个是int型
p.first = "小花"; //first代表第一项数据key键 = 小花
p.second = 10086; //second代表第二项数据value值 = 10086
cout << p.first ; //打印
cout << p.second << endl;
//map容器储存对组的三种方法
//定义一个map容器存放对组
map<string,int> fir;
//1、定义一个对组
pair<string,int> p1("小东",10088);
//插入数据
fir.insert(p1);
//2、生成一个对组
fir.insert(make_pair<string,int>("小妹",10011));
//3、创建一个对组,强烈推荐,方便实用
fir["小芳"] = 10000;
//[key] = value;
//键值是唯一的,但值可以多个。
// fir["小芳"] = 10001; //同名键值会覆盖前面的键值和值。
fir["小贝"] = 10000; //相同的值不会覆盖前面的键值。
//遍历
for(auto it2=fir.begin();it2!=fir.end();it2++){
cout << "key:" << it2->first << " value:" << it2->second << endl;
}
}
C++ Multimaps和maps很相似,但是MultiMaps允许重复的元素。
十三、STL 存储自定义数据类型
注意: 需要重载定义了类中的运算符操作 。
//利用STL 库封装一个背包类,管理材料,药水,和装备。
#include<iostream>
#include<list>
#include<string.h>
using namespace std;
class Back{
private:
string mat; //材料
string lq_med; //药水
string equip; //装备
public:
Back(string mat,string lq_med,string equip):mat(mat),lq_med(lq_med),equip(equip){ }
void show(){
cout << "材料:" << this->mat << endl;
cout << "药水:" << this->lq_med << endl;
cout << "装备:" << this->equip << endl;
}
friend ostream &operator<<(ostream &o,Back B); //重载运算符
};
//1.创建对象链表
//2.插入有参构造函数(可顺便初始化)
//3.重载<<运算符
//4.利用迭代器遍历
//重载<<,其实就是显示接口,在里面打印,参数传入一个o,一个类对象,只不过返回一个o作为<<运算符。
ostream &operator<<(ostream &o,Back B){
B.show(); //调用接口函数显示
return o; //返回<<运算符
}
int main()
{
list<Back> B; //创建对象类链表
B.push_back(Back("红宝石","红药水","无尽之刃"));
B.push_back(Back("蓝宝石","蓝药水","泣血之刃"));
B.push_back(Back("黄宝石","黄药水","暴风之刃"));
// list<Back>::iterator By;
//遍历
for (auto By = B.begin(); By!=B.end(); By++){
cout << *By << endl;
}
}
总结:
1、STL库很多,set,list,优先队列都是可以自动排序的,vector,deque支持下标操作,set和list是等不支持下标操作的,要会使用迭代器进行操作。
2、map支持两个类型,第一个是key,第二个是value,可以存放类。
3、auto是自动类型转换,方便了操作。