列表(list)

news2024/11/14 3:11:55

一、前言

 本次博客主要讲解 list 容器基本操作、常用接口做一个系统的整理,结合具体案例熟悉自定义内部排序方法的使用如有任何错误,欢迎在评论区指出,我会积极改正。

二、什么是list

listC++的一个序列容器插入和删除元素的效率较高时间复杂度常数级别list容器的底层数据结构为带头双向循环链表,这使得 list的元素可以存储在非相邻的内存中,在list内部,不同元素之间通过指向前一个元素的指针以及指向后一个元素的指针相关联。它的数据由若干个节点构成,每一个节点都包括一个信息块(即实际存储的数据)​、一个前驱指针和一个后驱指针,可以向前也可以向后进行访问,但不能随机访问。列表的定义在头文件<list>中。list 容器与其他序列容器如vector deque array相比,由于其底层数据结构为带头双向循环链表,因此 list 在插入删除元素方面很有优势在列表的任意位置进行插入和删除操作的时间复杂度为O(1)。但不能直接通过位置(下标)来直接访问元素。想要访问list的某个元素,必须从list的一端(或已知位置)迭代到该元素。另外,list还需要额外的存储空间来储存前一个元素和后一个元素的链接信息。

1.list的存储结构

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

2.list 容器的优点

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

3.list容器的缺点

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

头文件:

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

#include<list>

三、list 容器的定义

单独定义一个 list

list <typename> name;

   这里的typename可以是任何基本类型,例如int、double、char、结构体等,也可以是STL标准容器,例如string、set、queue、vector等。
       注意:使用前必须加上头文件:#include <list>

 四、list 容器常用接口的使用

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

在 C++ 中,std::list 是一个双向链表容器,提供了一些灵活的初始化方式。以下是 std::list 的常见构造(初始化)方法:

(1)默认构造函数

创建一个空list,不包含任何元素。

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

int main(){

    list<int> str_a;    //list定义的int类型的列表

    return 0;
}

(2)使用指定数量的元素构造

使用 n 个元素初始化 list,每个元素的值为默认值(例如,对于 int,默认值为 0)。

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

int main(){

    list<int> myList(5); // 列表包含 5 个元素,默认值为 0
    
    return 0;
}

也可以指定一个初始值 val,为所有元素赋相同的值。

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

int main(){

    list<int> myList(5, 10); // 列表包含 5 个元素,每个元素的值为 10

    return 0;
}

(3)使用初始化列表构造

使用花括号 {} 来初始化 list,指定初始元素的值。

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

int main(){

    list<int> myList = {1,2,3,4,5}; //列表包含5个元素,依次为1,2,3,4,5

    return 0;
}

(4)拷贝构造函数

使用另一个 list 来初始化新的 list,会创建一个原列表的副本。

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

int main(){

    list<int> originalList = {1, 2, 3};
    list<int> copiedList(originalList); 
    // 使用 originalList 初始化 copiedList,列表包含 3 个元素,依次为 1, 2, 3

    return 0;
}

(5)移动构造函数

使用 move 将一个临时 list 资源转移到新 list 中,从而避免拷贝开销。

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

int main(){

    list<int> originalList = {1, 2, 3};
    list<int> movedList(move(originalList)); // originalList 变为空,movedList 拥有原始数据

    return 0;
}

(6)范围构造函数

使用迭代器范围 [first, last) 初始化 list,可以将其他容器的部分或全部内容拷贝到 list 中。

#include <iostream>
#include <list>
#include <vector>

using namespace std;

int main(){

    vector<int> vec = {1, 2, 3, 4, 5};
    list<int> myList(vec.begin(), vec.end()); // 使用 vector 的元素初始化 list
    
    return 0;
}

(7)使用 assign 赋值

虽然这不是构造函数,但 assign 可以在声明后直接赋值初始化。

#include <iostream>
#include <list>
#include <vector>

using namespace std;

int main(){

    list<int> myList;
    myList.assign(5, 10); // 列表包含 5 个元素,每个元素的值为 10


    return 0;
}

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

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

