C++标准模板

C++标准模板库STL

一:基本概念

STL提供了一组表示容器、迭代器、函数对象和算法的模板。容器是一个与数组类似的单元,可以存储若干个值。STL容器是同质的,即存储值得类型是相同的;算法是完成特定的任务(包括对数组排序或者是链表中查找某个值),迭代器用来遍历容器的对象,类似于遍历数组的指针,是广义指针。STL使得能够构造各种容器(包括数组,队列以及链表等)和执行各种操作(包括搜索,排序,随机排列等)。
STL不是面向对象的编程,而是一种不同的编程模式——泛型编程

二:模板类Vector

模板类Vector是一种动态数组,它可以在运行阶段设置Vector对象的长度,可在末尾以及中间添加新数据,Vector是使用new与delete来管理内存,只不过这种管理是自动进行的。
第一:要使用Vector对象,必须包含头文件,即#include<vector>
第二:Vector包含在名称空间std中,因此,可用using编译指令,using声明或者是std::vector
第三:模板使用不同的语法来指出他的数据类型。
例如:

        #include<vector>
        ...
        using namespace std;
        vector<int> vi;  //创建大小为零的整型数组
        int n;
        cin>>n;
        vector<double> vd(n);//创建大小为n的双精度型数组

其中,vi是一个vector对象,vd是一个vector对象,vector对象在声明的时候可以自动调整长度。基本语法如下:

vector<typename> vt(n_elem);

含义为,创建一个名称为vt的一个对象,存储的数据类型为typename,数据个数为n_elem。
在计算中,矢量(vector)对应数组,存储了一些可以随机访问的值,即可以用索引来直接访问矢量的第10个元素,而不必首先访问前面的9个元素,可以使用[]来访问vector中元素。要使类成为通用的,应该将它设置为模板类,STL正是这样做的——在头文件vector(以前为vector.h)中定义一个vector模板。
要创建vector模板对象,可以使用通常的表示法来指出要使用的数据类型。另外,vector模板使用动态内存分配,因此可以用初始化参数来指出需要多少矢量。
迭代器是一个广义指针,它可以是指针,也可以是一个可对其执行类似指针操作的对象,稍后将知道,通过将指针广义化为迭代器,让STL能够为各种不同的容器类提供统一的接口。每一个容器都定义了一个合适的迭代器,该迭代器的类型是一个名为iterator的typedef,其作用域为整个类。
例如,要为vector的double类型规范声明一个迭代器,可以这样做:

    vector<double>::iterator pd;

假设scores是一个vector对象,则可以对其进行如下操作:

    pd=scores.begin();  //使pd对应第一个元素
    *pd=22.3;  //给第一个元素赋值
    ++pd;     //使pd指向下一个元素

可以用下面的例子显示容器的内容:

for(pd=scores.begin();pd!=scores.end();pd++)
    cout<<*pd<<endl;

vector模板类中还有一个比较方便的方法,push_back(),这是一个方便的方法,它将元素添加到矢量末尾,这样做时,他将负责内存管理,增加矢量的长度,使之能够容纳新成员,代码如下:

vector<double>scores; //创建一个空的vector
double temp;
while(cin>>temp&&temp>=0)
    scores.push_back(temp);
cout<<"you entered"<<scores.size()<<" scores.\n";

每次循环都给scores对象增加一个元素,在编写或运行程序时,无需了解元素个数,只要能够取得足够的内存,程序就可以根据需要增加scores的长度。

三:泛型编程

STL是一种泛型编程。面向对象编程关注的是编程的数据方面,而泛型编程关注的是算法。
泛型编程旨在编写独立于数据类型的代码,在C++中,完成通用程序的工具是模板。

3.1 迭代器的使用

