• STL


    STL

    一、stl概述

    STL是standard template library的简称----标准模板库。是c++的标准程序库的核心,它深刻的影响了标准程序库的整体结构,他是一种泛型编程。

    从根本上来说,stl是一些“容器”的集合,这些“容器”list,vector,set,map

    stl也是算法和其他一些组件的集合,程序员无需了解stl原理,便可享受数据结构和算法领域中的这一革命新成果

    stl包含了算法和结构

    template<class T>
    void sort(T* parr,int len)
    {
        for(int i=0;i<len-1;i++)
        {
            for(int j=0;j<len-1-i;j++)
            {
                 parr[j]=parr[j]^parr[j+1];
                 parr[j+1]=parr[j]^parr[j+1];
                 parr[j]=parr[j]^parr[j+1];
                
            }
        }
    }
    
    头文件
    #include<vector>
    #include<deque>
    #include<list>
    #include<map>
    #include<set>
    #include<functional>
    

    二、STL容器

    为了适应不同的需要,STL提供了不同的容器

    1、序列式容器---可序

    vector,list,deque等

    可序:每个元素都有固定的位置,元素的位置取决于插入的时机的位置 (下标),和元素值无关

    2、关系式容器--已序

    set,multiset,map,multimap等

    已序:元素的位置取决于元素值的大小,和插入的次序无关

    3、可序与已序

    可序的优点:元素进入容器比较简单,元素的查找相对比较麻烦

    已序的优点:元素进入容器比较麻烦,元素的查找相对比较简单

    4、容器接口

    不管是已序容器还是可序容器,有一些共同的功能,也就是相同的函数接口。这些函数主要是用于进行数据比较,迭代和存储的

    比如:size(),关系运算符重载,迭代器相关,数据的插入,删除等

    三、STL容器满足的特性

    1、外部数据外部管理,内部数据内部管理,容器进行元素插入操作时,内部实现的是拷贝操作,容器中每一个元素都要能被拷贝或赋值

    2、容器总体而言所有的元素都形成次序(下表次序),多次遍历每个元素次序总是相同

    3、各项操作并非绝对安全

    四、迭代器--iterator

    迭代可以理解为遍历。

    每一个STL的容器当中都会有一个迭代器,迭代器是帮助我们去容器中查找所有的元素

    1、迭代器定义

    可遍历stl容器内全部或部分元素的对象,一个迭代器用来指出容器中的一个特定位置。他类似于智能指针,具有遍历复杂数据结构的能力,其运作机制取决于其所遍历的数据结构

    每一个容器的内存模型可能并不相同,每一个容器都有自己的迭代器,该迭代器以嵌套的方式定义在容器的内部。这个迭代器可以帮助我们去该容器中查找元素

    2、半开区间

    假如在容器中有两个迭代器,会形成一个区间--半闭合区间(半开区间)

    两个迭代器指向容器的不同位置,两个迭代器会形成区间,这个区间叫做半开区间

    3、半开区间的优点

    1.为遍历元素,提供循环的结束时机

    2.不需要对空区间采取特殊的处理手段

    五、vector---模拟动态数组

    #include

    1、vector的理解

    封装了动态数组的顺序容器,可以简单的认为,vector是一个能够存放任意类型的动态数组,也称为向量

    2、vector的特性

    1.顺序序列,有序群集,逻辑位置和物理位置连续

    2.支持随机存取

    3.在末端添加或删除元素方便,性能好

    4.头部或者中部插入元素或删除元素需要移位,性能差

    5.可以扩容,但是会导致内存重新分配

    六、vector里的基本函数

    1、构造与析构

    1;
    vector();//创建一个空vector
    2;
    vector(int size);//创建一个vector,元素个数为size
    3;
    vector(int size,const t&t);//创建一个vector,元素个数为size,且值均为t
    4;
    vector(const vector&);//复制构造函数
    5;
    vector(begin,end);//复制[begin,end]区间内另一个数组的元素到vector中
    6;
    ~vector();//删除所有元素,释放内存
        
    

    2、非变动性函数

    1;
    int size()const;//返回向量中元素的个数
    2;
    bool empty()const;//判断向量是否为空,若为空,则向量中无元素
    3;
    int capaicity()const;//返回当前向量所能容纳的最大元素值,capacity--容量
    4;
    int max_size()const;//返回最大可允许的vector元素数量值
    5;
    int capaicity()const;//返??
    
    

    3、赋值操作

    1;
    void swap(vector&);//交换两个同类型向量的数据
    2;
    void assign(int n,const T&x);//设置向量中第n个元素的值为x
    3;
    void assign(const_iterator first,const_iterator last);//向量中[fist,last]中元素设置为当前向量元素
    

    4、元素存取

    1;
    reference at(int pos);//返回pos位置元素的引用,reference--引用
    2;
    operator[idx];//返回索引idx所标示的元素,不进行范围检查
    3;
    reference front();//返回首元素的引用
    4;
    reference back();//返回尾元素的引用
    

    5、迭代器相关

    1;
    iterator begin();//返回向量头指针,指向第一个元素
    2;
    iterator end();//返回向量尾指针,指向向量最后一个元素的下一个位置
    3;
    reverse_iterator rbegin();//反向迭代器,指向最后一个元素
    4;
    reverse_iterator rend();//反向迭代器,指向第一个元素之前的位置
    

    6、插入和删除

    1;
    void push_back(const T&x);//向量尾部增加一个元素x
    2;
    iterator insert(iterator it,const T&x);//向量中迭代器指向元素前增加1个元素x
    3;
    iterator insert(iterator it,int n,const T&x);//向量中迭代器指向元素前增加n个相同的元素x
    4;
    iterator insert(iterator it,const_iterator first,const_iterator last);//向量中迭代器指向元素前插入另一个相同类型向量的[first,last]间的数据
    5;
    iterator erase(iterator it);//删除向量中迭代器指向元素,erase-擦去
    6;
    iterator erase(iterator first,iterator last);//删除向量中[first,last]中的元素
    7;
    void pop_back();//删除向量中最后一个元素
    8;
    void clear();//清空向量中的所有元素
    9;
    void resize(int n);//将元素数量改为num
    10;
    void resize(int n,T elem);//将元素数量改为num,如果size()变大了。多出来的新元素都是elem的副本
    
    

    7、实际使用

    	vector<double> v1(10);//调用构造函数
    	vector<int> v;//动态数组的容器
    	for (int i = 0; i < 10; i++)
    	{
    		v.push_back(i + 1);//尾部插入元素
    	}
    	printf("%d
    ", v[5]);//operator[idx]返回idx所标示的元素,不进行范围检查
    	v.pop_back();//尾部弹出容器
    	vector<int>::iterator vit;//定义一个迭代器
    	vit = v.begin() + 3;//begin()返回的是指向第一个元素的指针,再向后面移动三位,带来容器下标为3的位置
    	v.insert(vit, 123);//插入,迭代器
    
    	vit=v.begin();//插入数据后,导致内存重分配,内存地址改变,必须重新让迭代器执行新的容器
    
    	vit=vit+5;//vit(迭代器)指向了容器下标为6的元素
    	v.erase(vit);//iterator erase(iterator it);//删除向量中迭代器指向元素,erase-擦去
    	//begin函数返回容器中第一个元素的位置(返回迭代器)
    	//end函数返回容器中最后一个元素的下一个位置(返回迭代器)
    	for (vit = v.begin(); vit != v.end(); vit++)
    	{
    		printf("%d
    ", *vit);
    	}
    

    8、二维数组的操作

    int row = 5, col = 6;//5行,6列
    	vector<vector<int>>myvector(row);//定义二维动态数组大小为row行
    	for (size_t i = 0; i < myvector.size(); i++)//动态二维数组为row行col列,值全为0
    	{
    		myvector[i].resize(col);//表示调整容器的大小为col,扩容后的每个元素的值为element,默认为0,就是给每一行指定大小为col
    		//void resize(int n);//将元素数量改为num
    		//int size()const;//返回向量中元素的个数
    	}
    	for (size_t i = 0; i < myvector.size(); i++)//输出动态二维数组
    	{
    		for (size_t j = 0; j < myvector[i].size(); j++)
    		{
                myvector[i][j] = i * 10 + j;
    			cout << myvector[i][j] << " ";
    		}
    		cout << endl;
    	}
    

    七、deque--双端队列

    1、deque的特性

    deuqe是双向开口的连续线性空间(动态将多个连续空间通过指针数组接合在一起)

    可以理解为:deque是双端数组,vector是单端数组

    1.头尾开放,能在头部尾部进行快速插入和删除

    2.支持随机存取

    3.在中段部分插入,删除元素速度较慢,因为所有元素都需要移动以腾出或填补空间

    4.专门实现队列,选用deque(仅在头尾进行操作)

    5.和vector一样,扩容会导致内存重分配,内存重分配会导致迭代器失效

    6.注意:在使用vector和deque时,如果进行了插入和删除操作,一定要重新给迭代器赋值

    2、实际使用

    	deque<int> d;
    	for (int i = 0; i < 10; i++)
    		d.push_back(i + 1);//从尾部添加了10个元素
    	for (int i = 0; i < 5; i++)
    		d.push_front((i + 1) * 10);//从头部添加了5个元素
    	d.pop_back();//从尾部删除一个元素
    	d.pop_front();//从头部删除一个元素
    	deque<int>::iterator dit;
    	d[3] = 123;//将容器下标为3的元素改为123
    	dit = d.begin() + 2;//让迭代器指向容器下标为2的元素的位置
    	d.insert(dit, 100);//在容器下标为2的元素的位置插入元素100;
    	dit = d.begin() + 8;;//deque执行了删除和插入操作后,进行了内存重分配,所以必须给迭代器重新赋值
    	dit -= 2;//迭代器指向下标为6的元素的位置
    	d.erase(dit);//删除当前迭代器指向位置里的元素
    	for (dit = d.begin(); dit != d.end(); dit++)
    		printf("%d
    ", *dit);//打印容器里面的元素
    
    

    3、构造与析构函数

    1、deque c;//产生一个空的deque
    2、deque c1(c2);//针对某个deque 产生同类型副本(所有元素都被拷贝)
    3、deque c(n);//产生一个deque,含有n个元素
    4、deque c(n,elem);//产生一个deque,含有n个元素,这些元素均是elem的副本
    5、deque c(beg,end);//产生一个deque,以区间[beg;end)内的元素作为初值
    6、~deque();//销毁所有元素,释放内存
    

    4、非变动性函数

    1、size();//返回容器的实际元素个数
    2、empty();//判断容器大小是否为零
    3、max_size();//返回可容纳的最大元素数量
    4、operator==
    5、operator!=
    6、operator<
    7、operator>
    8、operator<=
    9、operator>=
    10、at(idx);//返回索引idx所标示的元素,如果idx越界,抛出out_of_range异常
    11、operator[idx];//返回索引idx所标示的元素,不进行范围检查
    12、front();//返回第一个元素。不检查元素是否存在
    13、back();//返回最后一个元素,不检查元素是否存在
    14、begin();//返回一个随机迭代器,指向第一个元素
    15、end();//返回一个随机迭代器,指向最后元素的下一个位置
    16、rbegin();//返回一个逆向迭代器,指向逆向迭代器时的第一个元素
    17、rend();//返回一个逆向迭代器,指向逆向迭代器时的最后元素的下一个位置
    

    5、变动性函数

    1、operator=;//将c2的所有元素赋值给c1
    2、assign(n,elem);//将n个elem 副本赋值给c
    3、assign(beg,end);//将区间[beg;end)中的元素赋值给c
    4、c1.swap(c2);//将c1 和c2 的元素互换5、swap(c1,c2);//将c1 和c2 的元素互换,此为全局函数
    6、insert(pos,elem);//在pos位置插入一个elem副本,并返回新元素的位置
    7、insert(pos,n,elem);//在pos位置插入elem的n个副本,无返回值
    8、insert(pos,beg,end);//在pos位置插入在区间[beg;end)所有元素的副本,无返回值
    9、push_back(elem);//在尾部添加elem的一个副本
    10、pop_back();//删除最后一个元素(但不返回删除的元素)
    11、push_front(elem);//在头部插入elem的一个副本
    12、pop_front();//删除头部元素(但不返回删除的元素)
    13、erase(pos);//删除pos位置上的元素,返回下一个元素位置
    14、erase(beg,end);//删除[beg, end)区间内的所有元素,返回下一个元素位置
    15、resize(num);//将大小(元素个数)改为num,如果size()增长了,新增元素都以默认构造函数产生
    出来
    16、resize(num,elem);//将大小(元素个数)改为num,如果size()增长了,新增元素都是elem的副本
    17、clear();//移除所有元素,将容器清空
    
    

    八、list

    使用一个双向链表来管理元素

    list的内部结构和vector或deque截然不同。

    基本操作

    list<int> mylist;
    	for (int i = 0; i < 10; i++)
    		mylist.push_back(i + 1);//插入10个元素在list中
    	mylist.push_front(4);
    	mylist.push_front(4);
    	mylist.push_front(4);//从头部插入3个4到list中
    
    	mylist.push_back(4);
    	mylist.push_back(4);
    	mylist.push_back(4);//从尾部插入3个4到list中
    
    	mylist.remove(4);//删除list这个双向链表中所有值为4的节点
    	//bool isodd(int val){ return val % 2 != 0; }
    	mylist.remove_if(isodd);////删除所有“造成isodd(elem)结果为true”的元素,就是说将链表中的所有元素都传到isodd中,返回为true就将那个元素删除 
    	//bool ismin(int a, int b) { return a < b; }
    	mylist.unique(ismin);//如果存在若干相邻元素,都使ismin()的结果为true,则删除重复元素,只留下一个.就是说将链表中的所有元素都传到ismin这个函数中,结构返回为true就将b数据删除。4>1,不删除,1<2,删除2,1<3,删除3......
    
    	list<int>::iterator lit;
    	list<int> mylist1;
    	lit = mylist1.begin();//物理位置不是连续的,所以不能加减
    	mylist1.splice(lit, mylist);//将mylist内的所有元素转移到mylist之内、迭代器lit之前.因为是转移不是拷贝,所以原来的容器里就没有东西了(只需要将链表指针断开)
    	for (lit = mylist.begin(); lit != mylist.end(); lit++)
    		printf("%d
    ", *lit);
    	
    

    1、list的特性

    1.不支持随机存取

    2.在任何位置上,插入和删除都很快

    3.插入和删除操作不会导致迭代器失效

    2、构造与析构函数

    1、list c;//产生一个空的list
    2、list c1(c2);//产生一个与c2同类型的list(每个元素都被复制)
    3、list c(n);//产生拥有n个元素的list,这些元素都以默认构造函数初始化
    4、list c(n,elem);//产生拥有n个元素的list,每个元素都是elem的副本
    5、list c(beg,end);//产生一个list并以 [beg;end)区间内的元素为初值
    6、~list();//销毁所有元素,释放内存
    

    3、非变动性函数

    1、c.size();//返回元素个数
    2、c.empty();//判断容器大小是否为零
    3、c.max_size();//返回元素的最大可能数量
    4、operator==
    5、operator!=
    6、operator<
    7、operator>
    8、operator<=
    9、operator>=
    

    4、赋值操作

    1、operator=
    2、c.assign(n,elem);//将elem的n个拷贝赋值给c
    3、c.assign(beg,end);//将区间[beg;end)的元素赋值给c
    4、c1.swap(c2);//将c1和c2的元素互换
    5、swap(c1,c2);//将c1和c2的元素互换,此为全局函数
    
    

    5、直接取操作

    1、c.front();//返回第一个元素,不检查元素是否存在
    2、c.back();//返回最后一个元素,不检查元素是否存在
    注意:list不支持随机存取,只有上述2个函数才能直接取元素
    

    6、迭代器相关

    1、c.insert(pos,elem);//在迭代器pos所指位置上插入一个elem副本,并返回新元素的位置
    2、c.insert(pos,n,elem);//在迭代器pos所指位置上插入n个elem 副本,无返回值
    3、c.insert(pos,beg,end);//在迭代器pos所指位置上插入[beg;end)区间内的所有元素的副本,无返值
    4、c.push_back(elem);//在尾部追加一个elem副本
    5、c.pop_back();//删除最后一个元素(但不返回其值)6、c.push_front(elem);//在头部插入一个elem副本
    7、c.pop_front();//删除第一个元素(但不返回其值)
    8、c.remove(val);//删除所有值为val的元素
    9、c.remove_if(op);//删除所有“造成op(elem)结果为true”的元素
    10、c.erase(pos);//删除迭代器pos所指元素,返回下一个元素位置
    11、c.erase(beg,end);//删除区间[beg;end)内的所有元素,返回下一个元素位置
    12、c.resize(num);//将元素容量变为num。如果size()变大,则以默认构造函数构造所有新增元素
    13、c.resize(num,elem);//将元素容量变为num。如果size()变大,则以elem副本作为新增元素的初值
    14、c.clear();//删除全部元素,将整个容器清空
    
    

    7、特殊变动性操作

    1、c.unique();//如果存在若干相邻而数值相同的元素,就删除重复元素,只留下一个
    2、c.unique(op);//如果存在若干相邻元素,都使op()的结果为true,则删除重复元素,只留下一个
    3、c1.splice(pos,c2);//将c2内的所有元素转移到c1之内、迭代器pos之前
    4、c1.splice(pos,c2,c2pos);//将c2内的c2pos所指元素转移到c1内的pos所指位置上(c1 和c2可相同)
    5、c1.splice(pos,c2,c2beg,c2end);//将c2内的[c2beg;c2end)区间内所有元素转移到c1内的pos之前(c1
    和c2可相同)
    6、c.sort();//以operator< 为准则,对所有元素排序
    7、c.sort(op);//以op()为准则,对所有元素排序
    8、c1.merge(c2);//假设c1和c2容器都包含已排序元素,将c2的全部元素转移到c1,并保证合并后的list
    仍为已排序
    9、c1.merge(c2,op);//假设c1和c2容器都包含op()原则下的已排序元素,将c2的全部元素转移到c1,并
    保证合并后的list在op()原则下仍为已排序
    10、c.reverse();//将所有元素反序
    
    

    九、map

    二叉查找树

    map将key/value当做元素(pair),进行管理。可以根据key的排序准则自动将元素排序

    1、map的特性

    1.map的元素类型为key和T,必须满足一下两个条件

    2.key/value必须具备可赋值和可复制的性质

    3.对排序准则而言,key必须是可以比较的

    4.map根据元素的key自动对元素进行排序,根据已知的key搜寻某个元素的时候,就能有很好的性能,而根据已知value搜寻元素时,性能比较差

    基本操作

    //map容器里面的元素是一组,有key和value组成
    	//map已序,key来排序
    	//key和value可赋值和可复制
    	map<int, string> ms;
    	ms[4] = "张三";//key为4,value为"张三"
    	ms[2] = "李四";//把key和value做一个映射,通过key来关联value
    	ms[4] = "王五";//会将第一个key为4的数覆盖掉
    
    	ms.insert(make_pair(3, "name"));//理解为函数模板,可以通过make_pair()里的数据来推导出map的具体类型
    	//ms.insert(make_pair(3, "kisss"));不能这样用
    
    	map<int, string>::iterator mit;
    	for (mit = ms.begin(); mit != ms.end(); mit++)
    	{
    		printf("key=%d,value=%s
    ", mit->first, mit->second.c_str());
    	}
    	multimap<int, double> m1;
    	//m1[2]=3.12这样是不行的
    	m1.insert(make_pair(5, 1.2));
    	m1.insert(make_pair(3, 3.12));
    	m1.insert(make_pair(3, 1.3243));//key可以重复一样,然后打印的顺序是根据key的大小来排序的,key小的在前面打印,大的在后面打印
    	multimap<int, double>::iterator mit1;
    	for (mit1 = m1.begin(); mit1 != m1.end(); mit1++)
    	{
    		printf("key=%d,value=%lf
    ", mit1->first, mit1->second);
    	}
    	//使用头文件#include<functional>
    	multimap<int, double,greater<int>> m1;//本来打印的时候是按照key的大小升序来排的,不过现在也是按照key的大小,不过是降序排序
    

    2、构造与析构函数

    1、map c;//产生一个空的map,其中不含任何元素
    2、map c1(c2);//产生某个map的副本,所有元素均被复制
    3、map c(beg,end);//以区间[beg;end)内的元素产生一个map
    4、~map();//销毁所有元素,释放内存
    
    

    3、非变动性操作

    1、c.size();
    2、c.empty();
    3、c.max_size();
    4、operator==
    5、operator!=
    6、operator<
    7、operator>
    8、operator<=
    9、operator>=
    
    

    4、特殊搜寻操作--multimap

    1、count(key);//返回“键值等于key”的元素个数
    2、find(key);//返回“键值等于key”的第一个元素,找不到就返回end()
    3、lower_bound(key);//返回“键值为key”的元素的第一个可插入的位置,也就是“键值 >= key”的第一个
    元素位置
    4、upper_bound(key);//返回“键值为key”的元素的最后一个可插入的位置,也就是“键值 > key”的第一
    个元素位置
    5、equal_range(key);//返回“键值为key”的元素的第一个可插入位置和最后一个可插入位置,也就是“键
    值 == key”的元素区间
    

    5、赋值操作

    1、operator=
    2、c1.swap(c2);
    3、swap(c1,c2);
    

    6、迭代器相关

    1、c.begin();
    2、c.end();
    3、c.rbegin();
    4、c.rend();
    

    7、插入和删除

    1、c.insert(elem);//插入一份elem 副本
    2、c.insert(pos,elem);//插入一份elem 副本
    3、c.insert(beg,end);//将区间[beg;end)内所有元素的副本安插到c(无返回值)
    4、c.erase(elem);//移除“key与elem 相等”的所有元素,返回被移除的元素个数
    5、c.erase(pos);//移除迭代器pos 所指位置上的元素,无返回值
    6、c.erase(beg,end);//移除区间[beg;end)内的所有元素,无返回值
    7、c.clear();//移除全部元素,将整个容器清空
    

    8、元素存取

    1、operator[key]
    

    9、基本用法

    1、定义 > 排序
    #include<xfunctional>
    map<int, string, std::greater<int>> m;//降序的排序
    
    2、插入
    //1
    m.insert(std::pair<int,double>(2,3.14));
    //2
    m.insert(map<int, double>::value_type(6, 1.11));
    //3
    m.insert(std::make_pair(5, 9.99));
    

    十、set

    set和map的区别不大,只是key和value一样的

  • 相关阅读:
    GridView取不到值的问题总结
    DataGridView中的Combobox的应用
    .NET开发的一些积累
    .net字符串内存的分配
    冒泡排序
    字段自动递增的数据库建表的SQL写法
    [数据库]简单SQL语句总结
    C#知识
    sql语句大全
    白盒测试和黑盒测试
  • 原文地址:https://www.cnblogs.com/Kissfly123/p/14535120.html
Copyright © 2020-2023  润新知