C++容器之链表(std::list)

1 概述

  列表是序列容器,允许在序列中的任何位置进行恒定时间的插入和擦除操作,以及双向迭代。
  列表容器被实现为双链表;双链接列表可以将它们所包含的每个元素存储在不同且不相关的存储位置。排序是通过与每个元素的关联在内部保持的,其中链接到它前面的元素,链接到它后面的元素。
  它们与forward_list非常相似:主要区别在于forward_liist对象是单链表,因此它们只能向前迭代,以换取更小、更高效。
  与其他基本标准序列容器(数组、向量和deque)相比,列表在插入、提取和移动容器中已经获得迭代器的任何位置的元素方面通常表现得更好,因此在密集使用这些元素的算法(如排序算法)中也表现得更好。
  与这些其他序列容器相比,list和forward_list的主要缺点是它们缺乏通过位置对元素的直接访问;例如,要访问列表中的第六个元素,必须从已知位置(如开始或结束)迭代到该位置,这需要在这些位置之间的距离上花费线性时间。它们还消耗一些额外的内存来保持与每个元素相关联的链接信息(这可能是小型元素的大列表的重要因素)。

其类图如下:
类图

2 使用实例

void ListSuite::access()
{
    int  array[] = { 1, 2, 3, 4, 5 };
    std::list<int> a(array, array + ARRAY_SIZE(array));
    

    TEST_ASSERT_EQUALS(1, a.front())//size of a must more than 0
    TEST_ASSERT_EQUALS(5, a.back()) //size of a must more than 0
}

3 接口使用

3.1 construct

std::list<int> getList(int size, int value)
{
    return std::list<int>(size, value);
}
void ListSuite::construct()
{
    std::list<int> a;
    std::list<int> b(4); // 0 0 0 0
    std::list<int> c(4, 5);// 5 5 5 5
    std::list<int> d({1, 2, 3, 4, 5});
    std::list<int> e(d.begin(), d.end());
    std::list<int> f(d);
    std::list<int> g(getList(6, 8));
    TEST_ASSERT_EQUALS(0, a.size())
    TEST_ASSERT_EQUALS(4, b.size())
    TEST_ASSERT_EQUALS(4, c.size())
    TEST_ASSERT_EQUALS(5, d.size())
    TEST_ASSERT_EQUALS(5, e.size())
    TEST_ASSERT_EQUALS(5, f.size())
    TEST_ASSERT_EQUALS(6, g.size())
}

3.2 assigns

void ListSuite::assigns()
{
    std::list<int> a;
    std::list<int> b;
    std::list<int> c;
    a = { 1, 2, 3, 4, 5 };
    b = a;
    c = getList(5, 10);

    TEST_ASSERT_EQUALS(5, a.size())
    TEST_ASSERT_EQUALS(5, b.size())
    TEST_ASSERT_EQUALS(5, c.size())
}

3.3 iterators

#define ARRAY_SIZE(array) sizeof(array) / sizeof(array[0])
void ListSuite::iterators()
{
    int  array[] = { 1, 2, 3, 4, 5 };
    int  rarray[] = { 5, 4, 3, 2, 1 };
    std::list<int> a(array, array + ARRAY_SIZE(array));
    int index = 0;
    for(auto it = a.begin(); it != a.end(); ++it)
    {
        TEST_ASSERT_EQUALS(array[index++], *it)
    }
    
    index = 0;
    for(auto it = a.cbegin(); it != a.cend(); ++it)
    {
        TEST_ASSERT_EQUALS(array[index++], *it)
    }

    index = 0;
    for(auto it = a.rbegin(); it != a.rend(); ++it)
    {
        TEST_ASSERT_EQUALS(rarray[index], *it)
        rarray[index] = rarray[index] * 2;
        *it = rarray[index++];
    }
    
    index = 0;
    for(auto it = a.crbegin(); it != a.crend(); ++it)
    {
        TEST_ASSERT_EQUALS(rarray[index++], *it)
    }
}

3.4 capacity