理解迭代器是理解STL的关键所在。模板使得算法独立于存储的数据类型,而迭代器使得算法独立于使用的容器类型。
比如使用find函数来查找不同数据结构数据中的某个元素,泛型编程旨在使用同一个find函数来处理数组、链表以及其它任何容器类型,即函数不仅独立于容器中存储的数据类型,还独立于容器本身的数据结构。模板提供了存储在容器中数据类型的通用表示,因此还需要遍历容器中值得通用表示,迭代器正是这样的通用表示。
你只需要知道有迭代器,且begin()返回指向第一个元素的迭代器,end()返回一个指向超尾位置的迭代器。每个容器都使用++操作(以及*操作),让迭代器从第一个元素逐步指向超尾位置,从而遍历容器中的每一个元素。例如,要打印vector对象中的值,可以这样做:

vector<double>::iterator pr;
for(pr=scores.begin();pr!=scores.end();pr++)
cout<<*pr<<endl;
容器种类

STL具有容器概念和容器类型。概念是具有名称(如容器、序列容器、关联容器等)的通用类别;容器类型是可用于创建具体容器对象的模板。

序列容器

(1)deque
deque模板类(在deque头文件中声明)表示双端队列(double-ended queue),通常被简称为deque。在STL中,其实现类似于vector容器,支持随机访问。主要的区别在于,从deque对象的开始位置插入和删除元素的时间是固定的,而不像vector中那样是线性时间的。因此,如果多数操作发生在序列的起始和结尾处,应该考虑使用deque数据结构。
为了实现deque在两端插入和删除的操作的时间为固定这一目的,deque对象的设计比vector对象更为复杂。因此,尽管二者都提供对元素的随机访问和在序列中部执行线性时间的插入以及删除操作,但vector容器执行这些操作的速度要快一些。
使用deque容器必须在程序的开头加上头文件#include;deque属于std命名域的内容,因此在使用时应该通过命名限定,using std::deque,或者是直接使用全局的命名空间,即using namespace std。

   deque<Elem> c;//创建一个空的deque
   deque<Elem> c1(c2);//复制一个deque
   deque<Elem> c(n) 创建一个deque,含有n个数据,数据均已缺省构造产生
   ~deque<Elem>() 销毁所有数据,释放内存

成员函数
c.begin()返回指向第一个元素的迭代器
c.end()返回指向最后一个元素下一个位置的迭代器

1     deque<int> d {1,2,3,4,5};
2     deque<int>::iterator it;
3     for(it=d.begin();it!=d.end();it++){
4         cout << *it << " ";
5     }
6     cout << endl;

c.empty()判断c容器是否为空

deque<int> d {1,2,3,4,5};
    if(!d.empty()){
        cout << "d is not empty!" << endl;
    }else{
        cout << "d is empty!" << endl;
    }
    return 0;

c.front()返回c容器的第一个元素
c.back()返回c容器的最后一个元素

1     deque<int> d {1,2,3,4,5};
2     if(!d.empty()){
3         cout << "d.front():" << d.front() << endl;
4         cout << "d.back(): " << d.back() << endl;
5     }

c.size()返回c容器中实际拥有的元素个数

1     deque<int> d {1,2,3,4,5};
2     cout << "d.size():" << d.size() << endl;
3     return 0;

c.push_back(num)在末尾位置插入元素
c.pop_back()删除末尾位置的元素
c.push_front(num)在开头位置插入元素
c.pop_front()删除开头位置的元素

deque<int> d {1,2,3,4,5};
    d.push_back(10);
    deque<int>::iterator it;
    cout << "push_back(num):" ;
    for(it=d.begin();it!=d.end();it++){
            cout << *it << " ";
    }
    cout << endl;

    d.pop_back();
    cout << "pop_back(num):" ;
    for(it=d.begin();it!=d.end();it++){
        cout << *it << " ";
    }
    cout << endl;

    d.push_front(10);
    cout << "push_front(num):" ;
    for(it=d.begin();it!=d.end();it++){
        cout << *it << " ";
    }
    cout << endl;

    d.pop_front();
    cout << "pop_front(num):" ;
    for(it=d.begin();it!=d.end();it++){
        cout << *it << " ";
    }
    cout << endl;
    return 0;

