C++中STL常用容器(vector、deque、list、map、set)一文带你了解

一、vector容器(向量)

vector属于序列容器,序列是对基本容器的一种改进,在保持其基础功能上增加一些我们需要的更为方便的功能。要求序列的元素必须是严格的线性顺序排序。因此序列中的元素具有确定的顺序,可以执行将值插入到特定位置、删除特定区间等操作。下面要说明的deque、list同样属于序列(也叫顺序)容器。vector是动态数组,在内存中具有连续的存储空间,支持快速随机访问。由于具有连续的存储空间,所以在插入和删除操作方面,效率比较慢。

/*
 * @Author: Stylle
 * @Date: 2020-08-23 14:53:32
 * @LastEditors: Stylle
 * @LastEditTime: 2020-08-23 16:40:27
 * @FilePath: \c-master\常用容器vector的使用.cpp
 */
#include <iostream>
#include <vector>
#include <algorithm>
// #include <list>
// #include <queue>
// #include <map>

using namespace std;
/* 遍历方式1 :迭代器的方式遍历*/
void PrintVector(vector<int> &v)
{
    /* 容器遍历:利用begin和end迭代器方式 */
    for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
    {
        cout << *it << " ";
    }
    cout << endl;
}
/* 遍历方式2 :size方式数组下标方式*/
void PrintVector_size(vector<int> &v)
{
    for (std::vector<int>::size_type i = 0; i != v.size(); i++)
    {
        cout << v[i] << " ";
    }
    cout << endl;
}
/* 遍历方式3 :平常使用更推荐auto,速度更快,需要C++11支持*/
void PrintVector_auto(vector<int> &v)
{
    for (auto const &value : v)
    {
        cout << value << " ";
    }
    cout << endl;
}

/* 遍历方式4 :如果在遍历的过程中需要更改其中的数据更推荐使用本方法,需要C++17支持*/
template <typename T>
void printer(const T &val)
{
    cout << val << " ";
}
void PrintVector_for_each(vector<int> &v)
{
    //#include <algorithm>使用需要包含
    for_each(v.cbegin(), v.cend(), printer<int>);
    cout << endl;
}

int main(int argc, char **argv)
{
    vector<int> v1; //初始化方式1:无初始值
    /* 容器赋值 */
    for (int i = 0; i < 10; i++)
    {
        v1.push_back(i * 10);
    }
    cout << "V1: ";
    PrintVector(v1);
    v1.pop_back(); //删除最后一位数据
    cout << "V1: ";
    PrintVector(v1);

    vector<int> v2(10, 1); //初始化方式2:赋值10个1
    cout << "V2: ";
    PrintVector(v2);

    v1.swap(v2); //交换两个容器的数据
    cout << "V1: ";
    PrintVector(v1);
    cout << "V2: ";
    PrintVector(v2);

    cout << "V1元素个数:" << v1.size() << endl;
    v1.insert(v1.begin() + 5, 2, 8); //在容器元素第五个的后面插入两个8
    cout << "V1: ";
    PrintVector(v1);

    v1.erase(v1.begin() + 5); //删除第五个元素
    cout << "V1: ";
    PrintVector(v1);

    v1.erase(v1.begin() + 5, v1.end()); //删除第五个元素到最后一个元素的数据
    cout << "V1: ";
    PrintVector(v1);

    int &vNum1 = v1.front(); //返回容器V1的第一个元素的引用
    //如果这里定义的不是&元素则无法更改v1的内容,而这里却可以
    //front、back与end、begin的区别在于返回的一个是引用一个是迭代器
    int &vNum2 = v1.back(); //返回容器V1的最后一个元素的引用

    if (!v1.empty())
    {
        v1.clear(); //如果不为空则清空容器
    }
    cout << "V1: ";
    PrintVector(v1);

    vector<int> v3;
    v3.resize(10, 5); //指定空间大小
    cout << "V3的容量 = " << v3.capacity() << endl;
    cout << "V3:";
    PrintVector_auto(v3);

    cout << "V3:";
    PrintVector_for_each(v3);

    reverse(v2.begin(), v2.end()); //逆序储存从开始位置到结束位置,需要包含头文件#include <algorithm>
    PrintVector_auto(v2);

    return 0;
}

vector容器特点:
(1) 一个动态分配的数组(当数组空间内存不足时,都会执行: 分配新空间-复制元素-释放原空间);
(2) 当删除元素时,不会释放限制的空间,所以向量容器的容量(capacity)大于向量容器的大小(size);
(3) 对于删除或插入操作,执行效率不高,越靠后插入或删除执行效率越高;
(4) 高效的随机访问的容器。

二、deque容器(队列)