void ListSuite::capacity()
{
    std::list<int> a;
    std::list<int> b({1, 2, 3, 4, 5});

    TEST_ASSERT_EQUALS(0, a.size())
    TEST_ASSERT_EQUALS(5, b.size())
    TEST_ASSERT_EQUALS(true, a.empty())
    TEST_ASSERT_EQUALS(false, b.empty())
    TEST_ASSERT_EQUALS(a.max_size(), b.max_size())
}

3.5 access

void ListSuite::access()
{
    int  array[] = { 1, 2, 3, 4, 5 };
    std::list<int> a(array, array + ARRAY_SIZE(array));
    

    TEST_ASSERT_EQUALS(1, a.front())//size of a must more than 0
    TEST_ASSERT_EQUALS(5, a.back()) //size of a must more than 0
}

3.6 assign

void ListSuite::assign()
{
    std::list<int> a;
    std::list<int> b;
    std::list<int> c;
    a.assign({ 1, 2, 3, 4, 5 });
    b.assign(a.begin(), a.end());
    c.assign(4, 5);

    TEST_ASSERT_EQUALS(5, a.size())
    TEST_ASSERT_EQUALS(5, b.size())
    TEST_ASSERT_EQUALS(4, c.size())
}

3.7 emplace_front

void ListSuite::emplace_front()
{
    std::list<std::string> names;
    names.emplace_front("james"); //james
    TEST_ASSERT_EQUALS("james", names.front())
    names.emplace_front("jim"); //james jim
    TEST_ASSERT_EQUALS("jim", names.front())
}

3.8 push_front

void ListSuite::push_front()
{
    int array[] = { 1, 2, 3, 4, 5 };
    std::list<int> a;

    for(size_t i = 0; i < ARRAY_SIZE(array); i++)
        a.push_front(array[i]);

    int index = 0;
    for(auto it = a.rbegin(); it != a.rend(); ++it)
        TEST_ASSERT_EQUALS(array[index++], *it)
}

3.9 pop_front

void ListSuite::pop_front()
{
    std::list<int> a({1, 2, 3, 4, 5});

    TEST_ASSERT_EQUALS(1, a.front())

    a.pop_front();
    TEST_ASSERT_EQUALS(2, a.front())
    
    a.pop_front();
    TEST_ASSERT_EQUALS(3, a.front())

    a.pop_front();
    TEST_ASSERT_EQUALS(4, a.front())
    
    a.pop_front();
    TEST_ASSERT_EQUALS(5, a.front())

    a.pop_front();
    TEST_ASSERT_EQUALS(true, a.empty())

    if(!a.empty())
        a.pop_front();//??
    TEST_ASSERT_EQUALS(true, a.empty())
}

3.10 emplace_back

void ListSuite::emplace_back()
{
    std::list<std::string> names;
    names.emplace_back("james"); //james
    TEST_ASSERT_EQUALS("james", names.back())
    names.emplace_back("jim"); //james jim
    TEST_ASSERT_EQUALS("jim", names.back())
}

3.11 push_back

void ListSuite::push_back()
{
    int array[] = { 1, 2, 3, 4, 5 };
    std::list<int> a;

    for(size_t i = 0; i < ARRAY_SIZE(array); i++)
        a.push_back(array[i]);

    int index = 0;
    for(auto it = a.begin(); it != a.end(); ++it)
        TEST_ASSERT_EQUALS(array[index++], *it)
}

3.12 pop_back

void ListSuite::pop_back()
{
    std::list<int> a({1, 2, 3, 4, 5});

    TEST_ASSERT_EQUALS(5, a.back())

    a.pop_back();
    TEST_ASSERT_EQUALS(4, a.back())
    
    a.pop_back();
    TEST_ASSERT_EQUALS(3, a.back())

    a.pop_back();
    TEST_ASSERT_EQUALS(2, a.back())
    
    a.pop_back();
    TEST_ASSERT_EQUALS(1, a.back())

    a.pop_back();
    TEST_ASSERT_EQUALS(true, a.empty())

    if(!a.empty())
        a.pop_back();//??
    TEST_ASSERT_EQUALS(true, a.empty())
}