c.erase(pos)删除pos位置的元素c.erase(beg,end)删除区间为[beg,end)的元素
c.erase(beg,end)删除区间为[beg,end)之间的元素

deque<int> d {1,2,3,4,5};
    d.erase(d.begin());
    deque<int>::iterator it;
    cout << "erase(pos) after:" ;
    for(it=d.begin();it!=d.end();it++){
        cout << *it << " ";
    }
    cout << endl;
    d.erase(d.begin(), d.begin()+3);
    cout << "erase(beg,end) after:" ;
    for(it=d.begin();it!=d.end();it++){
        cout << *it << " ";
    }
    cout << endl;

c.insert(pos,num)在pos位置插入元素num
c.insert(pos,n,num)在pos位置插入n个元素num
c.insert(pos,beg,end)在pos位置插入区间为[beg,end)的元素

deque<int> d {1,2,3,4,5};
    deque<int>::iterator it;
    cout << "insert before:" ;
    for(it=d.begin();it!=d.end();it++){
        cout << *it << " ";
    }
    cout << endl;
    d.insert(d.end(),22);
    d.insert(d.end(), 3,88);
    int a[5] = {1,2,3,4,5};
    d.insert(d.begin(),a,a+3);
    cout << "insert after:" ;
    for(it=d.begin();it!=d.end();it++){
        cout << *it << " ";
    }
    cout << endl;
(2)vector,list
关联容器

(1)map
map是一类关联式容器,它是模板类。关联的本质在于元素的值与某个特定的键相关联,而并非通过元素在数组中的位置类获取。它的特点是增加和删除节点对迭代器的影响很小,除了操作节点,对其他的节点都没有什么影响。对于迭代器来说,不可以修改键值,只能修改其对应的实值。
使用map得包含map类所在的头文件:#include //注意,STL头文件没有扩展名.h
map对象是模板类,需要关键字和存储对象两个模板参数,基本的定义模式如下:

std:map<int, string> personnel;

这样就定义了一个以int为键,值为string的map对象personnel。

map中定义了以下三个类型:
map<K, V>::key_type : 表示map容器中,**索引的类型**;
map<K, V>::mapped_type : 表示map容器中,**键所关联的值的类型**;
map<K, V>::value_type : 表示一个pair类型,
它的first元素具有const map<K, V>::key_type类型,而second元素则有map<K, V>::mapped_type类型

对迭代器进行解引用时,将获得一个引用,指向容器中一个value_type类型的值,对于map容器,其value_type是pair类型。

1:在map中添加元素
使用下标操作符获取元素,然后给元素赋值;

    map<string, int> word_count; // 定义了一个空的map对象word_count;
    word_count["Anna"] = 1;

程序执行过程
1.在word_count中查找键为Anna的元素,没有找到.
2.将一个新的键-值对插入到word_count中,他的键是const string类型的对象,保存Anna。而他的值则采用直初始化,这就意味着在本例中指为0.
3.将这个新的键-值对插入到word_count中
4.读取新插入的元素,并将她的值赋为1.

使用map::insert方法添加元素。
1 map.insert(e);e是一个用在map中的value_type类型的值。如果键不存在,则插入一个值为e.second的新元素;如果键在map中已经存在,那么不进行任何操作。该函数返回一个pair类型,该pair类型的first元素为当前插入e的map迭代器,pair的second类型是一个bool类型,表示是否插入了该元素。也可以用pair类型来插入,例如:

#include<map>  //必须要生命头文件
map<int,string> mapstudent; //声明map
mapstudent.insert(pair<int,string>(5,"student"));
 //通过pair方式插入数据,也有通过valuetype方式的。插入完了之后就是访问,访问是通过一种叫做迭代器的方式,迭代器能够容纳任何数据结构,并且对任何数据结构进行访问,这才是迭代器强大的地方
map<int,string>::iterator iter;
for(iter=mapstudent.begin();iter!=mapstudent.end();iter++)
    cout<<iter->first<<"  "<<iter->second<<endl;

