zoukankan      html  css  js  c++  java
  • 7.5 C++基本序列式容器

    参考:http://www.weixueyuan.net/view/6402.html

    总结:

      vector可以理解为可以在两端插入、删除数据的数组,它提供了丰富的成员函数,用于操作数据。

        begin()返回的是一个迭代器,如果容器不为空,则返回的迭代器指向容器的第一个元素;如果容器为空,则返回的迭代器指向容器尾部之后的位置。

        end()函数同样返回的是一个迭代器,该迭代器指向的是容器尾部之后的位置。当容器为空时,begin()函数和end()函数都指向同一个位置。

        调用insert函数时,如果不是在容器尾部插入元素,则需要将所插入位置以后的元素都向后移一位,然后再将需要插入的元素插入到当前位置。

        erase函数删除容器中的元素

      vector和deque不同。vector说到底是个数组,在非尾部插入元素都需要移动其它元素,

      而deque则不同,它是一个可以操作数组头部和尾部的数组,因此在头部或尾部插入或删除数据,其处理效率都是一样的。

      当我们需要频繁在头部和尾部插入或删除数据,则deque优于vector。

      通常每定义一个容器,就会有一个与容器数据类型相关的迭代器。

      如果我们不需要修改容器中的元素,仅仅只是进行访问的话,则可以定义为const_iterator。

      当我们需要获得当前迭代器所指的元素时,我们可以用取址操作符“*”来操作迭代器,“*iter”就为迭代器所指向的元素。

      list并没有重载下标操作符,因而不能根据下标进行直接访问。

      list容器是一个双向链表,因此在容器中的任何位置插入元素,都不需要移动其它元素,因此执行效率是稳定的。

    ------------------

    我们以vector、deque和list为例介绍基本序列式容器。我们先来看一个关于vector的例子。

    例1:

    #include <iostream>
    #include <vector>
    using namespace std;
    
    int main()
    {
        vector< int > num;
        num.push_back( 50 );
        num.insert(num.begin(), 10);
        num.insert(num.end(), 20);
        num.push_back( 60 );
        num.push_back( 40 );
        cout << num.size() << endl;
        for(int i = 0; i < num.size(); i++)
            cout << num[i] << " ";
        cout << endl;
        num.erase(num.begin());
        cout << num.size() << endl;
        for(int i = 0; i < num.size(); i++)
            cout<< num[i] <<" ";
        cout << endl;
        return 0;
    }

    vector可以理解为可以在两端插入、删除数据的数组,它提供了丰富的成员函数,用于操作数据。在本例中我们加入了头文件vector,在使用vector时必须包含该头文件。

    我们接着来看一下主函数。在主函数中我们定义了一个vector类的int型实例num,需要注意的是我们并没有指定实例的大小,因为vector是可以根据需求自动调整大小的,这一点跟数组不同。接下来我们调用函数push_back,该函数时在vector实例num的最后添加一个元素,因为一开始定义的时候为空,因此此时的num中只包含一个元素50。

    之后我们再调用insert函数,该函数可以在指定位置插入元素。在insert参数中,我们分别调用了begin和end函数,这两个函数分别用来访问num实例的头部和尾部。begin()返回的是一个迭代器,如果容器不为空,则返回的迭代器指向容器的第一个元素;如果容器为空,则返回的迭代器指向容器尾部之后的位置。end()函数同样返回的是一个迭代器,该迭代器指向的是容器尾部之后的位置。当容器为空时,begin()函数和end()函数都指向同一个位置,当容器有一个元素的时候,begin()函数指向第一个元素的位置,end()函数则指向第一个元素之后的位置。调用insert函数时,如果不是在容器尾部插入元素,则需要将所插入位置以后的元素都向后移一位,然后再将需要插入的元素插入到当前位置。例如我们要在开头插入一个元素,则需要将容器现有的元素都向后移动一个位置,然后再将元素插入到第一个位置,因此vector在非尾部位置插入元素,其效率不高。在主函数中调用两次insert函数之后,此时的容器num中的元素有:10,50,20。

    之后又调用了两个push_back函数,在容器尾部插入了两次数据。此时容器中的数据按顺序依次为:10,50,20,60,40。

    之后调用size函数,返回容器的大小,因为此时容器中包含五个元素,因此返回值为5。接下来我们将容器中的元素一一打印出来,我们可以通过下标操作符访问容器中的元素,打印结果为:10,50,20,60,40。

    接下来调用erase函数删除容器中的元素,删除位置是容器第一个元素,删除之后,该位置就会空出,此时后面的元素需要全部向前移动一个位置。此时容器中的元素按顺序一次为:50,20,60,40。

    例2:

    #include <iostream>
    #include <deque>
    using namespace std;
    
    int main()
    {
        deque< int > num;
        num.push_back(50);
        num.insert(num.begin(), 10);
        num.insert(num.end(), 20);
        num.push_back(60);
        num.push_back(40);
        cout<<num.size()<<endl;
        for(int i=0; i < num.size(); i++)
            cout<<num[i]<<" ";
        cout<<endl;
        num.erase(num.begin());
        cout<<num.size()<<endl;
        for(int i=0; i < num.size(); i++)
            cout<<num[i]<<" ";
        cout<<endl;
        return 0;
    }

    我们将例1中的vector换成deque,运行程序我们发现两个程序的运行结果完全相同。是不是vector和deque相同呢?其实不是的,vector说到底是个数组,在非尾部插入元素都需要移动其它元素,而deque则不同,它是一个可以操作数组头部和尾部的数组,因此在头部或尾部插入或删除数据,其处理效率都是一样的。当我们需要频繁在头部和尾部插入或删除数据,则deque优于vector。

    例3:

    #include <iostream>
    #include <string>
    #include <list>
    using namespace std;
    
    int main()
    {
        list< string > str;
        str.insert( str.begin(), "A" );
        str.insert( str.begin(), "B" );
        str.insert( str.end(), "C" );
        str.insert( str.end(), "D" );
        str.insert( str.begin(), "E" );
        str.insert( str.begin(), "F" );
        list< string >::iterator iter;
        for(iter = str.begin(); iter != str.end(); iter++)
            cout<< * iter <<endl;
        str.reverse();
        for(iter = str.begin(); iter != str.end(); iter++)
            cout<< * iter <<endl;
        return 0;
    }

    在本例中我们定义了一个list容器string类型的实例str,之后我们先在容器中添加了6个string类型元素,为了遍历str容器,我们定义了一个迭代器iter。通常每定义一个容器,就会有一个与容器数据类型相关的迭代器,本例中定义了容器str,则它的对应的容器有:

    list < string >::iterator
    list< string >::const_iterator

    如果我们不需要修改容器中的元素,仅仅只是进行访问的话,则可以定义为const_iterator。


    为了从头到尾遍历容器,我们先将迭代器指向str.begin(),for循环的结束条件是str.end(),每次运行一遍循环体中的内容,迭代器自增一次,相当于指向下一个元素,我们之所以能够直接使用自增运算符,那是因为在容器的类中系统已经重载过了自增操作符。当我们需要获得当前迭代器所指的元素时,我们可以用取址操作符“*”来操作迭代器,“*iter”就为迭代器所指向的元素。在此程序中我们之所以没有按照vector和deque的方式,以下标进行访问容器中的元素,那是因为list并没有重载下标操作符,因而不能根据下标进行直接访问。

    在主函数中我们调用了reverse函数,对容器中的元素进行翻转,然后再次打印容器中的元素。

    list容器是一个双向链表,因此在容器中的任何位置插入元素,都不需要移动其它元素,因此执行效率是稳定的。

  • 相关阅读:
    C#编程(七十三)----------浅析C#中内存管理
    C#高级编程小结
    C#编程(七十二)----------DynamicObject和ExpandoObject
    C#编程(七十一)----------DLR ScriptRuntime
    C#编程(七十)----------dynamic类型
    C#编程(六十九)----------DLR简介
    C#编程(六十八)----------LINQ小结
    C#编程(六十七)----------LINQ提供程序
    C#编程(六十六)----------表达式树总结
    python 显示上午下午
  • 原文地址:https://www.cnblogs.com/yongpan/p/7966629.html
Copyright © 2011-2022 走看看