3.13 emplace

void ListSuite::emplace()
{
    std::list<std::string> names;
    auto it = names.emplace(names.begin(), "james"); //james
    TEST_ASSERT_EQUALS("james", *it)
    it = names.emplace(names.end(), "jim"); //james jim
    TEST_ASSERT_EQUALS("jim", *it)
}

3.14 insert

void ListSuite::insert()
{
    std::list<std::string> names;
    std::string name("James");

    auto it = names.insert(names.begin(), name);//James
    TEST_ASSERT_EQUALS(name, *it)

    it = names.insert(names.end(), 2, "Tom"); //James Tom Tom 
    TEST_ASSERT_EQUALS("Tom", *it)

    it = names.insert(names.end(), "Peter"); //James Tom Tom Peter
    TEST_ASSERT_EQUALS("Peter", *it)

    it = names.insert(names.end(), {"Jim", "Rose", }); //James Tom Tom Peter Jim Rose
    TEST_ASSERT_EQUALS("Jim", *it)
}

3.15 erase

void ListSuite::erase()
{
    std::list<int> a({1, 2, 3, 4, 5});
    auto it1 = a.begin();
    auto it2 = a.begin();

    std::advance(it1, 1);
    std::advance(it2, 4);
    TEST_ASSERT_EQUALS(2, *it1)
    TEST_ASSERT_EQUALS(5, *it2)

    auto it = a.erase(it1);//1 3 4 5
    TEST_ASSERT_EQUALS(3, *it)

    it = a.erase(it2);//1 3 4
    TEST_ASSERT_EQUALS(true, it == a.end())

    it1 = a.begin();
    std::advance(it1, 1);
    TEST_ASSERT_EQUALS(3, *it1)
    it = a.erase(a.begin(), it1);
    TEST_ASSERT_EQUALS(4, *it)
}

3.16 swap

void ListSuite::swap()
{
    std::list<int> a({1, 2, 3, 4, 5});
    std::list<int> b;

    TEST_ASSERT_EQUALS(5, a.size())
    TEST_ASSERT_EQUALS(0, b.size())

    a.swap(b);
    TEST_ASSERT_EQUALS(0, a.size())
    TEST_ASSERT_EQUALS(5, b.size())
}

3.17 resize

void ListSuite::resize()
{
    std::list<int> a;
    a.resize(5, 10);  //10 10 10 10 10
    for(auto it = a.begin(); it != a.end(); ++it)
        TEST_ASSERT_EQUALS(10, *it);
    
    a.resize(8);      //10 10 10 10 10 0 0 0
    auto end = a.begin();
    std::advance(end, 5);
    for(auto it = a.begin(); it != end; ++it)
        TEST_ASSERT_EQUALS(10, *it);
    
    for(auto it = end; it != a.end(); ++it)
        TEST_ASSERT_EQUALS(0, *it);

    a.resize(10, 20); //10 10 10 10 10 0 0 0 20 20
    auto begin = a.begin();
    std::advance(begin, 10);
    for(auto it = begin; it != a.end(); ++it)
        TEST_ASSERT_EQUALS(20, *it);
}

3.18 clear

void ListSuite::clear()
{
    std::list<int> a({1, 2, 3, 4, 5});

    TEST_ASSERT_EQUALS(5, a.size())
    a.clear();

    TEST_ASSERT_EQUALS(0, a.size())
}

3.19 splice

void ListSuite::splice()
{
    std::list<int> a({1, 2, 3, 4, 5});
    std::list<int> b({6, 7, 8, 9, 10});
    a.splice(a.end(), b);
    TEST_ASSERT_EQUALS(10, a.size())
    TEST_ASSERT_EQUALS(0, b.size())

    b.splice(b.begin(), a, a.begin());//1
    TEST_ASSERT_EQUALS(1, b.front())

    b.splice(b.end(), a, a.begin(), a.end());

    TEST_ASSERT_EQUALS(0, a.size())
    TEST_ASSERT_EQUALS(10, b.size())
}

说明:

  • 拼接两个list,不要求两个表是排好序的
  • 拼接时不是复制,而是移动,作为为参数容器中对应元素将会被删除。