程序实例:

#include <map>  
#include <string>  
#include <iostream>  
Using namespace std;  
Int main()  
{  
       Map<int, string> mapStudent;  
       mapStudent.insert(pair<int, string>(1, “student_one”));  
       mapStudent.insert(pair<int, string>(2, “student_two”));  
       mapStudent.insert(pair<int, string>(3, “student_three”));  
       map<int, string>::iterator  iter;  
       for(iter = mapStudent.begin(); iter != mapStudent.end(); iter++)  
      {  
           Cout<<iter->first<<”   ”<<iter->second<<end;  
      }  
}  

其中一定要注意可以用迭代器指针访问pair中first以及second类型的东西。即iter->first,iter->second。

//map添加数据总结;
map<int ,string>maplive;
1. maplive.insert(pair<int,string>(102,"aclive"));
2. maplive.insert(map<int,string>::value_type(321,"hai"));
3. maplive[112]="April";//map中最简单最常用的插入添加!

///
2 map.insert(beg, end) : beg和end是迭代器,返回void类型
3.map.insert(iter, e) : e是value_type类型的值,如果e.first不在map中,则创建新元素,并以迭代器iter为起点搜索新元素存储的位置,返回一个迭代器,指向map中具有给定键的元素。

word_count.insert(map<sting, int>::value_type("Anna", 1));
word_count.insert(make_pair("Anna", 1)); 

查找并获取map中的新元素
使用下标获取元素存在一个很危险的副作用:如果该键不在map容器中,那么下标操作会插入一个具有该键的新元素,因此引入map对象的查询操作:
map.count(k) : 返回map中键k的出现次数(对于map而言,由于一个key对应一个value,因此返回只有0和1,因此可以用此函数判断k是否在map中)
map.find(k) : 返回map中指向键k的迭代器,如果不存在键k,则返回超出末端迭代器。

int occurs = 0;
if( word_count.cout("foobar") )
     occurs = word_count["foobar"];

int occurs = 0;
map<string, int>::iterator it = word_count.find("foobar");
if( it != word_count.end() )
     occurs = it ->second;
//map中元素的查找:
//find()函数返回一个迭代器指向键值为key的元素,如果没找到就返回指向map尾部的迭代器。

map<int ,string >::iteratorl_it;; 
l_it=maplive.find(112);//返回的是一个指针
if(l_it==maplive.end())
cout<<"we do not find112"<<endl;
elsecout<<"wo find112"<<endl;
map<string,string> m;
if(m[112]=="")
cout<<"we do not find112"<<endl;

///
从map中删除元素
移除某个map中某个条目用erase(),该成员方法的定义如下:

iterator erase(iterator it); //通过一个条目对象删除
iterator erase(iterator first, iterator last); //删除一个范围
size_type erase(const Key& key); //通过关键字删除

示例2:map中元素的删除:

//如果删除112;
map<int ,string>::iterator l_it;
l_it =maplive.find(112);
if( l_it == maplive.end())
cout<<"we do not find112"<<endl;
else maplive.erase(l_it);//删除112;

map当中基本的操作函数:
C++Maps 是一种关联式容器,包含“关键字/值”对
begin() 返回指向map头部的迭代器
clear() 删除所有元素
count() 返回指定元素出现的次数
empty() 如果map为空则返回true
end() 返回指向map末尾的迭代器
equal_range() 返回特殊条目的迭代器对
erase() 删除一个元素
find() 查找一个元素
get_allocator() 返回map的配置器
insert() 插入元素
key_comp() 返回比较元素key的函数
lower_bound() 返回键值>=给定元素的第一个位置
max_size() 返回可以容纳的最大元素个数
rbegin() 返回一个指向map尾部的逆向迭代器
rend() 返回一个指向map头部的逆向迭代器
size() 返回map中元素的个数
swap() 交换两个map
upper_bound() 返回键值>给定元素的第一个位置
value_comp() 返回比较元素value的函数

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值