双向链表std::list和单向链表std::forward_list

中文标准库:std::list

中文标准库:std::forward_list

一、简介

  • list是由双向链表实现的,内存空间是不连续的。由链表的实现原理可知:

优点:插入和删除非常快。只需要在插入的地方更改指针的指向即可,不用移动数据。

缺点:不支持随机访问,查询效率较低,时间复杂度为O(n)

  • forward_list是一个单向链表,只支持单向顺序访问,在链表的任何位置进行插入/删除操作都非常快。

list的迭代器不支持+、-操作,支持++、--操作(vector迭代器支持+、-、++、--等操作),可以使用std::advance达到+的目的

二、构造

初始化列表:initializer_list

// C++11 初始化列表语法:
std::list<std::string> words1{ "the", "frogurt", "is", "also", "cursed" };

// words2 == words1
std::list<std::string> words2(words1.begin(), words1.end());

// words3 == words1
std::list<std::string> words3(words1);

// words4 为 {"Mo", "Mo", "Mo", "Mo", "Mo"}
std::list<std::string> words4(5, "Mo");

三、增加元素

右值引用

  • insert、emplace:在某一给定位置插入元素
template <class... Args>
  iterator emplace (const_iterator position, Args&&... args);

//single element(1)
iterator insert(const_iterator position, const value_type& val);
//fill(2)
iterator insert(const_iterator position, size_type n, const value_type& val);
//range(3)
template <class InputIterator>
iterator insert(const_iterator position, InputIterator first, InputIterator last);
//move(4)
iterator insert(const_iterator position, value_type&& val);
//initializer list(5)
iterator insert(const_iterator position, initializer_list<value_type> il);
  • emplace_back、push_back:在容器尾部插入元素
template <class... Args>
  void emplace_back (Args&&... args);

void push_back (const value_type& val);
void push_back (value_type&& val);
  • emplace_front、push_front:在容器头部插入元素
template <class... Args>
  void emplace_front (Args&&... args);

void push_front (const value_type& val);
void push_front (value_type&& val);
  • 示例代码:
std::list<int> List1;
List1.insert(List1.begin(), { 1,2 });     //1,2
List1.emplace(List1.end(), std::move(3)); //1,2,3
List1.emplace_back(4);                    //1,2,3,4
List1.emplace_front(5);                   //5,1,2,3,4
List1.push_back(6);           //5,1,2,3,4,6
List1.push_front(7);              //7,5,1,2,3,4,6

四、删除元素

  • clear:清空元素

void clear() noexcept;

  • pop_back、pop_front:移除尾部或首部元素

如果容器为空,这两个函数会中断(不是抛出异常)

void pop_back();
void pop_front();
  • erase:删除指定位置的元素
iterator erase (const_iterator position);  //仅仅删除这个位置的一个元素
iterator erase (const_iterator first, const_iterator last);  //删除first到last的所有元素
  • remove:删除指定元素

void remove (const value_type& val);

  • remove_if、erase_if(C++20):擦除所有满足特定判别标准的元素

注意:删除的是pred返回true的元素。

template< class T, class Alloc, class Pred >
typename std::list<T, Alloc>::size_type erase_if(std::list<T, Alloc>& c, Pred pred);

template <class Predicate>
  void remove_if (Predicate pred);

lambda表达式

  • 示例代码:
std::list<int> List2{ 0,1,2,3,4,5,6,7,8 };
List2.pop_back();  //0,1,2,3,4,5,6,7
List2.pop_front(); //1,2,3,4,5,6,7
List2.erase(List2.begin());  //2,3,4,5,6,7
List2.erase(std::find(List2.begin(), List2.end(), 5), List2.end());  //2,3,4
List2.remove(2); //3,4
List2.remove_if([](int n) {return n == 4; }); //3
List2.clear();  //清空

五、修改元素

  • 修改

list不能像vector一样通过[]修改元素,不过可以先删除需要修改的元素,再添加一个新的元素。

  • swap:交换
    注意:交换的两个list类型必须相同
    void swap (list& x);
  • 示例代码:
std::list<int> List4{ 2,3,4 };
std::list<int> List5{ 7,8,9 };
List4.swap(List5);

std::list<int> List6{ 1,2,3,4,5,6 };
List5.remove(3);
List6.emplace_back(7);
  • assign:替换原有的list的内容
    和swap相比,assign功能更强大,assign的参数可以是其他容器,也可以选择将list用容器中的一部分元素替换。
    list.assign(vector.begin(),vector.end());

六、访问元素、查找元素

注意:list没有自己的查找函数,如果要使用查找,可以用算法库(algorithm)中的std::find函数

  • front:访问第一个元素

  • back:访问最后一个元素

  • 示例代码:

std::list<int> List3{ 1,2,3,4,5 };
int front = List3.front();  //1
int back = List3.back();    //5
std::list<int>::iterator it = std::find(List3.begin(), List3.end(), 2);

