STL讲解(六)——list容器的介绍及使用


一、list是什么?

1.1 定义

list是C++的一个序列容器,插入和删除元素的效率较高,时间复杂度为常数级别,list容器的底层数据结构为带头双向循环链表,这使得 list的元素可以存储在非相邻的内存中,在list内部,不同元素之间通过指向前一个元素的指针以及指向后一个元素的指针相关联

list 容器与其他序列容器如vector deque array相比,由于其底层数据结构为带头双向循环链表,因此 list 在插入删除元素方面很有优势,在列表的任意位置进行插入和删除操作的时间复杂度为O(1)。但不能直接通过位置(下标)来直接访问元素。想要访问list的某个元素,必须从list的一端(或已知位置)迭代到该元素。另外,list还需要额外的存储空间来储存前一个元素和后一个元素的链接信息

1.2 list的存储结构

list 容器底层为带头双向循环链表,带头双向循环链表每个节点包含指向前驱节点的pre指针,指向后继节点的next指针以及节点的数据。list存储结构如下图所示: 哨兵节点表示 链表的第一个元素节点,且不保存任何数据

如果有老铁对带头双向循环链表忘记的可以看看这篇文章:带头双向循环链表详解

在这里插入图片描述

1.3 list容器的优点

  • 高效的插入和删除:由于std::list是基于带头双向循环链表实现的,插入和删除操作在任意位置都具有常数时间复杂度O(1),不需要移动其他元素。这使得std::list在需要频繁插入和删除元素的场景下非常高效
  • 稳定的迭代器:在std::list中进行插入和删除操作不会使得迭代器失效。这意味着在插入或删除元素后,仍然可以继续使用之前获取的迭代器进行遍历和操作
  • 动态内存管理:std::list可以动态调整大小,根据需要分配和释放内存。这使得std::list能够有效地处理大量元素的情况,而不会浪费过多的内存空间

1.4 list容器的缺点

  • 低效的随机访问:由于std::list的存储结构是带头双向循环链表,访问元素时需要从头或尾开始遍历链表,因此在列表中进行随机访问的效率较低。获取特定位置的元素需要遍历链表,时间复杂度为O(n),其中n是元素的总数量
  • 占用额外内存:相较于其他容器,std::list在存储上需要额外的指针来维护链表结构,因此在存储大量元素时,它可能占用更多的内存空间
  • 迭代器不支持指针算术:std::list的迭代器不支持指针算术运算,无法像指针那样直接进行加减操作,这限制了一些操作的灵活性

1.4 头文件

list是C++ 标准模板库的一部分,因此,想要使用list,需要在程序中包含头文件 list

#include<list>

二、list的定义

单独定义一个list:

list <typename> name;

这里的typename可以是任何基本类型,例如int、double、char、结构体等,也可以是STL标准容器,例如string、set、queue、vector等

注意:使用前必须加上头文件:#include

#include<iostream>
#include<list>
using namespace std;

int main()
{
	int a[3];         // 正常定义的-----静态数组
	list<int> str_a;  // list 定义的 int类型的链表

	char b[3];
	list<char>str_b;

	return 0;
}

在这里插入图片描述

三、list常用接口的使用

3.1 list的常见构造(初始化)

