STL后续-deque容器

前期简介:STL的六个组件

容器(container):一种空间,用来存放数据,可以分为连续空间和非连续空间

算法(algorithm):用来操作数据

迭代器(iterator):泛化的指针,用来指向容器中的某个位置便于算法间接的操作数据

仿函数(functor):又叫函数对象,即重载了函数调用运算符的类其实例化的对象,为算法提供策略(抛开函数调用来操作数据外,还可以使用仿函数来调用数据)

适配器(adaptor):为一个类模板,用于接口映射

空间配置器(allocator):为容器分配所需要大小的空间

容器的分类

STL标准模板库提供了很多容器,总体分为两种容器,序列容器(sequence containers)和关联容器(associative containers)

常见的序列容器有vector、deque、queue、stack、list,

常见的关联容器有set、multiset、map、multimap。
上章节讲到了vector容器,这章节详细的讲一下deque容器

deque

deque区别于vector,他是双端动态数组(双端队列),即可以两端操作,

 deque的特点

1、deque容器允许以常数项时间对头尾两端进行操作,比如插入删除操作

2、deque容器没有容量的概念(capacity),因为deque的容器是分段连续的空间,可以理解为多个vector且头尾都可以操作的空间集合(不严谨),有图示下:

此图可知:这个缓冲区每一行可以理解为一个vector,每个vector通过中控器相连在一起形成一个deque容器,类似于链表(链表中的每一个节点通过指针相连)

deque的API

/*
 * deque的构造函数
 * deque<T> deque;//默认构造函数
 * deque(begin,end);//将[begin,end)区间的数据拷贝给自己,不能这样初始化,可以使用insert(deque,begin,end);
 * deque(num,element);//将num个element数据拷贝给自己,调用不适用,可以使用deque(deque.end(),num,element);
 * deque(cons deque &deque);//拷贝构造函数,在deque不适合用(),可以使用=,即deque(自己)=deque;
 *
 * deque的赋值操作
 * assign(begin,end);//通过调用assign方法将[begin,end)区间的数据拷贝给自己
 * assign(num,element);//通过调用assign方法将num个element数据拷贝给自己
 * deque& opeerator=(const deque &deque);//重载赋值运算符,将deque对象拷贝赋值给自己
 * swap(deque);//调用swap方法将deque对象的数据和自己的数据互换
 *
 * deque空间操作
 * deque.size();//返回容器中的元素个数
 * deque.empty();//判断容器是否为空,为空则返回true,不为空返回false
 * deque.resize(num);//重新指定容器的长度为num,若容器变长,比原来长的部分空间以默认值填充(一般是0),若容器变短,则超出的部分元素被删除
 * deque.resize(num,element);//重新指定容器的长度为num,若容器变长,比原来长的部分空间以指定的element填充,若容器变短,则超出的部分元素被删除
 *
 * deque的双端队列插入和删除操作
 * push_bakc(element);//尾部插入一个element数据
 * push_front(element);//在头部插入一个element数据
 * pop_back();//没有参数,调用一次pop_back方法则表示删除容器尾部最后一位元素
 * pop_front();//也没有参数,调用一次pop_front方法则表示删除容器头部第一个元素
 *
 */

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

//自定义一个遍历deque容器的方法
void printDequeInt(deque<int> &d){
    deque<int>::iterator it=d.begin();
    for(;it!=d.end();it++){
        //*it表示取值,即*it==int(某一个值)
        cout<<*it<<" ";
    }
    cout<<endl;//容器内所有数据遍历之后输出换行
}

