C++STL序列式容器---vector和list常用的接口用法以及vector和list的区别

序列式容器


一. vector :
vector采用一段连续的内存来存储其元素,向vector添加元素的时候,如果容量不足,vector便会重新malloc一段更大的 
内存,然后把原内存中的数据memcpy到新的内存中,并free原内存块,然后将新元素加入。 
vector的元素插入性能跟以下几个要素关系重大:

    1. 插入的位置

       头部插入:将所有元素后移,然后将新元素插入
       中间插入:将插入点后面的元素后移,然后插入新元素  
       尾部插入:将新元素直接插入尾部

       总结:
            尾部插入无疑是最快的,头部插入最慢,中间插入次之,(尾部插入>中间插入>头部插入)
            慢的原因:在于插入前要移动后面的所有元素。删除元素也是同样的道理。

   2. 保留空间大小

      如果插入元素是,空间不足将导致重新malloc以及一系列的内存拷贝。如果使用者能对容量有预期, 
      那么采用reserve()来预先分配内存,将大大的提高性能。 

  综述,vector适用于尾部插入,但是此时无法兼顾查找的性能,因为二分查找的vector要求重新排序, 
  或者要求vector在插入时就保持有序,这样就无法做到尾部插入。

  但是vector作为动态数组的替代,已经足够优秀。
常用接口:

头文件: #include <vector>

//1.定义和初始化

     vector<int> vec1;                           // 默认初始化,vec1为空
     vector<int> vec2(vec1);                     // 使用vec1初始化vec2
     vector<int> vec3(vec1.begin(),vec1.end());  // 使用vec1初始化vec2
     vector<int> vec4(10);                       // 10个值为0的元素
     vector<int> vec5(10,4);                     // 10个值为4的元素

//2.常用操作方法 

     vec1.push_back(100);                       // 尾部添加元素
     int size = vec1.size();                    // 元素个数
     bool isEmpty = vec1.empty();               // 判断是否为空
     cout<<vec1[0]<<endl;                       // 取得第一个元素
     vec1.insert(vec1.end(),5,3);               // 从vec1.back位置插入5个值为3的元素
     vec1.pop_back();                           // 删除末尾元素
     vec1.erase(vec1.begin(),vec1.begin()+2);   // 删除vec1[0]-vec1[2]之间的元素,不包括vec1[2](左闭右开)
     cout<<(vec1==vec2)?true:false;              // 判断是否相等==、!=、>=、<=...
     vector<int>::iterator iter = vec1.begin();          // 获取迭代器首地址
     vector<int>::const_iterator c_iter = vec1.begin();   // 获取const类型迭代器
     vec1.clear();                                // 清空元素

//3.遍历

    // 1. 下标法
    int length = vec1.size();
    for(int i=0;i<length;i++)
    {
       cout<<vec1[i]<<" ";
    }
    cout<<endl;

    // 2. 迭代器法
    vector<int>::iterator iter = vec1.begin();
    for(;iter != vec1.end();iter++)
    {
       cout<<*iter<<" ";
    }
     cout<<endl;
用法一:
void test2()
{
    vector<int>  V1(10,1);                     // 10个值为1的元素
    vector<int>  V2(V1);                       // 使用V1初始化V2  
    vector<int>  V3(V1.begin(),V1.end());      // 使用V1初始化V3


    cout<<(V2 == V3)?true:false;               // 结果为1(为真)
    cout<<endl;

    vector<int> ::iterator iter = V3.begin();
    for( ; iter < V3.end(); iter++ )
    {
        cout<<*iter<<" ";
    }
    cout<<endl;// 结果为 1 1 1 1 1 1 1 1 1 1 
}
用法二:
#include <iostream>
#include <vector>
using namespace std;

