C++中STL常用容器的优点和缺点

北战南征 提交于 2020-02-06 05:59:06

【转】C++中STL常用容器的优点和缺点

 

我们常用到的STL容器有vector、list、deque、map、multimap、set和multiset,它们究竟有何区别,各自的优缺点是什么,为了更好的扬长避短,提高程序性能,在使用之前需要我们了解清楚。

verctor

vector类似于C语言中的数组,它维护一段连续的内存空间,具有固定的起始地址,因而能非常方便地进行随机存取,即 [] 操作符,但因为它的内存区域是连续的,所以在它中间插入或删除某个元素,需要复制并移动现有的元素。此外,当被插入的内存空间不够时,需要重新申请一块足够大的内存并进行内存拷贝。值得注意的是,vector每次扩容为原来的两倍,对小对象来说执行效率高,但如果遇到大对象,执行效率就低了。

#include<iostream>
#include<cstdio>
#include<vector>
using namespace std;
vector<int> a;//大概能开3e7个vector
vector<int> b;
int main(){
    int x=10;
    a.push_back(x);//插到末尾
    a.push_back(x=20);
    a.insert(a.end(),x=40); //相当于push_back
    a.insert(a.begin()+1,30); //插到任何一个位置
    a.insert(a.end(),3,2); //插入3个2
//    a.insert(4,50);  这样不合法,只能使用迭代器

    for(int i=0;i<a.size();i++) //可以通过下标访问
    cout<<a[i]<<" ";puts("");
    
    a.erase(a.begin()+1); //可以删掉某个元素
//    a.erase(30); 不能删除特定元素
    
    for(vector<int>::iterator it=a.begin();it!=a.end();it++) //可以通过迭代器访问
    cout<<*it<<" ";puts("");
    
    a.swap(b); //与另一个vector交换
    cout<<b.size()<<endl; // 大小
    cout<<a.empty(); //是否为空
    b.clear(); // 清空
}

 

 

 

list

list类似于C语言中的双向链表,它通过指针来进行数据的访问,因此维护的内存空间可以不连续,这也非常有利于数据的随机存取,因而它没有提供 [] 操作符重载。

#include<iostream>
#include<cstdio>
#include<list>
using namespace std;
list<int> a,b;
int main(){
    a.assign(3,2);//a 由3个2组成
    a.insert(a.begin(),3);
    a.push_back(1);
    b.assign(a.begin(),a.end());//b 由a组成
    
    a.assign(2,0);
    b.merge(a);//默认排成升序 若b小放前面,
    a.assign(2,4);
    b.merge(a);//否则放后面
    cout<<a.empty()<<endl;//赋完变空
    
    for(list<int>::iterator it=b.begin();it!=b.end();it++)
    cout<<*it<<" ";puts("");
    
    b.erase(b.begin());
    b.reverse();//反转
    
    for(list<int>::iterator it=b.begin();it!=b.end();it++)
    cout<<*it<<" ";puts("");
}

 

deque

deque类似于C语言中的双向队列,即两端都可以插入或者删除的队列。queue支持 [] 操作符,也就是支持随机存取,而且跟vector的效率相差无几。它支持两端的操作:push_back,push_front,pop_back,pop_front等,并且在两端操作上与list的效率
也差不多。或者我们可以这么认为,deque是vector跟list的折中。

 

map

map类似于数据库中的1:1关系,它是一种关联容器,提供一对一(C++ primer中文版中将第一个译为键,每个键只能在map中出现一次,第二个被译为该键对应的值)的数据处理能力,这种特性了使得map类似于数据结构里的红黑二叉树。

multimap

multimap类似于数据库中的1:N关系,它是一种关联容器,提供一对多的数据处理能力。

 

set

set类似于数学里面的集合,不过set的集合中不包含重复的元素,这是和vector的第一个区别,第二个区别是set内部用平衡二叉树实现,便于元素查找,而vector是使用连续内存存储,便于随机存取。

#include<iostream>
#include<cstdio>
#include<set>
using namespace std;
set<int> a,b;
int main(){
    a.insert(a.begin(),30);
    a.insert(a.end(),12); //加不加头尾没有什么意义
    //set是一个内部自动升序排序的容器
    a.insert(2);
    a.insert(3);
    a.insert(5);
    a.insert(10);
    
    a.erase(30); //可以删掉特定元素
    a.erase(a.begin()); //可以删头尾

    for(set<int>::iterator it=a.begin();it!=a.end();it++) //只能通过迭代器访问
    cout<<*it<<" ";puts("");
    
    cout<<"lower_bound:6 "<<*a.lower_bound(6)<<endl;//支持lower_bound 返回迭代器
    cout<<"upper_bound:5 "<<*a.upper_bound(6)<<endl;//upper_bound 同理
    cout<<"find:5 "<<*a.find(5)<<endl; // 支持查找某个元素 返回迭代器

}

 

 

 

multiset

multiset类似于数学里面的集合,集合中可以包含重复的元素。

小结

在实际使用过程中,到底选择这几种容器中的哪一个,应该根据遵循以下原则:

1、如果需要高效的随机存取,不在乎插入和删除的效率,使用vector;

2、如果需要大量的插入和删除元素,不关心随机存取的效率,使用list;

3、如果需要随机存取,并且关心两端数据的插入和删除效率,使用deque;

4、如果打算存储数据字典,并且要求方便地根据key找到value,一对一的情况使用map,一对多的情况使用multimap;

