C++的三大容器之顺序容器

顺序容器就是数据结构里的线性表,一共有 5 种:array、vector、deque、list、forward_list

如果按照存储的方式又可以分为链式存储(list 和 forward_list)和连续地址存储(array、vector 和 deque)

连续地址存储链式存储
优点查找效率高插入删除效率高
缺点插入删除效率低查找效率低,存储成本略高

对于array和vector在内存中的数据存放与C语言完全兼容,所以对于数据的操作速度很快。这两种容器的区别在于array是不能扩容的,而vector可以动态的扩容。

#include <iostream>
#include <vector>
#include <array>
#include <algorithm>

int main()
{
    std::array<int, 10> arr;
    std::vector<int> v;

    std::for_each(
        cbegin(arr), cend(arr),
        [&v](const auto& i)
        {
            v.emplace_back(i);
        });

    std::cout << arr.size() << std::endl; // 10
    std::cout << v.size() << std::endl; // 10
    return 0;
}

deque与vector的最大的区别是deque可以两头进行插入。删除的操作,vector只能在尾部进行插入和删除的操作。

#include <iostream>
#include <deque>

int main()
{
	std::deque<int> q;
    q.emplace_back(1);
    q.emplace_front(2);

    for(auto i : q)
    {
        std::cout << i << " "; // 2 1
    }
    return 0;
}

list 是双向链表,可以向前或者向后遍历,而 forward_list则是单向链表,只能向前遍历,查找效率会比list低。

#include <iostream>
#include <list>
#include <forward_list>

int main()
{
	std::list<int> l;
    l.emplace_back(1);
    l.emplace_front(2);
    l.emplace_back(3);

    for(auto i : l)
    {
        std::cout << i << " "; // 2 1 3
    }
    std::cout << std::endl;

    std::forward_list<int> fl;
    fl.emplace_front(2);
    fl.emplace_front(1);

    for(auto i : fl)
    {
        std::cout << i << " "; // 1 2
    }
    std::cout << std::endl;

    return 0;
}

虽然vector、deque、list和forward_list都可以进行动态的扩容,但是它们的机制是完全不同的。我们先看看vector是怎么扩容的:

#include <iostream>
#include <vector>

struct Point
{
	int m_a;
	int m_b;
    Point (int a, int b) : m_a(a), m_b(b)
    {
        std::cout << "构造函数" << std::endl;
    }
    Point (const Point& p) : m_a(p.m_a), m_b(p.m_b)
    {
        std::cout << "拷贝构造" << std::endl;
    }

    Point (Point &&p) : m_a(p.m_a), m_b(p.m_b)
    {
        std::cout << "移动构造" << std::endl;
    }
};

int main()
{
	std::vector<Point> v;

    for (int i = 1; i <= 5; i++)
    {
        std::cout << "*********" << i << "***********" << std::endl;
        v.emplace_back(i, i + 1);
        std::cout << "v.size = " << v.size() << std::endl;
    }
    return 0;
}

输出结果如下:
在这里插入图片描述
大家有没有发现,有时候会莫名其妙的调用拷贝构造函数,这是为什么呢?这是因为当 vector 的容量不够的时候,它会去寻找一块两倍大小的新内存,然后把旧元素拷贝或者移动过去,最后把新数据插入进去。这个问题之前我在工作中遇到过,所以影响特别深。我记得当时的业务中需要在vector容器中进行大量的数据插入,等数据达到一定量级的时候,接口返回时间越来越长。最后找到是这个原因导致,通过reserve接口进行所需容器的空间预估,可以减少动态扩容的调用拷贝构造的次数,从而提高程序性能。
而deque、list和forward_list相对比较简单,插入一个数据,扩容一个数据的大小。但是如果短时间有大量的数据插入,这时候一次性分配足够大的空间的vector的优势就比较明显了。所以实际开发中vector出现的记录很高。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值