int main()
{
    vector<int> V1;               // 初始化
    V1.push_back(1);              // 尾部插入
    V1.push_back(2);              // 尾部插入
    V1.insert(V1.end(),5,3);      // 从尾部插入5个3


    // 遍历:1. 下标法  2. 迭代器法

    // 1. 下标法

    int Size = V1.size();         // 元素的总个数
    for(int i = 0; i < Size; i++)
    {
        cout<<V1[i]<<" ";
    }
    cout<<endl; // 结果为 1 2 3 3 3 3 3

    // 2. 迭代器法----正向迭代器

    vector<int> ::iterator iter = V1.begin();
    for( ; iter < V1.end(); iter++ )
    {
        cout<<*iter<<" ";
    }
    cout<<endl;// 结果为 1 2 3 3 3 3 3

    // 2. 迭代器法----反向迭代器

    vector<int> ::reverse_iterator riter = V1.rbegin();
    for( ; riter < V1.rend(); riter++ )
    {
        cout<<*riter<<" ";
    }
    cout<<endl;// 结果为 3 3 3 3 3 2 1
    return 0;
}
用法三:
void test3()
{
    vector<int>  V1(10,1);                     // 10个值为1的元素

    V1.erase(V1.begin(),V1.begin()+2);         // 结果:8个1(2代表的不是下标,而是一个左闭右开的区间)

    V1.pop_back();                             // 尾删 结果:7个1

    //V1.resize(3,2); // 结果:3个1
    //V1.resize(8,2); // 结果:7个1 1个2
    V1.resize(8); // 结果:7个1 1个0(默认初始化为0)
    vector<int> ::iterator iter = V1.begin();
    for( ; iter < V1.end(); iter++ )
    {
        cout<<*iter<<" ";
    }
    cout<<endl;// 结果为:7个1

    V1.clear();                                // 清空
    cout<<V1.empty()<<endl;                    // 为真:1
}
二. list:

list很简单,它就是个双向链表。每一个节点的内存都是独立的。 

理论上,其优点是:任何位置的插入删除元素操作都是非常快的。
        缺点是:不适合用于元素的查找,因为他只能是扫描的方式。 

单链表和双向链表的优缺点:

      1. 结构上而言:双向链表复杂,占用的空间大一点
      2. 插入和删除:双向链表简单,更实用(因为在删除和插入时,需要找到前一个prev,而双向链表不用找)
      3. 时间复杂度:双向链表O(1);单链表O(n)

既然双向链表的优点很多,为什么单链表也很重要?

      因为:单链表会在哈希表的拉链法中会用到,还有图中会用到,应用还是很广的。 
           如果单用链表时,双向链表会比较好。
常用的接口:
头文件: #include <list>

// 1.定义和初始化

    list<int> lst1;                           // 创建空list
    list<int> lst2(3);                        // 创建含有三个元素的list
    list<int> lst3(3,2);                      // 创建含有三个元素为2的list
    list<int> lst4(lst2);                     // 使用lst2初始化lst4
    list<int> lst5(lst2.begin(),lst2.end());  // 同lst4

// 2.常用操作方法

    lst1.push_back(10);                    // 末尾添加值
    lst1.pop_back();                       // 删除末尾值
    lst1.begin();                          // 返回首值的迭代器
    lst1.end();                            // 返回尾值的迭代器
    lst1.clear();                          // 清空值
    bool isEmpty1 = lst1.empty();          // 判断为空
    lst1.erase(lst1.begin(),lst1.end());   // 删除元素
    lst1.front();                          // 返回第一个元素的引用
    lst1.back();                           // 返回最后一个元素的引用
    lst1.insert(lst1.begin(),3,2);         // 从指定位置插入个3个值为2的元素
    lst1.rbegin();                         // 返回第一个元素的前向指针
    lst1.remove(2);                        // 删除链表中所有为2的元素
    lst1.reverse();                        // 反转
    lst1.size();                           // 含有元素个数
    lst1.sort();                           // 排序
    lst1.unique();                         // 删除相邻重复元素

    //3.遍历
    //迭代器法
    list<int>::iterator iter = lst1.begin();
    for(;iter != lst1.end();iter++)
    {
       cout<<*iter<<" ";
    }
     cout<<endl;
用法一:初始化
#include <iostream>
#include <list>
using namespace std;