void test(){
/*
 * deque的构造函数
 * deque<T> deque;//默认构造函数
 * deque(begin,end);//将[begin,end)区间的数据拷贝给自己,不能这样初始化,可以使用insert(deque,begin,end);
 * deque(num,element);//将num个element数据拷贝给自己,调用不适用,可以使用deque(deque.end(),num,element);
 * deque(cons deque &deque);//拷贝构造函数,在deque不适合用(),可以使用=,即deque(自己)=deque;
 *
 * deque的赋值操作
 * assign(begin,end);//通过调用assign方法将[begin,end)区间的数据拷贝给自己
 * assign(num,element);//通过调用assign方法将num个element数据拷贝给自己
 * deque& opeerator=(const deque &deque);//重载赋值运算符,将deque对象拷贝赋值给自己
 * swap(deque);//调用swap方法将deque对象的数据和自己的数据互换
 *
 * deque空间操作
 * deque.size();//返回容器中的元素个数
 * deque.empty();//判断容器是否为空,为空则返回true,不为空返回false
 * deque.resize(num);//重新指定容器的长度为num,若容器变长,比原来长的部分空间以默认值填充(一般是0),若容器变短,则超出的部分元素被删除
 * deque.resize(num,element);//重新指定容器的长度为num,若容器变长,比原来长的部分空间以指定的element填充,若容器变短,则超出的部分元素被删除
 *
 * deque的双端队列插入和删除操作
 * push_bakc(element);//尾部插入一个element数据
 * push_front(element);//在头部插入一个element数据
 * pop_back();//没有参数,调用一次pop_back方法则表示删除容器尾部最后一位元素
 * pop_front();//也没有参数,调用一次pop_front方法则表示删除容器头部第一个元素
 *
 */

    //以int类型的deque容器为例,deque容器的双端队列插入操作
    deque<int> deq;
    deq.push_back(100);
    deq.push_back(300);
    deq.push_back(900);
    printDequeInt(deq);

    deq.push_front(1200);
    deq.push_front(2000);
    printDequeInt(deq);

    //deque容器的删除和空间操作
    cout<<deq.size()<<endl;//尾部删除前容器大小
    deq.pop_back();//调用尾部删除方法之后,尾部元素被删除
    cout<<deq.size()<<endl;//删除后容器大小
    printDequeInt(deq);

    cout<<deq.size()<<endl;//头部删除前容器大小
    deq.pop_front();
    cout<<deq.size()<<endl;//头部删除后容器大小
    printDequeInt(deq);

    if(deq.empty()){
        cout<<"容器为空"<<deq.size()<<endl;
        cout<<"尾部元素:"<<deq.back()<<"头部元素:"<<deq.front()<<endl;
    }
    else{
        cout<<"容器非空,大小为:"<<deq.size()<<endl;
        cout<<"尾部元素:"<<deq.back()<<"头部元素:"<<deq.front()<<endl;
    }
   deq.resize(100);
   cout<<deq.size()<<endl;
   printDequeInt(deq);

   deq.resize(3);
   cout<<deq.size()<<endl;
   printDequeInt(deq);

   //deque的赋值操作
   deque<int> deq1;
   deq1.assign(deq.begin(),deq.end());
   cout<<deq.size()<<endl;
   printDequeInt(deq1);

   deq1.assign(9,9999);
   cout<<deq1.size()<<endl;
   printDequeInt(deq1);


   deque<int> deq2;
   cout<<deq2.size()<<endl;
   deq2.resize(100);
   deq2=deq1;
   cout<<deq2.size()<<endl;
   printDequeInt(deq2);
   deq2.insert(deq2.end(),4,888);
   cout<<deq2.size()<<endl;
   printDequeInt(deq2);
   deq2.insert(deq2.end(),deq1.begin(),deq1.end());
   cout<<deq2.size()<<endl;
   printDequeInt(deq2);

   deq2.swap(deq1);
   cout<<"deq2的大小:"<<deq2.size()<<" deq1的大小:"<<deq1.size()<<endl;
   printDequeInt(deq2);
   printDequeInt(deq1);

   /*
   deque<int> deq2;
   cout<<deq2.size()<<endl;
   deq2.resize(100);
   deq2(deq1);
   cout<<deq2.size()<<endl;
   printDequeInt(deq2);
   deq2(4,888);
   cout<<deq2.size()<<endl;
   printDequeInt(deq2);
   deq2(deq1.begin(),deq1.end());
   cout<<deq2.size()<<endl;
   printDequeInt(deq2);

   deq2.swap(deq1);
   cout<<deq2.size()<<deq1.size()<<endl;
   printDequeInt(deq2);
   printDequeInt(deq1);
   */


}

int main()
{
    test();
    return 0;
}

输出结果:

tips:deq的构造函数不能直接对deq初始化

deque(begin,end);//将[begin,end)区间的数据拷贝给自己,不能这样初始化,可以使用insert(deque,begin,end);
 * deque(num,element);//将num个element数据拷贝给自己,调用不适用,可以使用deque(deque.end(),num,element);
 * deque(cons deque &deque);//拷贝构造函数,在deque不适合用(),可以使用=,即deque(自己)=deque;

deque的API (二)

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

//自定义一个遍历deque容器的方法
void printDequeInt(deque<int> &d){
    deque<int>::iterator it=d.begin();
    for(;it!=d.end();it++){
        //*it表示取值,即*it==int(某一个值)
        cout<<*it<<" ";
    }
    cout<<endl;//容器内所有数据遍历之后输出换行
}


}