deque容器类与vector类似,支持随机访问和快速插入删除,它在容器中某一位置上的操作所花费的是线性时间。与vector不同的是,deque还支持从开始端插入数据:push_front()。其余类似vector操作方法的使用。

/*
 * @Author: Stylle
 * @Date: 2020-08-23 17:07:22
 * @LastEditors: Stylle
 * @LastEditTime: 2020-08-23 17:45:36
 * @FilePath: \c-master\常用容器deque的使用.cpp
 */
#include <iostream>
#include <deque>
#include <algorithm>
using namespace std;

template <typename T>
void printer(const T &val)
{
    cout << val << " ";
}
//for_each遍历方式
void PrintVector_for_each(deque<int> &deq)
{
    //#include <algorithm>使用需要包含
    for_each(deq.cbegin(), deq.cend(), printer<int>);
    cout << endl;
}

int main(int argc, char **argv)
{
    deque<int> deq1;
    for (int i = 0; i < 5; i++)
    {
        deq1.push_back(i * 10);
    }
    //从队列前面插入数据
    for (int i = 25; i > 20; i--)
    {
        deq1.push_front(i * 10);
    }
    //从队列后面插入数据
    for (int i = 10; i > 5; i--)
    {
        deq1.push_back(i * 10);
    }
    PrintVector_for_each(deq1);
	//除了前后插入与vector容器使用方法相同
    return 0;
}

deque容器特点:
deque类似于C语言中的双向队列,即两端都可以插入或者删除的队列。queue支持 [] 操作符,也就是支持随机存取,而且跟vector的效率相差无几。它支持两端的操作:push_back,push_front,pop_back,pop_front等,并且在两端操作上与list的效率也差不多,在中间插入元素则会比较费时,因为必须移动中间其他的元素。或者我们可以这么认为,deque是vector跟list的折中。

三、list容器(列表)

list是STL实现的双向链表,与vector相比, 它允许快速的插入和删除,但是随机访问却比较慢。

/*
 * @Author: Stylle
 * @Date: 2020-08-23 16:31:50
 * @LastEditors: Stylle
 * @LastEditTime: 2020-08-23 19:09:07
 * @FilePath: \c-master\常用容器list的使用.cpp
 */
#include <iostream>
#include <list>
#include <algorithm>
using namespace std;

template <typename T>
void printer(const T &val)
{
    cout << val << " ";
}
void printList_for_each(list<int> &lst)
{
    for_each(lst.cbegin(), lst.cend(), printer<int>);
    cout << endl;
}

int main(int argc, char **argv)
{
    list<int> lst1;
    lst1.push_back(7);
    lst1.push_back(4);
    lst1.push_back(1);
    lst1.push_back(6);
    lst1.push_back(5);
    lst1.push_back(2);
    lst1.push_back(3);
    cout << "List1:";
    printList_for_each(lst1);

    list<int> lst2(lst1.begin(), lst1.end());
    cout << "List2:";
    printList_for_each(lst2);
    lst2.sort();
    cout << "List2:";
    printList_for_each(lst2);

    //相对于vector和deque新增的使用方法
    lst1.assign(lst2.begin(), lst2.end()); //分配值
    cout << "List1:";
    printList_for_each(lst1);

    //删除相同元素
    lst1.push_back(1);
    lst1.push_back(1);
    cout << "List1:";
    printList_for_each(lst1);

    lst1.remove(1); //删除列表中所有的1元素
    cout << "List1:";
    printList_for_each(lst1);

    lst1.push_front(2);
    lst1.push_front(2);
    lst1.push_front(2);
    cout << "List1:";
    printList_for_each(lst1);
    lst1.unique(); //删除相邻重复元素
    cout << "List1:";
    printList_for_each(lst1);

    //将 lst1中的首元素移到 lst1的最后
    lst1.splice(lst1.end(), lst1, lst1.begin());
    cout << "List1:";
    for (list<int>::iterator it = lst1.begin(); it != lst1.end(); it++)
    {
        cout << *it << " ";
    }
    cout << endl;

    //将 lst2中的所有元素移到 lst1的最后
    lst1.splice(lst1.end(), lst2);
    cout << "List1:";
    for_each(lst1.begin(), lst1.end(), [](int val) { cout << val << " "; });

	//这个我暂时没找到什么作用
    lst1.rbegin(); //返回第一个元素的前向指针
    return 0;
}

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

四、map容器

map属于关联容器与序列容器有着根本性的不同,序列容器的元素是按照在容器中的位置来顺序保存和访问的,而关联容器的元素是按关键元素来保存和访问的。关联容器支持高效的关键字查找与访问。两个主要的关联容器类型是map与set。