接口名称接口说明
list()构造空的list
list (size_type n, const value_type& val = value_type())构造的list中包含n个值为val的元素
list (const list& x)拷贝构造函数
list (InputIterator first, InputIterator last用[first, last)区间中的元素构造list

方式一:构造一个某类型的空容器:list<数据类型> 函数名; 初始化为空

list<int> lt1; //构造int类型的空容器

方式二: 构造一个含有n个val的某类型容器

list<int> lt2(10, 2); //构造含有10个2的int类型容器

方式三: 拷贝构造某类型容器的复制品

list<int> lt3(lt2); //拷贝构造int类型的lt2容器的复制品

方式四:使用迭代器拷贝构造某一段内容

string s("hello world");
list<char> lt4(s.begin(),s.end()); //构造string对象某段迭代器区间的内容

方式五:构造数组某段区间的内容

int arr[] = { 1, 2, 3, 4, 5 };
int sz = sizeof(arr) / sizeof(int);
list<int> lt5(arr, arr + sz); //构造数组某段区间的复制品  ->本质是调用迭代器区间的构造函数

方式六: 使用花括号构造内容(C++11)

list<int> lt{ 1,2,3,4,5 };  // 直接使用花括号进行构造---C++11允许
int main()
{
	list<int> li1;                          //构造一个没有元素的空容器

	list<int>li2(2, 10);                    //2个值为10的整数

	list<int> li3(li2.begin(), li2.end());  // 迭代器构造

	list<int>li4(li3);                      //拷贝构造

	// 迭代器构造函数也可以使用数组来进行构造,传的区间是左闭右开
	// 因为指向数组空间的指针是天然的迭代器

	int arr[] = { 1,2,3,4 };
	list<int>li5(arr, arr + 4);               

	// 用其它容器的迭代器初始化,只要数据d类型可以匹配上
	string s("hello");
	list<char> li6(s.begin(), s.end());
	for (auto& e : li6)
	{
		cout << e << " ";
	}
	cout << endl;

	return 0;
}

在这里插入图片描述

3.2 list的遍历及迭代器的操作

接口名称接口说明
迭代器begin() + end() 或者 rbegin() + rend()
范围forC++11支持更简单的for的新遍历方式(底层还是借用迭代器实现)

3.2.1 迭代器

接口名称接口说明
begin()返回第一个元素的迭代器
end()返回最后一个元素下一个位置的迭代器
rbegin()返回最后一个元素的迭代器
rend()返回第一个元素的前一个位置额迭代器

在这里插入图片描述

1、begin和end

通过begin函数可以得到容器中第一个元素的正向迭代器,通过end函数可以得到容器中最后一个元素的后一个位置的正向迭代器

注意:begin与end为正向迭代器,对迭代器执行++操作,迭代器向后移动

2、rbegin和rend

通过rbegin函数可以得到容器中最后一个元素的反向迭代器,通过rend函数可以得到容器中第一个元素的前一个位置的反向迭代器

注意:rbegin(end)与rend(begin)为反向迭代器,对迭代器执行++操作,迭代器向前移动

int main()
{
	int arr[] = { 1,2,3,4,5,6 };
	list<int>lt1(arr, arr + 6);

	//正向迭代器遍历容器
	list<int>::iterator it = lt1.begin();

	//循环遍历
	while (it != lt1.end())
	{
		cout << *it << " ";
		it++;
	}
	cout << endl;

	//反向迭代器遍历容器
	list<int>::reverse_iterator rit = lt1.rbegin();

	//遍历循环
	while (rit != lt1.rend())
	{
		cout << *rit << " ";
		rit++;
	}
	cout << endl;
	return 0;
}

在这里插入图片描述

3.2.2 范围for

如果支持迭代器,则一定支持范围for

int main()
{
	vector<int> v{ 1,2,3,4,5,6 };
	list<int> lt(v.begin(), v.end());

	for (auto& e : lt)
	{
		cout << e << " ";
	}
	cout << endl;
	return 0;
}

在这里插入图片描述

3.3 list的常见容量操作

接口名称接口说明
size返回容器中有效元素个数
resize调整容器的有效元素大小(size)
empty判断容器是否为空
clear用于清空容器,清空后容器的size为0, 但是头结点(哨兵位)不会被清除

3.3.1 size

size函数用于获取当前容器当中的元素个数
在这里插入图片描述

3.3.2 resize

在C++中,list 容器提供了resize()方法,用于调整列表的大小。使用resize()方法可以重新指定list的大小,并根据需要插入或删除list中的元素来达到指定的大小

resize()有两种重载形式:

  • void resize(size_type count, const T& value = T()):

这个重载会将列表的大小调整为count。如果count大于当前列表的大小,则在列表末尾插入足够数量的值为value的元素。如果count小于当前列表的大小,则删除超出count的元素

  • void resize(size_type count):

这个重载会将列表的大小调整为count。如果count大于当前列表的大小,则在列表末尾插入默认构造的元素。如果count小于当前列表的大小,则删除超出count的元素

int main()
{
	vector<int> v{ 1,2,3,4,5,6 };
	list<int> lt(v.begin(), v.end());
	for (auto a : lt) {
		cout << a << " ";
	}
	cout << endl;
	cout << endl;

	lt.resize(10);//把lt的大小设置为10
	for (auto a : lt) {
		cout << a << " ";
	}
	cout << endl;
	cout << endl;

	lt.resize(2);//把lt的大小设置为2
	for (auto a : lt) {
		cout << a << " ";
	}
	cout << endl;
	cout << endl;

	lt.resize(5, 8);//把lt的大小设置为5,不足的部分填充8
	for (auto a : lt) {
		cout << a << " ";
	}
	cout << endl;
	cout << endl;

	return 0;
}

在这里插入图片描述

3.3.3 empty

empty()方法用来判断list是否为空,如果为空,返回true;如果非空,返回false

int main()
{
	list<int> lt1;
	list<int> lt2(2,2);

	cout << "lt1是否为空?" << lt1.empty() << endl;
	cout << "lt2是否为空?" << lt2.empty() << endl;

	return 0;
}

在这里插入图片描述

3.3.4 clear

clear 函数用于清空容器,清空后容器的size为0, 但是头结点(哨兵位)不会被清除

int main()
{
	vector<int> v{ 1,2,3,4,5,6 };
	list<int> lt(v.begin(), v.end());
	for (auto a : lt) {
		cout << a << " ";
	}
	cout << endl;
	cout << lt.size() << endl;

	lt.clear();
	for (auto a : lt) {
		cout << a << " ";
	}
	cout << endl;
	cout << lt.size() << endl;
	cout << endl;

	return 0;
}

在这里插入图片描述

3.4 list的常见访问操作

3.4.1 front()——访问list头元素

front()返回list第一个元素

int main()
{
	vector<int> v{ 1,2,3,4,5,6 };
	list<int> lt(v.begin(), v.end());
	for (auto a : lt) {
		cout << a << " ";
	}
	cout << endl;

	int front = lt.front();
	cout << front << endl;
	return 0;
}

在这里插入图片描述

3.4.2 back()——访问list尾元素

back()返回list最后一个元素

int main()
{
	vector<int> v{ 1,2,3,4,5,6 };
	list<int> lt(v.begin(), v.end());
	for (auto a : lt) {
		cout << a << " ";
	}
	cout << endl;

	int back = lt.back();
	cout << back << endl;
	return 0;
}

在这里插入图片描述

3.5 list常见修改操作

接口名称接口说明
push_front在list首元素前插入值为val的元素
pop_front删除list中第一个元素
push_back在list尾部插入值为val的元素
pop_back删除list中最后一个元素
insert在list position 位置中插入值为val的元素
erase删除list position位置的元素
swap交换两个list中的元素

3.5.1 push_back()——添加元素(list尾部)

向list中添加元素,使用push_back()方法,作用是向list尾部添加一个元素

int main()
{
	vector<int> v{ 1,2,3,4,5,6 };
	list<int> lt(v.begin(), v.end());
	for (auto a : lt) {
		cout << a << " ";
	}
	cout << endl;

	lt.push_back(10);
	for (auto a : lt) {
		cout << a << " ";
	}
	cout << endl;

	return 0;
}

在这里插入图片描述

3.5.2 pop_back()——移除list元素(尾部)

删除list中的元素,使用pop_back()方法,作用是删除list尾部的一个元素

int main()
{
	vector<int> v{ 1,2,3,4,5,6 };
	list<int> lt(v.begin(), v.end());
	for (auto a : lt) {
		cout << a << " ";
	}
	cout << endl;

	lt.pop_back();
	for (auto a : lt) {
		cout << a << " ";
	}
	cout << endl;

	return 0;
}

在这里插入图片描述

3.5.3 pop_front()——删除list元素(头部)

删除list中的元素,使用pop_front()方法,作用是删除list头部的一个元素

int main()
{
	vector<int> v{ 1,2,3,4,5,6 };
	list<int> lt(v.begin(), v.end());
	for (auto a : lt) {
		cout << a << " ";
	}
	cout << endl;

	lt.pop_front();
	for (auto a : lt) {
		cout << a << " ";
	}
	cout << endl;

	return 0;
}

在这里插入图片描述

3.5.4 push_front()——添加元素(list头部)

向list中添加元素,使用push_front()方法,作用是向list头部添加一个元素

int main()
{
	vector<int> v{ 1,2,3,4,5,6 };
	list<int> lt(v.begin(), v.end());
	for (auto a : lt) {
		cout << a << " ";
	}
	cout << endl;

	lt.push_front(8);
	for (auto a : lt) {
		cout << a << " ";
	}
	cout << endl;

	return 0;
}

在这里插入图片描述

3.5.5 insert()——添加元素(任意位置)

向list中添加元素

insert共有三种形式:

  • insert(iterator, value);
  • insert(iterator, num, value);
  • insert(iterator, iterator1, iterator2);

1、list.insert(iterator,value)

使用insert(iterator,value)方法,作用是向iterator迭代器指向元素的前边添加一个元素value,并返回一个迭代器指向新插入的元素

在这里插入图片描述

int main()
{
	vector<int> v{ 1,2,3,4,5,6 };
	list<int> lt(v.begin(), v.end());
	for (auto a : lt) {
		cout << a << " ";
	}
	cout << endl;
	cout << endl;

	list<int>::iterator it = find(lt.begin(), lt.end(), 2);

	list<int>::iterator itnew = lt.insert(it, 10);

	cout << "返回的迭代器指向的元素为" << *itnew;
	cout << endl;
	cout << endl;

	cout << "insert添加一个元素后的lt为:";
	for (auto num : lt) {
		cout << num << " ";
	}
	cout << endl;
	return 0;
}

在这里插入图片描述

2、list.insert(iterator,num,value)

使用insert(iterator,num,value)方法,作用是向iterator迭代器指向元素的前边添加num个元素value,并返回一个迭代器指向新插入的第一个元素
在这里插入图片描述

int main()
{
	vector<int> v{ 1,2,3,4,5,6 };
	list<int> lt(v.begin(), v.end());
	for (auto a : lt) {
		cout << a << " ";
	}
	cout << endl;
	cout << endl;

	list<int>::iterator it = find(lt.begin(), lt.end(), 2);

	list<int>::iterator itnew = lt.insert(it, 2, 10);

	cout << "返回的迭代器指向的元素为" << *itnew;
	cout << endl;
	cout << endl;

	cout << "insert添加一个元素后的lt为:";
	for (auto num : lt) {
		cout << num << " ";
	}
	cout << endl;
	return 0;
}

在这里插入图片描述
3、insert(iterator, iterator1, iterator2)

使用insert(iterator, iterator1, iterator2);方法,作用是向iterator迭代器指向元素的前边添加[iterator1,iterator2)之间的元素

int main()
{
	vector<int> v{ 1,2,3,4,5,6 };
	list<int> lt(v.begin(), v.end());
	for (auto a : lt) {
		cout << a << " ";
	}
	cout << endl;
	cout << endl;

	list<int>lt1(2, 10);
	list<int> ::iterator it1 = lt1.begin();
	list<int>::iterator it2 = lt1.end();

	list<int>::iterator it = find(lt.begin(), lt.end(), 2);

	list<int>::iterator itnew = lt.insert(it, it1, it2); //使用insert在2之前添加[it1, it2)之间的元素

	cout << "返回的迭代器指向的元素为" << *itnew;
	cout << endl;
	cout << endl;

	cout << "insert添加一个元素后的lt为:";
	for (auto num : lt) {
		cout << num << " ";
	}
	cout << endl;
	return 0;
}

在这里插入图片描述

3.5.6 erase()——删除元素(任意位置)

erase的作用就是根据传入的迭代器删除list中的元素,参数为一个迭代器,只删除迭代器指向的元素;参数为两个迭代器,删除两个迭代器之间的元素

erase 共有两种形式:

  • list.erase(iterator)
  • list.erase(iterator1,iterator2)

1、list.erase(iterator)

这种用法会删除迭代器iterator指向的元素

在这里插入图片描述

int main()
{
	vector<int> v{ 1,2,3,4,5,6 };
	list<int> lt(v.begin(), v.end());
	for (auto a : lt) {
		cout << a << " ";
	}
	cout << endl;
	cout << endl;

	list<int>::iterator it = find(lt.begin(), lt.end(), 2);

	list<int>::iterator itnew = lt.erase(it); 

	cout << "返回的迭代器指向的元素为" << *itnew;
	cout << endl;
	cout << endl;

	cout << "insert删除一个元素后的lt为:";
	for (auto num : lt) {
		cout << num << " ";
	}
	cout << endl;
	return 0;
}

在这里插入图片描述

2、list.erase(iterator1,iterator2)
这种用法会删除迭代器iterator1指向的元素到iterator2指向元素之间的元素,包括iterator1指向的元素但不包括iterator2指向的元素,即擦除[iterator1,iterator2)

在这里插入图片描述

int main()
{
	vector<int> v{ 1,2,3,4,5,6 };
	list<int> lt(v.begin(), v.end());
	for (auto a : lt) {
		cout << a << " ";
	}
	cout << endl;
	cout << endl;

	list<int>::iterator it1 = find(lt.begin(), lt.end(), 2);
	list<int>::iterator it2 = find(lt.begin(), lt.end(), 6);

	list<int>::iterator itnew = lt.erase(it1,it2); 

	cout << "返回的迭代器指向的元素为" << *itnew;
	cout << endl;
	cout << endl;

	cout << "insert删除一个元素后的lt为:";
	for (auto num : lt) {
		cout << num << " ";
	}
	cout << endl;
	return 0;
}

在这里插入图片描述

3.5.7 swap()——交换元素

swap的作用就是交换两个list的元素,list1.swap(list2),两个list存储的元素类型必须相同,元素个数可以不同

int main()
{
	vector<int> v{ 1,2,3,4,5,6 };
	list<int> lt1(v.begin(), v.end());
	for (auto a : lt1) {
		cout << a << " ";
	}
	cout << endl;
	cout << endl;

	list<int>lt2(10, 8);
	for (auto a : lt2) {
		cout << a << " ";
	}
	cout << endl;
	cout << endl;

	lt1.swap(lt2);

	for (auto a : lt1) {
		cout << a << " ";
	}
	cout << endl;
	cout << endl;

	for (auto a : lt2) {
		cout << a << " ";
	}
	cout << endl;
	cout << endl;

	return 0;
}

在这里插入图片描述

3.6 list的常见操作函数

函数声明接口说明
splice将元素从列表转移到其它列表
remove删除具有特定值的元素
remove_if删除满足条件的元素
unique删除重复值
sort容器中的元素排序
merge合并排序列表
reverse反转元素的顺序
assign将值赋给容器

3.6.1 splice()——从另一个list中移动元素

splice 方法用于将另一个 std::list 的元素插入到当前列表的指定位置

splice共有三种形式:

  • splice(iterator_pos, otherList) : 将otherList中的所有元素移动到iterator_pos指向元素之前
  • splice(iterator_pos, otherList, iter1): 从 otherList转移 iter1 指向的元素到当前list。元素被插入到 iterator_pos指向的元素之前
  • splice(iterator_pos, otherList, iter_start, iter_end) : 从 otherList转移范围 [iter_start, iter_end) 中的元素到 当前列表。元素被插入到 iterator_pos指向的元素之前

注意:
1、splice 操作不会进行元素的复制或移动,只是修改指针连接,因此效率较高,插入操作的时间复杂度为 O(1)
2、在 splice 操作后,被移动的元素将不再属于原始列表
3、splice 操作后,原始列表和插入列表的大小会相应改变

int main() {
    std::list<int> list1 = { 1, 2, 3, 4, 5 };
    std::list<int> list2 = { 10, 20, 30 };
    std::list<int> list3 = { 1, 2, 3, 4, 5 };
    std::list<int> list4 = { 10, 20, 30 };
    std::list<int> list5 = { 1, 2, 3, 4, 5 };
    std::list<int> list6 = { 10, 20, 30 };

     //用法一 : splice(iterator_pos, otherList),将list2中所有元素插入到list1的第一个位置
    list1.splice(list1.begin(), list2);
    cout << "转移list2元素到list1之后的list1: ";
    for (int i : list1) {
        std::cout << i << " ";
    }
    std::cout << std::endl;
    std::cout << "转移list2元素到list1之后的list1: ";
    for (int i : list2) {
        std::cout << i << " ";
    }
    std::cout << std::endl;

     //用法二:splice(iterator_pos, otherList, iter1)
    auto it = list3.begin();
    std::advance(it, 2);//// 将迭代器向后移动两个位置,指向第三个元素
    list3.splice(it, list4, list4.begin());    // 将list4的第一个元素(10)插入到list3的第三个位置
    std::cout << "转移list4元素到list3之后的list3: ";
    for (int i : list3) {
        std::cout << i << " ";
    }
    std::cout << std::endl;
    std::cout << "转移list4元素到list3之后的list4: ";
    for (int i : list4) {
        std::cout << i << " ";
    }
    std::cout << std::endl;
    //用法三:splice(iterator_pos, otherList, iter_start, iter_end),将list5中第二个到第四个元素移动到list6的末尾
    auto first = list5.begin();
    std::advance(first, 1);
    auto last = list5.begin();
    std::advance(last, 4);
    list6.splice(list6.end(), list5, first, last);
    std::cout << "转移list5元素到list6之后的list5: ";
    for (int i : list5) {
        std::cout << i << " ";
    }
    std::cout << std::endl;
    std::cout << "转移list5元素到list6之后的list6: ";
    for (int i : list6) {
        std::cout << i << " ";
    }
    std::cout << std::endl;
    return 0;
}

在这里插入图片描述

3.6.2 remove()——移除特定值的元素

remove 用于从列表中移除与指定值相等的元素

int main()
{
	vector<int> v{ 1,2,3,4,5,6 };
	list<int> lt1(v.begin(), v.end());
	for (auto a : lt1) {
		cout << a << " ";
	}
	cout << endl;
	cout << endl;

	lt1.remove(4);
	for (auto a : lt1) {
		cout << a << " ";
	}
	cout << endl;

	return 0;
}

在这里插入图片描述

3.6.3 remove_if()——移除满足特定标准的元素

使用 remove_if 方法可以从 mylist 中移除所有满足函数func的元素,下边的例子中定义了一个函数isEven(),判断一个数字是否为偶数

使用方式:remove_if(func)

bool isEven(int n)
{
	return n % 2 == 0;
}
int main()
{
	vector<int> v{ 1,2,3,4,5,6 };
	list<int> lt1(v.begin(), v.end());
	for (auto a : lt1) {
		cout << a << " ";
	}
	cout << endl;
	cout << endl;
	
	lt1.remove_if(isEven);
	for (auto a : lt1) {
		cout << a << " ";
	}
	cout << endl;

	return 0;
}

在这里插入图片描述

3.6.4 unique()——删除连续的重复元素

unique()方法用于移除链表中相邻且重复的元素,仅保留一个副本

int main()
{
	vector<int> v{ 1,1,2,3,3,3,4,5,5,5,5,6 };
	list<int> lt1(v.begin(), v.end());
	for (auto a : lt1) {
		cout << a << " ";
	}
	cout << endl;
	cout << endl;

	lt1.unique();
	for (auto a : lt1) {
		cout << a << " ";
	}
	cout << endl;

	return 0;
}

在这里插入图片描述
注意: 若想使用unique函数做到真正的去重,还需在去重前对容器内元素进行排序

3.6.5 sort()——对元素进行排序

sort()方法用于对链表中的元素进行排序。默认情况下,它按升序对元素进行排序,使用元素类型的 < 运算符进行比较

int main()
{
	vector<int> v{ 1,5,3,8,2,10,6,27,9 };
	list<int> lt1(v.begin(), v.end());
	for (auto a : lt1) {
		cout << a << " ";
	}
	cout << endl;
	cout << endl;

	lt1.sort();
	for (auto a : lt1) {
		cout << a << " ";
	}
	cout << endl;

	return 0;
}

在这里插入图片描述

3.6.6 merge()——合并list

将两个已排序的列表合并成一个有序的列表。merge()方法将另一个列表的元素插入到调用方法的列表中,并保持排序顺序

注意:merge()方法只能用于已排序的list。如果list未排序,则合并的结果将是不正确的

int main()
{
	vector<int> v{ 1,5,3,8,2,10,6,27,9 };
	list<int> lt1(v.begin(), v.end());
	lt1.sort();
	for (auto a : lt1) {
		cout << a << " ";
	}
	cout << endl;

	list<int> lt2 = { 2, 4, 6 };
	for (auto b : lt2) {
		cout << b << " ";
	}
	cout << endl;

	lt1.merge(lt2);
	

	cout << "合并后的lt1为:";
	for (auto a : lt1) {
		cout << a << " ";
	}
	cout << endl;

	return 0;
}

在这里插入图片描述

3.6.7 reverse()——将该链表的所有元素的顺序反转 (C++11)

reverse()方法用于反转链表中元素的顺序,即将链表中的第一个元素变为最后一个元素,第二个元素变为倒数第二个元素,以此类推

int main()
{
	vector<int> v{ 1,5,3,8,2,10,6,27,9 };
	list<int> lt1(v.begin(), v.end());
	lt1.sort();
	for (auto a : lt1) {
		cout << a << " ";
	}
	cout << endl;
	cout << endl;

	lt1.reverse();
	for (auto a : lt1) {
		cout << a << " ";
	}
	cout << endl;
	return 0;
}

在这里插入图片描述

3.6.8 assign()——将值赋给容器

assign()用于将链表中的元素替换为新的元素序列。它可以接受不同形式的参数,

提供了两种重载形式:

  • 第一种形式接受迭代器范围作为参数,用于将另一个容器或数组中的元素复制到链表中。它会将链表清空,并将指定范围内的元素复制到链表中。void assign(InputIterator first, InputIterator last);
  • 第二种形式接受一个元素数量和一个值作为参数,用于将指定数量的相同值的元素分配给链表。它会将链表清空,并将指定数量的元素赋值为指定的值。void assign(size_type count, const T& value);
int main()
{
	list<int> lt1;
	vector<int> v{ 1,5,3,8,2,10,6,27,9 };

	lt1.assign(v.begin(), v.end());
	for (auto a : lt1) {
		cout << a << " ";
	}
	cout << endl;
	cout << endl;

	lt1.assign(8, 8);
	for (auto a : lt1) {
		cout << a << " ";
	}
	cout << endl;
	return 0;
}

在这里插入图片描述

四、vector 与 list 的对比

对比vectorlist
底层结构动态顺序表,连续空间带头结点的双向循环链表
访问支持随机访问,首地址+下标不能随机访问,可通过find查找,访问随即元素时间复杂度O(N)
插入删除任意位置插入和删除效率低,需要搬移元素,时间复杂度为O(N),插入时有可能需要增容,增容:开辟新空间,拷贝元素,释放旧空间,导致效率更低任意位置插入和删除效率高,不需要搬移元素,时间复杂度为O(1)
空间利用率底层为连续空间,不容易造成内存碎片,空间利用率较高,缓存利用率高。可以一次将一个数据附近的空间都加载到缓存,不用频繁地从内存读取数据底层节点动态开辟,容易造成内存碎片,空间利用率低,缓存利用率低
迭代器原生态指针对指针进行了封装
迭代器失效容量相关的操作都有可能导致迭代器失效,如插入引起的扩容,删除元素等插入元素不会导致迭代器失效,删除节点会导致,且只影响当前迭代器,其他迭代器不受影响
使用场景不关心插入和删除效率,支持随机访问大量插入和删除操作,不关心随机访问的场景、
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值