void test1()
{
    list<int> lst1;                           // 创建空list
    list<int> lst2(3);                        // 创建含有三个元素的list(默认初始化为0)
    list<int> lst3(3,2);                      // 创建含有三个元素为2的list
    list<int> lst4(lst2);                     // 使用lst2初始化lst4
    list<int> lst5(lst2.begin(),lst2.end());  // 同lst4

    cout<<(lst4 == lst5)?true:false;          // 判断lst4和lst5是否相同,结果为:1(为真)
    cout<<endl;

    list<int>::iterator iter = lst3.begin();
    for(;iter != lst3.end();iter++)
    {
       cout<<*iter<<" ";
    }
     cout<<endl; // 结果为:2 2 2
}

int main()
{
    test1();
    return 0;
}
用法二:头插头删、尾插尾删
void test2()
{
    list<int> l1;

    l1.push_back(1);
    l1.push_back(2);
    l1.push_back(3);

    list<int>::iterator iter1 = l1.begin();
    for(;iter1 != l1.end();iter1++)
    {
       cout<<*iter1<<" ";
    }
    cout<<endl; // 结果为:1 2 3

    l1.pop_back();   // 结果为:1 2
    l1.push_back(3); // 尾插3
    l1.pop_front();  // 结果为:2 3
    l1.push_front(1); // 头插1
    l1.insert(l1.end(),2,4); // 在指定位置插入2个4

    list<int>::iterator iter2 = l1.begin();
    for(;iter2 != l1.end();iter2++)
    {
       cout<<*iter2<<" ";
    }
    cout<<endl; // 结果为:1 2 3 4 4
} 
用法三:unique( ) & sort( )
1. unique( ):只是将相邻的相同元素删除
void test2()
{
    list<int> l1;

    l1.push_back(1);
    l1.push_back(1);
    l1.push_back(1);
    l1.push_back(2);
    l1.push_back(1);
    l1.push_back(3);

    l1.unique(); 

    list<int>::iterator iter1 = l1.begin();
    for(;iter1 != l1.end();iter1++)
    {
       cout<<*iter1<<" ";
    }
    cout<<endl; // 结果:1 2 1 3
} 
去重:先排序sort( ),再unique( )
void test2()
{
    list<int> l1;

    l1.push_back(1);
    l1.push_back(1);
    l1.push_back(1);
    l1.push_back(2);
    l1.push_back(1);
    l1.push_back(3);

    l1.sort();
    l1.unique(); 

    list<int>::iterator iter1 = l1.begin();
    for(;iter1 != l1.end();iter1++)
    {
       cout<<*iter1<<" ";
    }
    cout<<endl; // 结果:1 2 3
} 
用法四: 逆置:reverse( ) || 反向迭代器
1. reverse( )
void test2()
{
    list<int> l1;

    l1.push_back(1);
    l1.push_back(2);
    l1.push_back(3);

    l1.reverse(); 

    list<int>::iterator iter1 = l1.begin();
    for(;iter1 != l1.end();iter1++)
    {
       cout<<*iter1<<" ";
    }
    cout<<endl; // 结果:3 2 1
} 
2. 反向迭代器
void test2()
{
    list<int> l1;

    l1.push_back(1);
    l1.push_back(2);
    l1.push_back(3);

    list<int>::reverse_iterator iter1 = l1.rbegin();
    for(;iter1 != l1.rend();iter1++)
    {
       cout<<*iter1<<" ";
    }
    cout<<endl; // 结果:3 2 1
} 
三 . vector和list的区别:

相同点:
      1. 都可以存储一组类型相同的元素
      2. 尾部插入和删除,性能差不多
不同点:

      1. 存储顺序:

         vector :是顺序表,表示的是一块连续的内存,元素被顺序存储;
           list : 是双向链表,在内存中不一定连续。

      2. 扩容的开销:

         vector : 当数值内存不够时,vector会重新申请一块足够大的连续内存,把原来的数据拷贝到新的内存里面
           list : 因为不用考虑内存的连续,因此新增开销比vector小。

      3. 头部或者中间的插入和删除: 

          vectorvector需要进行元素的移动
            list : 性能比vector4. 随机访问:

         vector : 直接通过下标就可以访问,时间复杂度为O(1)
           list : 需要遍历,时间复杂度为O(n)
           所以:vector的随机访问效率更高


总而言之:
         1. 已知需要存储的元素时,vector要好
         2. 如果需要任意位置插入元素,list要好
  • 0
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值