/*
 * @Author: Stylle
 * @Date: 2020-08-23 16:32:10
 * @LastEditors: Stylle
 * @LastEditTime: 2020-08-23 20:45:41
 * @FilePath: \c-master\常用容器map的使用.cpp
 */
#include <iostream>
#include <map>
#include <algorithm>

using namespace std;

int main(int argc, char **argv)
{
    map<int, string> map1;

    //常用操作方法
    map1[3] = "Three";                                   //添加元素
    map1.insert(map<int, string>::value_type(2, "Two")); //插入元素1
    map1.insert(pair<int, string>(4, "Four"));           //插入元素2
    map1.insert(make_pair<int, string>(1, "One"));       //插入元素3

    string str = map1[3];                               //根据key取得value,key不能修改
    map<int, string>::iterator iter_map = map1.begin(); //取得迭代器首地址
    int key = iter_map->first;                          //取得eky
    string value = iter_map->second;                    //取得value
    map1.erase(iter_map);                               //删除迭代器数据

    //遍历方式1
    for (map<int, string>::iterator it = map1.begin(); it != map1.end(); it++)
    {
        //遍历输出key  value
        cout << it->first << " " << it->second << endl;
    }
    map1.erase(3); //根据key删除value
    //遍历方式2:使用auto指针
    for (auto it = map1.begin(); it != map1.end(); it++)
    {
        cout << it->first << " " << it->second << endl;
    }

    return 0;
}

map容器特点:
map内部自建了一颗红黑二叉树,可以对数据进行自动排序,所以map里的数据都是有序的。

五、set容器

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

/*
 * @Author: Stylle
 * @Date: 2020-08-23 17:08:20
 * @LastEditors: Stylle
 * @LastEditTime: 2020-08-23 21:11:19
 * @FilePath: \c-master\常用容器set的使用.cpp
 */
#include <iostream>
#include <set>
#include <algorithm>
#include <random>
#include <ctime>

using namespace std;

int main(int argc, char **argv)
{
    set<string> set1;
    set1.insert("one"); //第一种方法:直接添加
    set1.insert("two");

    set<string> set2;
    set2.insert(set1.begin(), set1.end()); //第二中方法:通过指针迭代器

    //迭代器遍历set容器
    cout << "Set2:";
    for (auto it = set2.begin(); it != set2.end(); it++)
    {
        cout << *it << " ";
    }
    cout << endl;

    set<int> set3;
    srand((unsigned)time(NULL));
    for (int i = 0; i < 10; i++)
    {
        set3.insert(rand() % 10);
    }
    cout << "Set3:";
    for (auto it = set3.begin(); it != set3.end(); it++)
    {
        cout << *it << " ";
    }
    cout << endl;

    if (!set3.count(6)) //存在,返回1,不存在,返回0
    {
        set3.insert(6);
    }
    set3.find(1); // 返回指向元素内容为1的指针
    cout << "Set3:";
    for (auto it = set3.begin(); it != set3.end(); it++)
    {
        cout << *it << " ";
    }
    cout << endl;

    return 0;
}

set容器特点:
储存同一类型的数据元素(这点和vector、queue等其他容器相同),每个元素的值都唯一(没有重复的元素),根据元素的值自动排列大小(有序性),无法直接修改元素,高效的插入删除操作

六、四种容器遍历方式

其中比较重要的四种容器遍历方式:

/* 遍历方式1 :迭代器的方式遍历*/
void PrintVector(vector<int> &v)
{
    /* 容器遍历:利用begin和end迭代器方式 */
    for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
    {
        cout << *it << " ";
    }
    cout << endl;
}
/* 遍历方式2 :size方式数组下标方式*/
void PrintVector_size(vector<int> &v)
{
    for (std::vector<int>::size_type i = 0; i != v.size(); i++)
    {
        cout << v[i] << " ";
    }
    cout << endl;
}
/* 遍历方式3 :平常使用更推荐auto,速度更快,需要C++11支持*/
void PrintVector_auto(vector<int> &v)
{
    for (auto const &value : v)
    {
        cout << value << " ";
    }
    cout << endl;
}

/* 遍历方式4 :如果在遍历的过程中需要更改其中的数据更推荐使用本方法,需要C++17支持*/
template <typename T>
void printer(const T &val)
{
    cout << val << " ";
}
void PrintVector_for_each(vector<int> &v)
{
    //#include <algorithm>使用需要包含
    for_each(v.cbegin(), v.cend(), printer<int>);
    cout << endl;
}

七、总结

