STL——标准模板库

1.STL--standard template library标准模板库
类模板构成容器  函数模板构成算法

1)迭代器(it):++,*,->,==,!=
     输入迭代器:可读*it的值,但不一定能修改(设置)*it的值
     输出迭代器:可以设置*it的值,但不一定能读取*it的值
     前向迭代器:可以读取也可以设置*it的值
     双向迭代器:支持--
     随机迭代器:几乎跟指针一样,支持--,+n,-n,比较大小,[下标]


2)适配器:是使一事物的行为类似于另一事物的行为的一种机制,包括容器适配器,迭代器适配器和函数适配器。

3)函数模板(通用算法algorithm)--->关于算法的  查找 排序
     内容太多,通用算法依赖迭代器实现,可以从头到尾遍历整个容器的方法
   for_each()  find find_if  count count_if sort copy
   iterator find(pos_beg, pos_end, data)
   iterator find_if(pos_beg, pos_end, cond), bool cond(element)

   int count(...), int count_if(...)

01sort.cpp

#include <string>
#include <algorithm>  //sort排序算法需要的头文件

class Person
{
    string name;
    int age;
public:
    Person(const char* name, int age):name(name),age(age){}
    friend ostream&operator<<(ostream&o,const Person&p)
    {
        return o<<p.name<<':'<<p.age;
    }
    friend bool operator<(const Person& a,const Person& b)
    {
        return a.age<b.age;
    }
};

template<typename T>
void print(T b, T e)
{
    while(b!=e)
        cout << *b++ << ' ';
    cout << endl;
}


int main()
{
    int a[6]={8,1,6,3,2,5};
    double b[4]={5.5,3.3,6.6,2.2};
    string c[5]={"nice","to","see","you","all"};
    Person d[3]= {Person("芙蓉",18),Person("杨强",20),Person("薇薇",16)};
    sort(a,a+6);sort(b,b+4);sort(c,c+5);sort(d,d+3);
    print(a,a+6);print(b,b+4);print(c,c+5);print(d,d+3);  //半开区间 [)含头不含尾

    return 0;
}



4)类模板(容器containter)---->关于数据结构  数组 链表 栈 队列 二叉树
       a.标准容器:序列(顺序)式容器(vector是个能够存放任意类型的动态数组,能够增加和压缩数据;deque适合首尾删除增加;list链表)
           关联式容器(set不允许重复;multiset允许重复;map不允许重复;multimap允许重复)
           迭代器(标准容器类都有一个内部类iterator,支持* -> ++ == !=),用来访问容器里的内容
            插入迭代器,iostream迭代器,反向,const迭代器,
              五种迭代器:输入,输出,前向,双向,随机访问迭代器
            迭代器是封装成类的指针,数组里面,指针是最原始的迭代器
            每种容器都自己负责封装迭代器类

       b.容器适配器(特殊容器):栈 队列 优先队列

       c.函数对象:(仿函数)对象能像函数一样使用,比如重载()运算符

       d.内存分配器allocator




标准容器(类模板)共性://特殊容器不支持下面操作
   构造函数(包括无参构造,拷贝构造,区间构造(两个迭代器表示的两个位置))
   析构函数

   迭代器相关函数:

           iterator,reverse_iterator,const_iterator,const_reverse_iterator

           .begin()正向iterator,返回指向第一个元素位置的迭代器

           .end()返回指向超越最后一个位置的迭代器
           .rbegin()反向reverse_iterator,反向迭代器

           .rend()

   标准都支持 * -> == ++ -- = !=
   插入:.insert(pos,element)  其中pos是个表示位置的迭代器
   删除:.erase(pos), .erase(pos_beg,pos_end)
   清除:.clear() 清除容器里所以的数据
   大小:.size()  .max_size()
   交换:.swap(c2) (成员函数) .swap(c1,c2)(通用算法也就是函数)

   运算:= > < >= <= == !=

02container.cpp