3.20 remove

void ListSuite::remove()
{
    std::list<int> a({1, 2, 3, 3, 4, 5});

    TEST_ASSERT_EQUALS(6, a.size())
    a.remove(3);
    TEST_ASSERT_EQUALS(4, a.size())
}

说明:

  • 删除list中等于指定值的所有元素。

3.21 remove_if

bool single_num(const int& value) { return value < 10; }
struct is_even
{
    bool operator()(const int& value) {  return value % 2 == 0; }
};
void ListSuite::remove_if()
{
    std::list<int> a({15, 36, 7, 17, 20, 39, 4, 1});

    a.remove_if(single_num);//15, 36, 17, 20, 39
    TEST_ASSERT_EQUALS(5, a.size())

    a.remove_if(is_even());//15, 17, 39
    TEST_ASSERT_EQUALS(3, a.size())

    a.remove_if([](const int& value){ return value > 20; }); // 15 , 17
    TEST_ASSERT_EQUALS(2, a.size())
}

说明:

  • 删除list中符合谓词函数的所有元素

3.22 unique

void ListSuite::unique()
{
    std::list<int> a({ 1, 2, 3, 3, 4, 3, 5, 6 , 6});

    TEST_ASSERT_EQUALS(9, a.size())
    a.unique();//1 2 3 4 3 5 6
    TEST_ASSERT_EQUALS(7, a.size()) 

    a.sort();
    a.unique();//1 2 3 4 5 6
    TEST_ASSERT_EQUALS(6, a.size())

    std::list<float > b{ 1.2, 1.5, 2.2, 2.3, 3.2, 3.3 };
    b.unique([](const float& l, const float& r) { return int(l) == int(r); }); // 1.2 2.2 3.2
    TEST_ASSERT_EQUALS(3, b.size())
}

说明:

  • 该函数删除list中相同元素,不过前提是list是排好序的
  • 如果是无序list,只会删除相邻相同的元素,如果相同元素在list中不相邻,将不会被删除。

3.23 merge

void ListSuite::merge()
{
    std::list<int> a{1, 2, 3, 4, 5};
    std::list<int> b{6, 7, 8, 9, 10};

    a.sort();
    b.sort();
    a.merge(b);
    TEST_ASSERT_EQUALS(10, a.size())
    TEST_ASSERT_EQUALS(0, b.size())
}

说明:

  • 合并两个list,前期是两个list是排好序的,合并后也是排好序的。

3.24 sort

void ListSuite::sort()
{
    int array[] =  { 1, 5, 6, 7, 8, 15, 32 };
    std::list<int> a{5, 1, 7, 8, 6, 15, 32};
    a.sort();
    int index = 0;
    for(auto it = a.begin(); it != a.end(); ++it)
        TEST_ASSERT_EQUALS(array[index++], *it)
    a.sort([](int const&l, int const&r ){ return l > r; });

    index = 0;
    for(auto it = a.rbegin(); it != a.rend(); ++it)
        TEST_ASSERT_EQUALS(array[index++], *it)
}

说明:

  • 默认谓词是小于,按升序排序
  • 可以指定为为大于,按降序排序

3.25 reverse

void ListSuite::reverse()
{
    int array[] = { 1, 2, 3, 4, 5 };
    std::list<int> a(array, array +ARRAY_SIZE(array));
    a.reverse();

    int index = 0;
    for(auto it  = a.rbegin(); it != a.rend(); ++it)
        TEST_ASSERT_EQUALS(array[index++], *it) 
}

3.26 get_allocator

void ListSuite::get_allocator()
{
    std::list<int> a;
    auto allocator = a.get_allocator();
    int* p = allocator.allocate(5);

    allocator.deallocate(p, 5);
    try
    {
        p = allocator.allocate(allocator.max_size() + 1);
    }
    catch(...)
    {
        p = nullptr;
    }
    TEST_ASSERT_EQUALS(true, p == nullptr)
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

flysnow010

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

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

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

打赏作者

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

抵扣说明:

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

余额充值