void test1(){
    /*deque的数据存取
     * at(idx);//返回索引idx所指的数据,如果idx越界,抛出out_of_range
     * operator[idx];//越界不报错
     * front();//返回第一个数据
     * back();//返回最后一个数据
     *
     * deque的插入操作
     * insert(position,element);//在position位置上插入element元素
     * insert(position,n,element);//在position位置上插入n个element元素
     * inseret(position,begin,end);//在position位置上插入[begin,end)区间的元素
     *
     * deque的删除操作
     * clear();//删除所有数据
     * erase(begin,end);//删除[begin,end)区间的元素
     * erase(position);//删除position位置上的元素
     */
    deque<int> deq1;
    deq1.push_back(100);
    deq1.push_back(200);
    deq1.push_front(99999);
    printDequeInt(deq1);
    cout<<deq1.size()<<endl;

    for(unsigned int i=0;i<deq1.size();i++){
        cout<<deq1.at(i)<<" ";//越界抛出异常
        //cout<<deq1[i]<<" ";//越界不抛出异常

    }
    cout<<endl;
    deq1.insert(deq1.begin()+1,3,88888888);
    printDequeInt(deq1);
    cout<<deq1.size()<<endl;

    deq1.erase(deq1.begin());
    printDequeInt(deq1);
    cout<<deq1.size()<<endl;

    cout<<deq1.back()<<" "<<deq1.front()<<endl;

    for(unsigned int i=0;i<deq1.size()+1;i++){
        cout<<deq1.at(i)<<" ";//越界抛出异常
        //cout<<deq1[i]<<" ";//越界不抛出异常

    }
    cout<<endl;
}

int main()
{
    test1();
    return 0;
}

第一个输出结果:

第二个输出结果:

tips:根据结果可知,双端动态数组deq1调用at方法,如果数据访问越界,就会抛出异常,而以数组的方式则不会抛出异常(第二个输出结果)

vector容器和deque容器的应用:

案例:学校举办一场篮球比赛,有五名选手ABCDE,十个评委,每一个评委都会给这五名选手分别打分,去除最高分和最低分,取平均分为五名选手的最终得分,平均分最高的为冠军,第二名亚军,第三名季军。

设计方法:1、创建五名选手,放到vector容器

2、遍历vector容器,取出每一个选手让10名评委打分,10个评委打的分数放进deque容器

3、sort算法对deque容器的分数排序并用pop_back和pop_front方法去掉最高分和最低分

4、deque容器遍历一遍,累加分数/deque.size(),获取平均分

5、对每一个人的平均分比较,筛选出冠军、亚军、季军

案例输出:

#include <iostream>
#include<string>
#include<vector>
#include<time.h>
#include<deque>
#include<algorithm>

using namespace std;

class Person
{

    friend void playGame(vector<Person> &v);
    friend void showPersonScore(vector<Person> &v);
private:
    string name;
    double score;

public:
    Person() {}
    Person(string name,double score){
        this->name=name;
        this->score=score;

    }
};

void createPersonToVector(vector<Person> &v){
    string tmpName="ABCDE";
    int i=0;
    for(i=0;i<5;i++){
        string name="选手";
        name+=tmpName[i];
        v.push_back(Person(name,0.0));
    }

}

void playGame(vector<Person> &v){
    //设置随机数种子
    srand(time(NULL));
    //逐个选手参加比赛
    vector<Person>::iterator it=v.begin();
    for(;it!=v.end();it++){
        //设置deque容器,把10个评委打分放进去
        deque<int> d;
        int i=0;
        for(;i<10;i++){
            //使用rand方法产生随机数,模拟10个评委打分
            d.push_back(rand()%41+60);//限制分数最低60,最高100

        }
        //sort方法排序并去掉最低分和最高分
        sort(d.begin(),d.end());
        d.pop_back();
        d.pop_front();

        //accumulate方法求和
        int sum=accumulate(d.begin(),d.end(),0);
        //求平均分
        (*it).score=(double)sum/d.size();
    }

}

void showPersonScore(vector<Person> &v){


    sort(v.begin(),v.end(),[](const Person &a,const Person &b){
        return a.score>b.score;
    });
    //输出排序后的结果
    cout<<"冠军:"<<v[0].name<<",得分:"<<v[0].score<<endl;
    cout<<"亚军:"<<v[1].name<<",得分:"<<v[1].score<<endl;
    cout<<"季军:"<<v[2].name<<",得分:"<<v[2].score<<endl;

    //遍历所有选手和得分结果
    cout<<"所有选手和得分公示结果如下:"<<endl;
    vector<Person>::iterator it=v.begin();
    for(;it!=v.end();it++){
        cout<<"选手:"<<(*it).name<<",得分:"<<(*it).score<<endl;
    }
}

int main()
{
    //将五名选手放进vectr容器
    vector<Person> v;
    createPersonToVector(v);
    //五名选手参加比赛
    playGame(v);
    //遍历选手成绩
    showPersonScore(v);
    return 0;
}

执行第一次程序,使用随机数输出结果:

执行第二次程序,使用随机数输出结果:

tips:每一次输出的结果是随机的,这里的随机是依赖srand和rand方法,严格来说不算真正的随机,只能是模拟随机

总结:

vector容器和deque容器的区分点:

1、vector 单端动态数组 空间连续,deque 双端动态数组 空间分段连续

2、vector 有容量的概念 deque容器没有容量的概念

3、vector 一端操作数据,deque双端操作数据(常数项时间)

4、vector和deque都是随机访问迭代器

tips:合适的场景选用合适的容器,才是最佳的选择,而不是选择一个你所擅长的容器或者你所喜欢的容器

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值