#include <iostream>
using namespace std;
#include <vector>
#include <algorithm>
#include "print.h"
int main()
{
	int a[5]={33,22,11,55,44};
	vector<int> vi(a,a+5);
	cout << vi.size() << endl;
	sort(vi.begin(), vi.end());//只能是数组、vector和deque
	vector<int>::iterator b = vi.begin();
	while(b!=vi.end())
		cout << *b++ << ' ';
	cout << endl;
	for(int i=0; i<5; i++)
		cout << a[i] << ',';
	cout << endl;
	print(vi.begin(), vi.end());
	print(a, a+5);
	print(vi.rbegin(), vi.rend());
	b = vi.begin();
	vi.insert(++++b,66);
	vi.insert(vi.begin(), 77);
	vi.insert(vi.end(),88);
	print(vi.begin(), vi.end());
	cout << vi.size() << '/' << vi.max_size() << endl;
	vi.erase(------vi.end());
	print(vi.begin(), vi.end());
	vi.erase(++++vi.begin(),--vi.end());
	print(vi.begin(), vi.end());
	vector<int> v2(a,a+5);
	print(v2.begin(), v2.end());
	cout << "==================" << endl;
	vi.swap(v2);
	print(vi.begin(), vi.end());
	print(v2.begin(), v2.end());
	cout << "==================" << endl;
	swap(vi,v2);
	print(vi.begin(), vi.end());
	print(v2.begin(), v2.end());
	cout << "==================" << endl;
	vector<int> t=vi;
	vi = v2;
	v2 = t;
	print(vi.begin(), vi.end());
	print(v2.begin(), v2.end());
	vi.clear();
	cout << vi.size() << endl;
	print(vi.begin(), vi.end());
	vector<int> x;
	cout << "vector当前容量:" << x.capacity() << endl;
}

print.h

#ifndef PRINT_H
#define PRINT_H 1
//输出一个指定区间中的所有数据(含头不含尾)
template<typename T>
void print(T b, T e, char c=' ')
{
	while(b!=e)
		cout << *b++ << c;
	cout << endl;
}
#endif


————————————————————————————————————————
序列式容器共性vector deque list:
  构造函数:增加了指定元素个数和初始值(初始值默认是0)
  插入:.insert(pos,n,element)  .insert(pos,pos_beg,pos_end)

  赋值:.assign(n,element)  .assign(pos_beg,pos_end) 旧的全部清理新的插入(pos_beg和pos_end是其他 列的位置)

  调整:.resize(n,element=0) 把大小调整为n 添加的个数的内容是element
  首尾:.front(), .back()  可以修改首尾元素的值

  增删:.push_back(element)  .pop_back() 只删除,返回void

03sequence.cpp

#include <deque>
#include <iostream>
using namespace std;
#include "print.h"
#include <string>

int main()
{
	deque<string> ds;
//	deque< vector<int> >;
	ds.push_back("曾文武");
	ds.push_back("赵旭泽");
	ds.push_back("薛小娟");
	ds.push_back("高上");
	print(ds.begin(),ds.end(),',');
	ds.insert(++++ds.begin(),2,"芙蓉");
	print(ds.begin(),ds.end(),',');
	string s[3]={"张彦春","张永香","刘克磊"};
	ds.insert(----ds.end(),s,s+3);
	print(ds.begin(),ds.end(),',');
	ds.pop_back(); ds.pop_back();
	print(ds.begin(),ds.end(),',');
	cout << "front:" << ds.front() << ",back:" << ds.back() << endl;
	ds.resize(12,"郭益如");
	print(ds.begin(),ds.end(),',');
	ds.assign(5,"康森林");
	print(ds.begin(),ds.end(),',');
	//ds.clear();
	ds.front() = "孙冬冬";
	ds.back() = "梁振杰";
	print(ds.begin(),ds.end(),',');	
}

print.h

<span style="font-size:18px;">#ifndef PRINT_H
#define PRINT_H 1
//输出一个指定区间中的所有数据(含头不含尾)
template<typename T>
void print(T b, T e, char c=' ')
{
	while(b!=e)
		cout << *b++ << c;
	cout << endl;
}
#endif
</span>


个性:
  1.vector个性其实就是一个动态数组(数组实现) 当容量不够时重新分配的大小是原来的两倍
     vector迭代器在插入删除之后可能会失效因为可能会重新分配内存,如果插入删除过再用迭代器需要重新去取得
     当前容量:.capacity()
     约定容量:.reserver(n)只要不超过这个容量就不用重新再分配,以免反复重新分配空间

     下标[]:   .operator[](i)不检查越界  .at(i)这个函数做越界检查,越界会抛出异常

04vector.cpp

#include <iostream>
using namespace std;
#include <vector>
#include "print.h"
#include <exception>
#include <typeinfo>