注意:遍历链表-------只能用**迭代器**和**范围for**

  • begin与end为正向迭代器,对迭代器执行++操作,迭代器向后移动
  • rbegin(end)与rend(begin)为反向迭代器,对迭代器执行++操作,迭代器向前移动

迭代器

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

(1). 使用迭代器遍历

通过 begin()end() 获取 list 的起始和终止迭代器,使用迭代器遍历 list

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

int main(){

    list<int> myList = {1,2,3,4,5};

    // 使用普通迭代器遍历
    for(list<int>::iterator it = myList.begin(); it != myList.end(); it++){
        cout << *it << " ";
    }
    cout << endl; //输出:1 2 3 4 5 
    return 0;
}
  • 注意:begin与end为正向迭代器,对迭代器执行++操作,迭代器向后移动

 rbegin和rend

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

反向迭代器遍历容器:

#include <iostream>
#include <list>
using namespace std;
int main()
{
	int array[] = { 1,2,3,4,5,6,7,8 };
	// 用已有的数组 初始化 list 链表
	list<int> lt(array, array + sizeof(array) / sizeof(array[0]));
	// 正向迭代器遍历容器
	list<int>::reverse_iterator it = lt.rbegin();
	// 开始循环遍历
	while (it != lt.rend())
	{
		cout << *it << " ";    // 8 7 6 5 4 3 2 1
		it++;
	}
	cout << endl;
	return 0;
}
  • 注意:rbegin(end)与rend(begin)为反向迭代器,对迭代器执行++操作,迭代器向前移动

(2)使用基于范围的 for 循环(C++11)

在 C++11 及以上版本中,可以使用基于范围的 for 循环简化遍历过程。

#include <iostream>
#include <list>

using namespace std;

int main(){

    list<int> myList = {1,2,3,4,5};


    for(int value : myList){
        cout << value << " ";
    }
    cout << endl; // 输出:1 2 3 4 5

    return 0;
}

4.3 list 容器的常见容量操作