七、其他

  • 排序:sort()

默认升序排序,若要使用降序排序:

升序:sort(std::less<data-type>())

降序:sort(std::greater<data-type>())

        List7.sort(std::greater<int>());  //降序
        List7.sort(std::less<int>());     //升序
  • 逆序:reverse()

  • 移除重复元素:unique()
    注意:不相邻的重复元素不会被删除

  • 合并:merge
    前提:两个已排序的list,且必须按升序排序(list::sort()默认升序排序)

注意:归并完之后,x会被清空(即全部移动到调用对象中去)
函数原型:

void merge(list& x);
void merge(list&& x);
template <class Compare>
void merge(list& x, Compare comp);
template <class Compare>
void merge(list&& x, Compare comp);

示例代码:

std::list<int> List7{ 8,7,7,9 };
List7.sort();
std::list<int> List8{ 5,3,3,2 };
List8.sort();
List7.merge(List8);
  • 转移元素:splice()

函数原型:

//entire list(1)
void splice(const_iterator position, list& x);
void splice(const_iterator position, list&& x);
//single element(2)
void splice(const_iterator position, list& x, const_iterator i);
void splice(const_iterator position, list&& x, const_iterator i);
//element range(3)
void splice(const_iterator position, list& x, const_iterator first, const_iterator last);
void splice(const_iterator position, list&& x, const_iterator first, const_iterator last);

示例代码:

std::list<int> List9{ 1,2,3,4,5 };
std::list<int> List10{ 7,8,9 };
auto it9 = List9.begin();
std::advance(it9, 2); //迭代器指向的元素向后移动两位,指向3
List9.splice(it9, List10);  //List9:1,2,7,8,9,3,4,5;List10为空

std::list<int> List11{ 1,2,3 };
std::list<int> List12{ 5,6,7,8,9 };
auto it12 = List12.begin();
std::advance(it12, 2);
List11.splice(List11.begin(), List12, it12, List12.end());  //List11:7,8,9,1,2,3;Lis12:5,6

完整代码

点击查看代码
#include <iostream>
#include <algorithm>
#include <list>

int main()
{
    //插入
    std::list<int> List1;
    List1.insert(List1.begin(), { 1,2 });     //1,2
    List1.emplace(List1.end(), std::move(3)); //1,2,3
    List1.emplace_back(4);                    //1,2,3,4
    List1.emplace_front(5);                   //5,1,2,3,4
    List1.push_back(6);                       //5,1,2,3,4,6
    List1.push_front(7);                      //7,5,1,2,3,4,6

    //删除
    std::list<int> List2{ 0,1,2,3,4,5,6,7,8 };
    List2.pop_back();  //0,1,2,3,4,5,6,7
    List2.pop_front(); //1,2,3,4,5,6,7
    List2.erase(List2.begin());  //2,3,4,5,6,7
    List2.erase(std::find(List2.begin(), List2.end(), 5), List2.end());  //2,3,4
    List2.remove(2); //3,4
    List2.remove_if([](int n) {return n == 4; }); //3
    List2.clear();  //清空

    //查找
    std::list<int> List3{ 1,2,3,4,5 };
    int front = List3.front();  //1
    int back = List3.back();    //5
    std::list<int>::iterator it = std::find(List3.begin(), List3.end(), 2);

    //修改
    std::list<int> List4{ 2,3,4 };
    std::list<int> List5{ 7,8,9 };
    List4.swap(List5);

    std::list<int> List6{ 1,2,3,4,5,6 };
    List5.remove(3);
    List6.emplace_back(7);

    //归并
    std::list<int> List7{ 8,7,7,9 };
    List7.sort();
    std::list<int> List8{ 5,3,3,2 };
    List8.sort();
    List7.merge(List8);

    //排序
    List7.sort(std::greater<int>());  //降序
    List7.sort(std::less<int>());     //升序

    //移除相邻重复元素
    List7.unique();

    //逆序
    List7.reverse();

    //转移元素
    std::list<int> List9{ 1,2,3,4,5 };
    std::list<int> List10{ 7,8,9 };
    auto it9 = List9.begin();
    std::advance(it9, 2); //迭代器指向的元素向后移动两位,指向3
    List9.splice(it9, List10);  //List9:1,2,7,8,9,3,4,5;List10为空

    std::list<int> List11{ 1,2,3 };
    std::list<int> List12{ 5,6,7,8,9 };
    auto it12 = List12.begin();
    std::advance(it12, 2);
    List11.splice(List11.begin(), List12, it12, List12.end());  //List11:7,8,9,1,2,3;Lis12:5,6

    return 0;
}

原文链接: https://www.cnblogs.com/mmmmmmmmm/p/14812567.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍;

也有高质量的技术群,里面有嵌入式、搜广推等BAT大佬

    双向链表std::list和单向链表std::forward_list

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/404134

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年4月24日 下午6:42
下一篇 2023年4月24日 下午6:42

相关推荐