int main()
{
    vector<double> vd, vv;
    for(int i=0; i<9; i++){
        vd.push_back(i+0.1);
        cout << &*vd.begin() << ':';得到首个元素的地址 会发现有变化
        cout << vd.size() << '/' << vd.capacity() << endl;
    }
    cout << "------------------" << endl;
    vv.reserve(9);
    for(int i=0; i<9; i++){
        vv.push_back(i+0.5);
        cout << vv.size() << '/' << vv.capacity() << endl;
    }
    vd[3] = 123.45;
    vv.at(5) = 67.8;
    for(int i=0; i<=vd.size(); i++)
        cout << vd[i] << ' ';
    cout << endl;
    try{
    for(int i=0; i<=vv.size(); i++)
        cout << vv.at(i) << ' ';
    cout << endl;
    }catch(exception& e){
        cout << "异常:" << e.what() << endl;
        cout << "类型:" << typeid(e).name() << endl;
    }
    int m=3, n=5;
    void print(const vector< vector<int> >& v);
    vector< vector<int> > vvi(m, vector<int>(n) );//二维数组
    print(vvi);
    vvi.resize(m+3);
    vvi[1].assign(9,1);
    vvi[5].assign(4,5);
    print(vvi);
}
void print(const vector< vector<int> >& v)
{
    for(int i=0; i<v.size(); i++){
        for(int j=0; j<v[i].size(); j++){
            cout << v[i][j] << ' ';
        }
        cout << endl;
    }
}

  2.deque的个性:double-ended queue
    下标[]: .operator[](i) 不检查越界, .at(i)越界抛异常

     增删: .push_front(element), .push_back() .pop_front() .pop_back()

       适合从前面插入或删除数据

05deque.cpp

#include <iostream>
using namespace std;
#include <deque>
#include "print.h"
int main()
{
    deque<char> dc;
    dc.push_back(97);dc.push_back('c');
    dc.push_front('s');dc.push_front('d');
    dc.push_back('k');dc.push_front('$');
    print(dc.begin(),dc.end());//该函数在前面类中有定义
    dc[1] = 't';
    for(int i=0; i<dc.size(); i++)
        cout << dc[i] << ',';
    cout << endl;
    dc.pop_back();
    dc.pop_front();
    print(dc.begin(),dc.end());
}

     
  3.list的个性:双向链表
    增删:.push_front(element), .pop_front(), .remove(element)//==
    不支持下标[]
    除重:.unique()相邻的重复元素只保留一个
    排序:.sort(compare_func=less)默认用小于符号比较,从小到大排序
    倒置:.reverse()颠倒链表中元素顺序
    转移:.splice(pos,list2), .splice(pos,list2,pos2), .splice(pos,list2,pos_beg,pos_end)

    归并:.merge(list2) 两组都排好序的归并后的结果才是排好序的

06list.cpp

#include <iostream>
using namespace std;
#include <list>
#include "print.h"
#include <cassert>
bool compare(int x, int y)
{
    x%=3, y%=3;
    return x<y;
}
int main()
{
    int a[10]={3,8,8,8,5,5,1,8,8,7}, b[6]={9,3,5,2,7,6};
    list<int> li(a,a+10), lili(b,b+6);
    print(li.begin(), li.end());
    li.unique();
    print(li.begin(), li.end());
    li.sort();
    print(li.begin(), li.end());
    li.unique();
    print(li.begin(), li.end());
    li.reverse();
    print(li.begin(), li.end());
    li.splice(li.begin(),lili);//转移之后lili为空
    print(li.begin(), li.end());
    assert(lili.empty());
    li.remove(5);
    print(li.begin(), li.end());
    li.sort();li.unique();
    print(li.begin(), li.end());
    lili.push_back(0);lili.push_back(4);lili.push_back(7);
    lili.push_back(5);lili.push_back(10);
    lili.sort();
    print(lili.begin(), lili.end());
    li.merge(lili);
    print(li.begin(), li.end());
    lili.assign(b,b+6);
    print(lili.begin(), lili.end());
    lili.sort(greater<int>());
    print(lili.begin(), lili.end());
    lili.sort(compare);
    print(lili.begin(), lili.end());
}

———————————————————————————————————————————  
关联式容器共性:都是用二叉查找树实现的,都自动根据关键字排序
  set<K>,  multiset<K>, map<K,V>, multimap<K,V)
  查找:.find(key)返回一个迭代器指向找到的第一个元素,失败返回.end()
  统计:.count(key)统计关键字等于key的元素的个数
  删除:.erase(key)删除关键字等于key的所有元素
  区间:.lower_bound(key)取得关键字为key的第一个元素的位置, .upper_bound(key)取得关键字 为key的最后一个元素之后的位置, .equal_range(key)一次取得关键字为key的元素的区间,返回一个pair

  插入: .insert(element)//由于是二叉查找树实现的所以插入的时候不用指定位置