1、如需高效的随机存取,不在乎插入和删除的效率,使用vector;
2、如需大量的插入和删除元素,不关心随机存取的效率,使用list;
3、如需随机存取,并且关心两端数据的插入和删除效率,使用deque;
4、如果打算存储数据字典,并且要求方便地根据key找到value,一对一的情况使用map,一对多的情况使用multimap;
5、如果打算查找一个元素是否存在于某集合中,唯一存在的情况使用set,不唯一存在的情况使用multiset

  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: listvectormapset 是标准模板库(STL容器,分别用于不同的数据存储和访问方式。 1. list(链表)是一个双向链表,可以根据需要在任意位置插入和删除元素。它没有固定大小,可以根据需要动态分配内存。由于是链表结构,所以访问元素的效率较低,但在插入和删除操作上非常高效。 2. vector(动态数组)是一个支持随机访问的连续内存的数组,可以在尾部追加元素,并且能够根据需要动态分配内存。由于是连续内存,所以在访问元素时效率较高,但在插入和删除操作上相对较慢。 3. map(映射)是一个存储键值对的关联容器,通过键(key)来访问值(value)。它内部实现了一棵红黑树(平衡二叉树),保证了以对数时间复杂度执行查找、插入和删除操作。键是唯一的,可以用于对数据进行有序存储和遍历。 4. set(集合)是一个存储唯一元素的容器,内部实现也是基于红黑树。它自动对元素进行排序,并且保证元素的唯一性。可以利用set进行集合运算,如并集、交集、差集等。 这四种容器在不同的场景下有不同的使用方式: - 如果需要经常进行插入和删除操作,并且不关心元素的顺序,则可以选择使用list。 - 如果需要频繁访问元素,不需要进行插入和删除操作,或者只在尾部进行插入和删除,则可以选择使用vector。 - 如果需要按照键来查找和存储数据,则可以选择使用map。 - 如果需要存储唯一元素,并且需要对元素进行排序和集合运算,则可以选择使用set。 当然,具体的选择还会根据实际需求和性能要求进行权衡。 ### 回答2: listvectormapset都是C++标准模板库(STL容器,有着不同的特点和用法。 1. list(链表)是双向链表的实现,其的元素可以随意插入和删除。它没有随机访问的功能,只能通过迭代器进行跳跃式访问。它适用于需要频繁的插入和删除操作,并且不需要随机访问的场景。 2. vector(向量)是动态数组的实现,支持随机访问。在vector进行插入和删除操作需要移动其他元素,所以效率可能会低于list。但是它具有随机访问的能力,并且在末尾插入和删除元素的效率较高。vector适用于需要频繁的随机访问和在末尾插入删除元素的场景。 3. map(映射)是一种由键和值对组成的容器,通过键进行查找和插入操作。map内部通过红黑树实现,所以键值对是按照键的顺序来存储的。map的每个键是唯一的,如果插入一个已存在的键,将会覆盖原有的值。map适用于需要按键进行查找的场景。 4. set(集合)是一种由唯一元素组成的容器,元素按照一定的顺序进行存储。set内部也是通过红黑树实现,所以元素是按照一定顺序排列的。set的元素是唯一的,插入重复的元素将会被忽略。set适用于需要维护一组唯一元素并进行一些集合操作(如并集、交集等)的场景。 总结而言,list适用于频繁的插入和删除操作,vector适用于频繁的随机访问和末尾插入删除操作,而mapset适用于按键进行查找或维护一组唯一元素的场景。根据实际需求选择适当的容器可以提高代码的效率。 ### 回答3: listvectormapset是C++标准库常用容器类,它们分别用于不同的存储和访问数据的需求。 1. list(链表): - 使用双向链表实现,支持快速的插入和删除操作; - 不支持随机访问,只能通过迭代器依次访问元素; - 元素的添加和删除不会导致迭代器失效; - 适用于需要频繁插入和删除元素的场景,但对于随机访问的需求较少。 2. vector(动态数组): - 使用动态数组实现,支持随机访问; - 在尾部插入或删除元素的时间复杂度为常数,其他位置的插入和删除操作需要移动部分元素; - 内存分配是连续的,支持快速的随机访问; - 在需要经常随机访问元素的场景下使用较多。 3. map(有序映射): - 使用红黑树实现,基于键值对的有序映射; - 插入和查找操作的时间复杂度为对数时间复杂度; - map的元素按照键值的顺序进行排列; - 适用于需要进行查找操作的场景,如字典、索引等。 4. set(有序集合): - 使用红黑树实现,表示一个有序的不重复元素集合; - 插入和查找操作的时间复杂度为对数时间复杂度; - set的元素按照从小到大的顺序排列; - 适用于需要维护有序不重复元素的场景。 总结: - list适用于频繁插入和删除元素的场景; - vector适用于需要经常随机访问元素的场景; - map适用于需要查找操作的场景,按照键值有序排列; - set适用于需要维护有序不重复元素的场景。 实际使用,根据具体的需求选择合适的容器可以提高程序的效率。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

凉开水白菜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值