5、如果打算查找一个元素是否存在于某集合中,唯一存在的情况使用set,不唯一存在的情况使用multiset。

我们常用到的STL容器有vector、list、deque、map、multimap、set和multiset,它们究竟有何区别,各自的优缺点是什么,为了更好的扬长避短,提高程序性能,在使用之前需要我们了解清楚。

verctor

vector类似于C语言中的数组,它维护一段连续的内存空间,具有固定的起始地址,因而能非常方便地进行随机存取,即 [] 操作符,但因为它的内存区域是连续的,所以在它中间插入或删除某个元素,需要复制并移动现有的元素。此外,当被插入的内存空间不够时,需要重新申请一块足够大的内存并进行内存拷贝。值得注意的是,vector每次扩容为原来的两倍,对小对象来说执行效率高,但如果遇到大对象,执行效率就低了。

#include<iostream>
#include<cstdio>
#include<vector>
using namespace std;
vector<int> a;//大概能开3e7个vector
vector<int> b;
int main(){
    int x=10;
    a.push_back(x);//插到末尾
    a.push_back(x=20);
    a.insert(a.end(),x=40); //相当于push_back
    a.insert(a.begin()+1,30); //插到任何一个位置
    a.insert(a.end(),3,2); //插入3个2
//    a.insert(4,50);  这样不合法,只能使用迭代器

    for(int i=0;i<a.size();i++) //可以通过下标访问
    cout<<a[i]<<" ";puts("");
    
    a.erase(a.begin()+1); //可以删掉某个元素
//    a.erase(30); 不能删除特定元素
    
    for(vector<int>::iterator it=a.begin();it!=a.end();it++) //可以通过迭代器访问
    cout<<*it<<" ";puts("");
    
    a.swap(b); //与另一个vector交换
    cout<<b.size()<<endl; // 大小
    cout<<a.empty(); //是否为空
    b.clear(); // 清空
}

 

 

 

list

list类似于C语言中的双向链表,它通过指针来进行数据的访问,因此维护的内存空间可以不连续,这也非常有利于数据的随机存取,因而它没有提供 [] 操作符重载。

#include<iostream>
#include<cstdio>
#include<list>
using namespace std;
list<int> a,b;
int main(){
    a.assign(3,2);//a 由3个2组成
    a.insert(a.begin(),3);
    a.push_back(1);
    b.assign(a.begin(),a.end());//b 由a组成
    
    a.assign(2,0);
    b.merge(a);//默认排成升序 若b小放前面,
    a.assign(2,4);
    b.merge(a);//否则放后面
    cout<<a.empty()<<endl;//赋完变空
    
    for(list<int>::iterator it=b.begin();it!=b.end();it++)
    cout<<*it<<" ";puts("");
    
    b.erase(b.begin());
    b.reverse();//反转
    
    for(list<int>::iterator it=b.begin();it!=b.end();it++)
    cout<<*it<<" ";puts("");
}

 

deque

deque类似于C语言中的双向队列,即两端都可以插入或者删除的队列。queue支持 [] 操作符,也就是支持随机存取,而且跟vector的效率相差无几。它支持两端的操作:push_back,push_front,pop_back,pop_front等,并且在两端操作上与list的效率
也差不多。或者我们可以这么认为,deque是vector跟list的折中。

 

map

map类似于数据库中的1:1关系,它是一种关联容器,提供一对一(C++ primer中文版中将第一个译为键,每个键只能在map中出现一次,第二个被译为该键对应的值)的数据处理能力,这种特性了使得map类似于数据结构里的红黑二叉树。

multimap

multimap类似于数据库中的1:N关系,它是一种关联容器,提供一对多的数据处理能力。

 

set

set类似于数学里面的集合,不过set的集合中不包含重复的元素,这是和vector的第一个区别,第二个区别是set内部用平衡二叉树实现,便于元素查找,而vector是使用连续内存存储,便于随机存取。

#include<iostream>
#include<cstdio>
#include<set>
using namespace std;
set<int> a,b;
int main(){
    a.insert(a.begin(),30);
    a.insert(a.end(),12); //加不加头尾没有什么意义
    //set是一个内部自动升序排序的容器
    a.insert(2);
    a.insert(3);
    a.insert(5);
    a.insert(10);
    
    a.erase(30); //可以删掉特定元素
    a.erase(a.begin()); //可以删头尾

    for(set<int>::iterator it=a.begin();it!=a.end();it++) //只能通过迭代器访问
    cout<<*it<<" ";puts("");
    
    cout<<"lower_bound:6 "<<*a.lower_bound(6)<<endl;//支持lower_bound 返回迭代器
    cout<<"upper_bound:5 "<<*a.upper_bound(6)<<endl;//upper_bound 同理
    cout<<"find:5 "<<*a.find(5)<<endl; // 支持查找某个元素 返回迭代器

}

 

 

 

multiset

multiset类似于数学里面的集合,集合中可以包含重复的元素。

小结

在实际使用过程中,到底选择这几种容器中的哪一个,应该根据遵循以下原则:

1、如果需要高效的随机存取,不在乎插入和删除的效率,使用vector;

2、如果需要大量的插入和删除元素,不关心随机存取的效率,使用list;

3、如果需要随机存取,并且关心两端数据的插入和删除效率,使用deque;

4、如果打算存储数据字典,并且要求方便地根据key找到value,一对一的情况使用map,一对多的情况使用multimap;

5、如果打算查找一个元素是否存在于某集合中,唯一存在的情况使用set,不唯一存在的情况使用multiset。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!