01associate.cpp
#include <set>
#include <iostream>
using namespace std;
#include "../stl1/print.h"
struct Person{
    string name;
    int age;
public:
    Person(const char* n, int a):name(n),age(a){}
};
bool operator<(const Person& a, const Person& b)
{return a.age<b.age||a.age==b.age&&a.name<b.name;}
ostream& operator<<(ostream&o, const Person& x)
{return o<<x.name<<':'<<x.age;} 
int main()
{
    multiset<Person> mp;
    mp.insert(Person("赵元培",26));
    mp.insert(Person("郭益如",18));
    mp.insert(Person("姚连斌",20));
    mp.insert(Person("赵元培",26));
    mp.insert(Person("赵元培",26));
    mp.insert(Person("王臣彬",21));
    mp.insert(Person("郭益如",18));
    mp.insert(Person("姚连斌",20));
    mp.insert(Person("张洪铭",22));
    mp.insert(Person("赵元培",26));
    mp.insert(Person("郭益如",18));
    mp.insert(Person("王臣彬",21));
    mp.insert(Person("郭益如",18));
    mp.insert(Person("王臣彬",21));
    mp.insert(Person("郭益如",18));
    print(mp.begin(), mp.end());
    multiset<Person>::iterator it=mp.find(Person("张洪铭",22));
    if(it==mp.end()) cout << "没有找到张洪铭" << endl;
    else cout << "发现目标:" << *it << endl;
    it=mp.find(Person("芙蓉",22));
    if(it==mp.end()) cout << "没有找到芙蓉" << endl;
    else cout << "发现目标:" << *it << endl;
    it = mp.find(Person("郭益如",18));
    cout << mp.count(*it) << "个" << *it << endl;
    it = mp.find(Person("赵元培",26));
    cout << mp.count(*it) << "个" << *it << endl;
    multiset<Person>::iterator ib, ie;
    ib = mp.lower_bound(Person("王臣彬",21));
    ie = mp.upper_bound(Person("王臣彬",21));
    cout << "===================" << endl;
    print(ib, ie);
    cout << "===================" << endl;
    pair<multiset<Person>::iterator,multiset<Person>::iterator>p=mp.equal_range(Person("姚连斌",20));
    print(p.first,p.second);
    typedef multiset<Person>::iterator Iter;
    pair<Iter,Iter>q=mp.equal_range(Person("郭益如",18));
    print(q.first,q.second);
    cout << "===================" << endl;
    mp.erase(Person("郭益如",18));
    mp.erase(Person("赵元培",26));
    print(mp.begin(), mp.end());
}




个性:
   1.map的个性:
    不允许key重复
    强调元素是map(key,value)一对
    支持以key为下标访问对应的value的引用,如果key不存在就新增一个元素以这个为key
    别的关联式容器不支持以Key为下标

    如果存的是对应关系就用map,如果存的只是关心的数据不存在对应关系就用set,set把整个元素作为key来比较。

02map.cpp

#include <iostream>
using namespace std;
#include <map>
#include "print.h"
struct P{
	string name;
	int age;
public:
	P(){}
	P(const char* n, int a):name(n),age(a){}
};
ostream& operator<<(ostream&o, const P& x)
{return o<<x.name<<':'<<x.age;} 
int main()
{
	map<int,P> mis;
	mis.insert(map<int,P>::value_type(8,P("王龙",20)));
	mis.insert(pair<int,P>(5,P("钟玉龙",22)));
	mis.insert(make_pair(4,P("李霖",21)));
	mis[3] = P("何军军",20);
	mis[6] = P("蒲嗣良",23);
	mis.insert(make_pair(5,P("芙蓉",18)));
	print(mis.begin(), mis.end());
	mis[6] = P("蒲松龄",300);
	print(mis.begin(), mis.end());
}
print.h

#ifndef PRINT_H
#define PRINT_H 1
//输出一个指定区间中的所有数据(含头不含尾)
template<typename T>
void print(T b, T e, char c=' ')
{
	while(b!=e)
		cout << *b++ << c;
	if(c!='\n') cout << endl;
}
template<typename K, typename V>
ostream& operator<<(ostream& o, const pair<K,V>& p)
{
	return o << p.first << ':' << p.second;
} 
#endif

   2.multimap的个性:
     允许重复key
     元素是key/value对

     不支持方括号下标

04multiset.cpp