接口名称接口说明
empty()判断 list 是否为空
size返回容器中有效元素个数
resize(

调整容器的有效元素大小(size)

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

(1)empty()

判断 list 是否为空。如果 list 不包含任何元素,则返回 true,否则返回 false

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

int main(){
    list<int> myList;

    if(myList.empty()) {
        cout << "The list is empty." << endl;
    } else{
        cout << "The list is not empty." << endl;
    }
    return 0; // 输出:The list is empty.
}

(2)size()

返回 list 中元素的数量。

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

int main()
{
    list<int> myList = {1,2,3,4,5};
    cout << "Size of the list: " << myList.size()<<endl; // 输出5
    return 0;
}

(3)resize()

调整 list 的大小。如果新大小比当前大小大,则会在 list 的末尾添加默认值的元素;如果新大小比当前大小小,则会移除多余的元素。

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

void PrintList(list<int> l){

    list<int>::iterator it = l.begin();
    while(it != l.end()){
        cout << *it << " ";
        it ++;
    }
    cout << endl;
}

int main(){

    list<int> myList = {1,2,3,4,5};

    // 缩小列表的大小
    myList.resize(3); // 现在myList只包含1,2,3
    PrintList(myList);

    //扩大列表的大小,添加默认值0
    myList.resize(6); // 现在myList包含1,2,3,0,0,0
    PrintList(myList);
    return 0;
}

(4)clear

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

#include <iostream>
#include <list>
using namespace std;
 
int main()
{
	list<int> lt(5, 2);
	for (auto e : lt)
	{
		cout << e << " ";
	}
	cout << endl; //2 2 2 2 2
	cout << lt.size() << endl; //5
	lt.clear(); //清空容器
	for (auto e : lt)
	{
		cout << e << " ";
	}
	cout << endl; //(无数据)
	cout << lt.size() << endl; //0
	return 0;
}

list 容量的常见访问操作

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

front()返回list第一个元素

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

int main(){
    list<int> mylist {1,2,3,4,5,6,7,8};
    cout << "初始化后的mylist为: ";
    for(auto num: mylist){
        cout << num<< " ";
    }
    int front = mylist.front(); // 1
    cout << "\nmylist的头元素为: " << front;

    return 0;
}
 ②  back()——访问list尾元素

back()返回list第一个元素
示例如下: 

💻示例代码💻 

#include<iostream>
#include<list>

using std::cout;
using std::endl;
using std::list;

int main() {
    list<int> mylist {1, 2, 3, 4, 5, 6, 7, 8};
    cout<< "初始化后的mylist为:";
    for (auto num : mylist) {
        cout<< num<< " ";
    }
    int front = mylist.back();  // 8

    cout<< "\nmylist的头元素为:"<< front;
}

list 容器的常见修改操作

接口名称接口说明
push_front在list首元素前插入值为val的元素
pop_front

删除list中第一个元素

push_back在list尾部插入值为val的元素
pop_back删除list中最后一个元素
insert在list position 位置中插入值为val的元素
erase删除list position位置的元素
swap交换两个list中的元素
① push_back()——添加元素(list尾部)

 向list中添加元素,使用push_back()方法,作用是向list尾部添加一个元素。示例如下:

 💻示例代码💻

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

int main(){

    list<int> mylist{1,2,3,4};
    cout << "初始化后的mylist为: ";
    for(auto num:mylist){
        cout <<num<<" ";
    }
    //在list尾部插入一个元素8
    mylist.push_back(8);
    cout << "\n尾部插入一个元素后的mylist为: ";
    for(auto num: mylist){
        cout << num << " "; //1 2 3 4 8
    }
    return 0;
}
② pop_back()——移除list元素(尾部)

删除list中的元素,使用pop_back()方法,作用是删除list尾部的一个元素。示例如下:

💻示例代码💻 

#include <list>
#include <iostream>
 
using std::cout;
using std::list;
using std::endl;
 
int main() {
    list<int> mylist{1, 2, 3, 4};
    cout << "初始化后的mylist为:";
    for (auto num : mylist) {
        cout << num << " ";
    }
    // 删除mydeue尾部一个元素
    mylist.pop_back();
    cout << "\n尾部删除一个元素后的mylist为:";
    for (auto num : mylist) {
        cout << num << " ";   // 1 2 3
    }
}
 ③ pop_front()——删除list元素(头部)

 删除list中的元素,使用pop_front()方法,作用是删除list头部的一个元素。示例如下:

💻示例代码💻 

#include <list>
#include <iostream>
 
using std::cout;
using std::list;
using std::endl;
 
int main() {
    list<int> mylist{1, 2, 3, 4};
    cout << "初始化后的mylist为:";
    for (auto num : mylist) {
        cout << num << " ";
    }
    // 删除mydeue头部一个元素
    mylist.pop_front();
    cout << "\n头部删除一个元素后的mylist为:";
    for (auto num : mylist) {
        cout << num << " ";    // 2 3 4
    }
}
④ push_front()——添加元素(list头部)

 向list中添加元素,使用push_front()方法,作用是向list头部添加一个元素。示例如下:

💻示例代码💻 

#include <list>
#include <iostream>
 
using std::cout;
using std::list;
using std::endl;
 
int main() {
    list<int> mylist{1, 2, 3, 4};
 
    cout << "初始化后的mylist为:";
    for (auto num : mylist) {
        cout << num << " ";
    }
    // 在list头部插入一个元素8
    mylist.push_front(8);
 
    cout << "\n头部插入一个元素后的mylist为:";
    for (auto num : mylist) {
        cout << num << " ";  // 8 1 2 3 4
    } 
}
⑤ insert()——添加元素(任意位置)

insert共有三种形式:
- insert(iterator, value);
- insert(iterator, num, value);
- insert(iterator, iterator1, iterator2); 

用法一:list.insert(iterator,value) 

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

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

void PrintList(list<int> l){
    for(auto num : l){
        cout << num << " ";
    }
    cout << endl;
}

int main(){

    list<int> mylist{1,2,3,4};
    cout <<"初始化后的mylist为:";
    PrintList(mylist);
    // it 指向mylist的第二个元素
    list<int>::iterator it = mylist.begin();
    it  ++;

    // 使用insert添加一个元素
    list<int>::iterator itnew = mylist.insert(it,10);
    cout << "\n返回的迭代器指向的元素为: " << *itnew << endl;
    PrintList(mylist);

    return 0;
}

用法二:list.insert(iterator,num,value) 

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

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

void PrintList(list<int> l){

    for(auto num: l){

        cout << num << " ";
    }
    cout << endl;
}

int main(){

    list<int> mylist{1,2,3,4};
    cout << "初始化后的mylist为: ";
    for(auto num : mylist){
        cout << num << " ";
    }
    // it 指向mylist的第二个元素
    list<int>::iterator it = mylist.begin();
    it ++;
    //使用insert添加2个元素,value为20
    mylist.insert(it, 2, 20);
    PrintList(mylist);

    return 0;
}

用法三:insert(iterator, iterator1, iterator2)

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

 

 💻示例代码💻

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

void PrintList(list<int> l)
{
    for(auto num: l){
        cout << num << " ";
    }
    cout << endl;
}

int main(){
    list<int> mylist{1,2,3,4};
    cout << "初始化后的mylist为: ";
    // it指向mylist的第二个元素
    list<int>::iterator it = mylist.begin();
    it ++;
    //定义一个辅助list
    list<int> list{20,30,40};
    //it1指向list的第一个元素
    ::list<int>::iterator it1 = list.begin();
    // it2指向list2的最后一个元素后一个位置
    ::list<int>::iterator it2 = list.end();
    // 使用insert在2之前添加[it1,it2]之间的元素
    mylist.insert(it,it1,it2);
    cout << "\n使用insert插入元素后:";
    PrintList(mylist);


    return 0;
}
⑥ erase()——删除元素(任意位置)

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

 erase 共有 两 种形式:
list.erase(iterator)
list.erase(iterator1,iterator2)

 用法一:list.erase(iterator)

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

 💻示例代码💻

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

void PrintList(list<int> l){

    for( auto num: l){
        cout << num<< " ";
    }

}

int main(){

    list<int> mylist{1,2,3,4};
    cout <<"初步化后的mylist为:";
    // it指向mylist的第二个元素
    list<int>::iterator it = mylist.begin();
    it ++ ;
    //删除it指向的元素,即2,并返回一个迭代器指向2之后的元素
    list<int>::iterator itnew = mylist.erase(it);
    cout << "\n删除元素后返回的迭代器itnew指向的元素为:"<< *itnew;
    cout << "\n使用erase删除元素后:";
    PrintList(mylist);

}

 用法二:list.erase(iterator1,iterator2) 

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

💻示例代码💻 

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

void PrintList(list<int> l){

    for( auto num: l){
        cout << num<< " ";
    }

}

int main(){

    list<int> mylist{1,2,3,4};
    cout << "初始化后的mylist为:";
    PrintList(mylist);

    //it1指向mylist的第2个元素
    list<int>::iterator it1 = mylist.begin();
    it1 ++;
    // it2指向最后一个元素的最后一个位置
    list<int>::iterator it2 = mylist.end();

    // 删除[it1,it2]之间的元素,即删除2,3,4
    mylist.erase(it1,it2);
    cout << "\n使用erase删除元素后:";
    PrintList(mylist);

    return 0;
}
⑦ swap()——交换元素 ​​​​​​​

 ❤swap的作用就是交换两个list的元素

交换两个list的元素,使用 swap()方法, list1.swap(list2),两个list存储的元素类型必须相同,元素个数可以不同。示例如下: 

💻示例代码💻 

/*交换两个list的元素,使用swap()方法,list1.swap(list2),
  两个list存储的元素类型必须相同,元素个数可以不同。
*/
#include <list>
#include <iostream>
using namespace std;

void PrintList(list<int> l){

    for( auto num: l){
        cout << num<< " ";
    }
    cout << endl;

}

int main(){

    list<int> mylist1{1,11,111,1111};
    list<int> mylist2{2,22,222};
    cout << "初始化后的mylist1为:";
    PrintList(mylist1);

    cout << "初始化后的mylist2为:";
    PrintList(mylist2);
    //交换两个列表的元素·
    mylist1.swap(mylist2);
    //交换后mylist1为:
    cout << "使用swap()交换后mylist1为:";
    PrintList(mylist1);

    cout << "使用swap()交换后mylist1为:";
    PrintList(mylist2);

    return 0;
}

输出:

初始化后的mylist1为:1 11 111 1111 
初始化后的mylist2为:2 22 222 
使用swap()交换后mylist1为:2 22 222 
使用swap()交换后mylist1为:1 11 111 1111 

list 容器的常见操作函数

函数声明接口说明
splice将元素从列表转移到其它列表
remove删除具有特定值的元素
remove_if删除满足条件的元素
unique删除重复值
sort容器中的元素排序
merge合并排序列表
reverse反转元素的顺序
① 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 操作不会进行元素的复制或移动,只是修改指针连接,因此效率较高。
2. 在 splice 操作后,被移动的元素将不再属于原始列表。
3. splice 操作后,原始列表和插入列表的大小会相应改变。
4. 插入操作的时间复杂度为 O(1) 

💻示例代码💻 

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

void PrintList(list<int> l){

    for( auto num: l){
        cout << num<< " ";
    }
    cout << endl;

}

int main(){
    list<int> list1{1,2,3,4,5};
    list<int> list2{10,20,30};
    list<int> list3{1,2,3,4,5};
    list<int> list4{10,20,30};
    list<int> list5{1,2,3,4,5};
    list<int> list6{10,20,30};
    cout << "初始化之后的list1: ";
    PrintList(list1);
    /*
     用法一 : splice(iterator_pos, otherList)
    */
    // 将list2中所有元素插入到list1的第一个位置
    list1.splice(list1.begin(),list2);
    // 输出结果
    cout << "转移list2元素到list1之后的list1: ";
    PrintList(list1);
    cout << "转移list2元素到list1之后的list2: ";
    PrintList(list2);
    /*
        用法二:splice(iterator_pos, otherList, iter1)
     */
    auto it = list3.begin();
    //将迭代器向后移动两个位置,指向第三个元素
    advance(it,2);
    //将list4的第一个元素(10)插入到list3的第三个位置
    list3.splice(it,list4,list4.begin());
    //输出结果
    cout << "转移list4元素到list3之后的list3: ";
    PrintList(list3);
    cout << "转移list4元素到list3之后的list4: ";
    PrintList(list4);
    /*
      用法三:splice(iterator_pos, otherList, iter_start, iter_end)
     */
    auto it2 = list5.begin();
    advance(it2,2);
    list5.splice(it2,list6,list6.begin(),list6.end());
    cout << "转移list6元素到list5之后的list5: ";
    PrintList(list5);
    cout << "转移list6元素到list5之后的list6: ";
    PrintList(list6);

    return 0;
}

运行结果:

初始化之后的list1: 1 2 3 4 5 
转移list2元素到list1之后的list1: 10 20 30 1 2 3 4 5 
转移list2元素到list1之后的list2: 
转移list4元素到list3之后的list3: 1 2 10 3 4 5 
转移list4元素到list3之后的list4: 20 30 
转移list6元素到list5之后的list5: 1 2 10 20 30 3 4 5 
转移list6元素到list5之后的list6: 
② remove()——移除特定值的元素

std::list 的 remove 方法用于从列表中移除与指定值相等的元素。示例如下: 

#include <iostream>
#include <list>

int main() {
    std::list<int> mylist {1, 2, 3, 4, 5};
    // 移除列表中所有值为2的元素
    mylist.remove(2);
    std::cout << "移除之后的mylist: ";
    for (const auto& element : mylist) {
        std::cout << element << " ";
    }
    std::cout << std::endl;
    return 0;
}
③ remove_if()——移除满足特定标准的元素 
使用方式:remove_if(func)

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

💻示例代码💻 

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

bool isEven(int n){
    return n % 2 == 0;
}
int main(){

    list<int> mylist{1,2,3,4,5};
    // 一处列表中所有满足 isEven 的元素(偶数)

    mylist.remove_if(isEven);
    cout << "移除之后的mylist: ";

    for(const auto& element : mylist){
        cout << element << " ";
    }
    cout << endl;

    return 0;
}

 📄输出📄

移除之后的mylist: 1 3 5 

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

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

💻示例代码💻 

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

int main(){

    list<int> mylist{1,2,2,3,3,4,5,5,5};
    cout << "初始化后的list为: ";
    for(auto i: mylist){
        cout << i << " ";
    }
    cout << endl;
    mylist.unique();
    cout << "执行unique后的list为: ";
    for (auto i: mylist){
        cout << i << " ";
    }
    cout << endl;

    return 0;
}

运行结果:

初始化后的list为: 1 2 2 3 3 4 5 5 5 
执行unique后的list为: 1 2 3 4 5 
⑤ sort()——对元素进行排序 

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

💻示例代码💻 

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

void PrintList(list<int> l){

    for( auto num: l){
        cout << num << " ";
    }
    cout << endl;
}

int main(){

    list<int> mylist{5,0,3,2,4,1};
    cout << "初始化后的list为 ";
    PrintList(mylist);
    mylist.sort();
    cout << "经过sort排序后的list为:";
    PrintList(mylist);

    return 0;
}

运行结果:

初始化后的list为 5 0 3 2 4 1 
经过sort排序后的list为:0 1 2 3 4 5 
⑥ merge()——合并list 

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

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

💻示例代码💻 

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

void PrintList(list<int> l){

    for( auto num: l){
        cout << num << " ";
    }
    cout << endl;
}

int main(){
    list<int> list1{1,3,5};
    list<int> list2{2,4,6};
    cout << "初始化后的list1为: ";
    PrintList(list1);
    cout << "初始化后的list2为: ";
    PrintList(list2);
    //将list2合并到list1中
    list1.merge(list2);
    // 输出合并后的列表
    cout << "合并后的list1为: ";
    PrintList(list1);
    return 0;
}

运行结果:

初始化后的list1为: 1 3 5 
初始化后的list2为: 2 4 6 
合并后的list1为: 1 2 3 4 5 6 
 ⑦ reverse()——将该链表的所有元素的顺序反转 【C++11】
 reverse()方法用于反转链表中元素的顺序,即将链表中的第一个元素变为最后一个元素,第二个元素变为倒数第二个元素,以此类推。示例如下:​​​​​​​

💻示例代码💻 

#include <iostream>
#include <list>

using namespace std;

void PrintList(list<int> l){

    for( auto num: l){
        cout << num << " ";
    }
    cout << endl;
}

int main(){

    list<int> mylist{1,2,0,3,4,5};
    cout <<"初始化list为:";
    PrintList(mylist);
    mylist.reverse();
    cout <<"Reverse后的list为:";
    PrintList(mylist);


    return 0;
}

代码运行结果:

初始化list为:1 2 0 3 4 5 
Reverse后的list为:5 4 3 0 2 1 
 ⑧ assign()——将值赋给容器

assign()方法用于将链表中的元素替换为新的元素序列。它可以接受不同形式的参数,提供了两种重载形式。

  • 第一种形式接受迭代器范围作为参数,用于将另一个容器或数组中的元素复制到链表中。它会将链表清空,并将指定范围内的元素复制到链表中。void assign(InputIterator first,InputIteratorlast);
  • 第二种形式接受一个元素数量和一个值作为参数,用于将指定数量的相同值的元素分配给链表。它会将链表清空,并将指定数量的元素赋值为指定的值。void assign(size_type count, const T& value);

💻示例代码💻 

#include <iostream>
#include <vector>
#include <list>

int main() {
    std::list<int> myList;
    // 使用迭代器范围进行分配
    std::vector<int> numbers = {1, 2, 3, 4, 5};
    myList.assign(numbers.begin(), numbers.end());
    std::cout << "第一次执行assign之后的list为: ";
    for (auto i : myList) {
        std::cout << i << " ";
    }
    std::cout << std::endl;
    // 使用元素数量和值进行分配
    myList.assign(3, 100);
    std::cout << "第二次执行assign之后的list为: ";
    for (auto i : myList) {
        std::cout << i << " ";
    }
    std::cout << std::endl;
    return 0;
}

运行结果:

第一次执行assign之后的list为: 1 2 3 4 5
第二次执行assign之后的list为: 100 100 100 

五、vector 与 list  的对比

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

​​​​​​​

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2239864.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Sam Altman:年底将有重磅更新,但不是GPT-5!

大家好&#xff0c;我是木易&#xff0c;一个持续关注AI领域的互联网技术产品经理&#xff0c;国内Top2本科&#xff0c;美国Top10 CS研究生&#xff0c;MBA。我坚信AI是普通人变强的“外挂”&#xff0c;专注于分享AI全维度知识&#xff0c;包括但不限于AI科普&#xff0c;AI工…

zabbix监控端界面时间与服务器时间不对应

1. 修改系统时间 # tzselect Please select a continent, ocean, "coord", or "TZ".1) Africa2) Americas3) Antarctica4) Asia5) Atlantic Ocean6) Australia7) Europe8) Indian Ocean9) Pacific Ocean 10) coord - I want to use geographical coordina…

大数据新视界 -- 大数据大厂之 Impala 性能提升:高级执行计划优化实战案例(下)(18/30)

&#x1f496;&#x1f496;&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎你们来到 青云交的博客&#xff01;能与你们在此邂逅&#xff0c;我满心欢喜&#xff0c;深感无比荣幸。在这个瞬息万变的时代&#xff0c;我们每个人都在苦苦追寻一处能让心灵安然栖息的港湾。而 我的…

P2356 弹珠游戏

铁子们好呀&#xff0c;博主好久没更新了&#xff0c;今天给大家更新一道编程题&#xff01;&#xff01;&#xff01; 题目链接如下&#xff1a;P2356 弹珠游戏 好&#xff0c;接下来&#xff0c;我将从三个方面讲解这道例题。分别是 题目解析算法原理代码实现 文章目录 1.题…

项目管理十大知识领域:如何提升项目执行力

项目管理是一门复杂的学科&#xff0c;涉及到多个领域的知识与技能。有效的项目管理不仅能够确保项目按时、按质、按预算完成&#xff0c;还能提升团队协作、提高效率&#xff0c;甚至在面对风险和变化时保持项目的稳定性和成功率。项目管理十大知识领域是构建成功项目的基石&a…

【miniMax开放平台-注册安全分析报告-无验证方式导致安全隐患】

前言 由于网站注册入口容易被黑客攻击&#xff0c;存在如下安全问题&#xff1a; 暴力破解密码&#xff0c;造成用户信息泄露短信盗刷的安全问题&#xff0c;影响业务及导致用户投诉带来经济损失&#xff0c;尤其是后付费客户&#xff0c;风险巨大&#xff0c;造成亏损无底洞…

HBuilder使用虚拟机

按文档的连接一直不成功 没找到Simulator&#xff0c;原来是因为我电脑之前没安装过虚拟机版本 安装模拟器Simulator | uni-app官网 找到settings,左下角安装需要的对应版本的虚拟机就好了&#xff0c;然后重启hb

vcenter service基本异常处理

服务&#xff1a;vcenter service 版本&#xff1a; 7.0.3 问题描述&#xff1a;无法访问vcenter ui 排障思路&#xff1a; 1. 登入vcenter所在服务器执行基础排查&#xff1a;内存、cpu、磁盘、网络等&#xff0c;发现磁盘日志目录已经爆满&#xff0c;删除180天前的日志恢…

WordPress中最佳的无障碍插件:入门级指南

在今天的互联网时代&#xff0c;网站对所有用户都友好和可访问是非常重要的。对普通用户&#xff0c;特别是对有视力、听力或其他障碍的用户&#xff0c;为他们提供无障碍的体验显得尤为重要。使用WordPress建立网站的用户&#xff0c;有一些非常好的插件可以帮助你轻松实现这一…

科技前沿:汽车智能玻璃,开启透明显示新纪元

根据QYResearch调研团队最新发布的《全球汽车智能玻璃市场报告2023-2029》显示&#xff0c;预计到2029年&#xff0c;全球汽车智能玻璃市场的规模将攀升至0.5亿美元&#xff0c;且在未来几年内&#xff0c;其年复合增长率&#xff08;CAGR&#xff09;将达到5.5%。 以下图表展…

基于Multisim信号波形发生器电路正弦波方波三角波锯齿波(含仿真和报告)

【全套资料.zip】正弦方波三角波锯齿波方波占空比可调频率可调电路Multisim仿真设计数字电子技术 文章目录 功能一、Multisim仿真源文件二、原理文档报告资料下载【Multisim仿真报告讲解视频.zip】 功能 1.设计一个能够产生多个信号输出的信号发生器&#xff0c; 要求输出波形…

Spring Boot——日志介绍和配置

1. 日志的介绍 在前面的学习中&#xff0c;控制台上打印出来的一大堆内容就是日志&#xff0c;可以帮助我们发现问题&#xff0c;分析问题&#xff0c;定位问题&#xff0c;除此之外&#xff0c;日志还可以进行系统的监控&#xff0c;数据采集等 2. 日志的使用 在程序中获取日…

刘铁猛C#入门 024 类的声明,继承和访问控制

类声明的全貌 C#声明类的位置 声明既定义(C#与Java) 类的修饰符 最简单的类声明 类的访间控制 &#xff1a;默认internal 共性 public 和 internal 都是访问修饰符&#xff0c;用于定义一个类型的成员可以被谁访问。它们都可以用来声明类、结构、接口、枚举、字段、方法、…

人工智能(AI)对于电商行业的变革和意义

![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/402a907e12694df5a34f8f266385f3d2.png#pic_center> &#x1f393;作者简介&#xff1a;全栈领域优质创作者 &#x1f310;个人主页&#xff1a;百锦再新空间代码工作室 &#x1f4de;工作室&#xff1a;新空间代…

pgsql 版本升级和数据迁移(编译版)

最近给pgsql从16.0升级到16.4&#xff0c;有挺多细节 1.关闭pgsql 为了保证数据一致性和过渡平稳&#xff0c;还是需要暂停pgsql。 systemctl stop pgsql2.备份现有数据 需要切换到pgsql的用户&#xff0c;通常用root是不行的 pg_dumpall > /xxx/xxx/backup.sql3.重命名…

⚙️ 如何调整重试策略以适应不同的业务需求?

调整 Kafka 生产者和消费者的重试策略以适应不同的业务需求&#xff0c;需要根据业务的特性和容错要求来进行细致的配置。以下是一些关键的调整策略&#xff1a; 业务重要性&#xff1a; 对于关键业务消息&#xff0c;可以增加重试次数&#xff0c;并设置较长的重试间隔&#x…

uniCloud云对象调用第三方接口,根据IP获取用户归属地的免费API接口,亲测可用

需求 在2022年5月初&#xff0c;网络上各大平台上&#xff0c;都开始展示用户IP属地&#xff0c;在某音、某手等小视频平台以及各主流网站应用中&#xff0c;都展示IP归属地&#xff0c;如下图所示&#xff1a; 解决办法 收费文档的肯定有很多&#xff0c;基本你百度搜“归…

蓝桥杯PythonB组扫盲

题目分布&#xff08;参考2024年省赛&#xff09;&#xff1a;总共八道题&#xff0c;两填空8代码&#xff08;考察计算机基础知识和一些简单数学计算知识&#xff0c;不会太难&#xff0c;稍微准备下就行&#xff09;&#xff0c;六道程序设计题&#xff08;重点和难点&#x…

STM32单片机WIFI语音识别智能衣柜除湿消毒照明

实践制作DIY- GC0196-WIFI语音识别智能衣柜 一、功能说明&#xff1a; 基于STM32单片机设计-WIFI语音识别智能衣柜 二、功能介绍&#xff1a; STM32F103C系列最小系统板LCD1602显示器ULN2003控制的步进电机&#xff08;柜门开关&#xff09;5V加热片直流风扇紫外消毒灯DHT11…

git重置的四种类型(Git Reset)

git区域概念 1.工作区:IDEA中红色显示文件为工作区中的文件 (还未使用git add命令加入暂存区) 2.暂存区:IDEA中绿色(本次还未提交的新增的文件显示为绿色)或者蓝色(本次修改的之前版本提交的文件但本次还未提交的文件显示为蓝色)显示的文件为暂存区中的文件&#xff08;使用了…