#include <map>
#include <iostream>
using namespace std;
#include "print.h"
#include <string>
int main()
{
    typedef multimap<string,double> MSD;
    MSD m;
    m.insert(MSD::value_type("王刚",100000));
    m.insert(make_pair("何军军",120000));
    m.insert(make_pair("杨勇",20000));
    m.insert(make_pair("何军军",160000));
    m.insert(make_pair("杨勇",3000));
    m.insert(MSD::value_type("王刚",220000));
    m.insert(MSD::value_type("王刚",150000));
    m.insert(make_pair("何军军",130000));
    m.insert(make_pair("杨勇",1000000));
    m.insert(make_pair("杨勇",110000));
    print(m.begin(), m.end());
    MSD::iterator ib = m.begin(), ie;
    MSD cnt;
    while(ib!=m.end()){
        string name = ib->first;
        ie = m.upper_bound(name);
        double sum = 0.0;
        while(ib!=ie) sum += ib++->second;
        cnt.insert(make_pair(name,sum*0.03));
    }
    print(cnt.begin(),cnt.end());
}


  3.set的个性
    元素就是key
    不允许重复key  如果重复就会被抛弃

    可以默认被排好序

05set.cpp

#include <set>
#include <iostream>
using namespace std;
#include <string>
#include "print.h"
#include <fstream>
int main()
{
	set<string> ss;//set<char*> ss;
	string s;//char s[100];
	ifstream fin("maillist");
	if(!fin){return 1;}
	while(fin>>s) ss.insert(s);
	print(ss.begin(), ss.end(), '\n');
}


  4.multiset的个性
    元素就是key

    允许有重复的key

06mutiset.cpp

#include <set>
#include <iostream>
using namespace std;
#include "print.h"
#include <string>
#include <map>
int main()
{
	multiset<string> ms;
	string name;
	cout << "请输入你选举的人的姓名(Ctrl+D表示结束):\n";
	while(cin>>name){//Ctrl+D表示输入结束
		ms.insert(name);
	}
	print(ms.begin(), ms.end());
	multiset<string>::iterator ib=ms.begin(), ie;
	multimap<int,string> mis;
	while(ib!=ms.end()){
		mis.insert(make_pair(ms.count(*ib),*ib));
		ib = ms.upper_bound(*ib);
	}
	print(mis.begin(),mis.end(),'\n');
}


————————————————————————————————————————————
迭代器:是一种检查容器内元素并遍历元素的数据类型
  标准库为每种容器定义了一种迭代器类型,而且只有少数的容器比如vecotr deque支持下标操作
  所以,一般容器都能使用迭代器来检查、遍历容器,有的还可以使用下标来实现



特殊容器:stack queue  priority_queue
相同:  .push(element)  .pop()  .empty()  都不提供迭代器
不同: 栈: .top()
       队列 .front()  .back()
       优先队列  .top() 入的时候不讲究顺序,出的时候通过堆调整来实现最大的先出

07special.cpp

#include <queue>
#include <iostream>
using namespace std;

int main()
{
	priority_queue<int> pq;
	pq.push(50);pq.push(80);pq.push(20);pq.push(70);
	pq.push(60);pq.push(30);
	while(!pq.empty()){
		cout << pq.top() << endl;
		pq.pop();//最大的先出
	}
}

priorty_queue使用堆调整:只保证最大的在前面 不保证别的


一份讲解全面的标准模板STL学习资料 标准模板STL主要由6大组件组成: (1)容器(Containers)。包括各种基本数据结构的类模板STL容器部分主要由头文件<vector>、<list>、<deque>、<set>、< map>、<stack>和<queue>组成。 (2)算法(Algorithms)。包括各种基本算法,如比较、交换、查找、排序、遍历操作、复制、修改、移除、反转、合并等等。 STL算法部分主要由头文件<algorithm>和<numeric>组成。 (3)迭代器(Iterators)。迭代器是面向对象版本的指针,如同指针可以指向内存中的一个地址,迭代器可以指向容器中的一个位置。 STL的每一个容器类模板中,都定义了一组对应的迭代器类,用以存取容器中的元素。这样,在STL中迭代器就将算法和容器联系起来了,通过迭代器,算法函数可以访问容器中指定位置的元素,而无需关心元素的具体类型。 STL迭代器部分主要由头文件<utility>和<iterator>组成。 (4)函数对象(Function Objects)。一种行为类似于函数的class,实现技术上是一个改写了“call operator()”的class。 STL 提供 15 个预定义的 Function objects。头文件<functional>中定义了一些类模板,用以声明函数对象。 (5)适配器(Adaptors)。简单地说就是一种接口类,专门用来修改现有类的接口,提供一种新的接口;或调用现有的函数来实现所需要的功能。 主要包括3种适配器Container Adaptors、Iterator Adaptors与Function Adaptors。其中迭代器适配器的定义在头文件<iterator>中,函数适配器的定义在头文件<functional>中。 (6)内存配置器(Allocators)。为STL提供空间配置的系统。 头文件<memory>中的主要部分是模板类allocator,它负责产生所有容器中的默认分配器。容器使用allocator完成对内存的操作,allocator提供内存原语以对内存进行统一的存取。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值