【C++】链表(list)的使用以及与vector的区别

一、list 简介

在 C++ 中,std::list 是标准库提供的一个容器类,用于将数据进行链式存储。链表(list)是一种物理存储单元上非连续的存储结构,数据元素的逻辑顺序是通过链表中的指针链接实现的。

  • 链表的组成:链表由一系列结点组成。
  • 结点的组成:1.存储数据元素的数据域 2.存储下一个结点地址的指针域

STL中的链表是一个双向循环链表,由于链表的存储方式并不是连续的内存空间,因此链表list中的迭代器只支持前移和后移,属于双向迭代器


二、std::list 与 std::vector的区别

  1. 底层实现:

    • list 是由双向链表实现的,每个元素包含指向前一个和后一个元素的指针。这种实现使得在列表中的任意位置插入和删除元素都是高效的,但对于随机访问元素的性能较差。
    • vector 是由动态数组实现的,元素在内存中是连续存储的。这种实现使得随机访问元素的性能非常好,但在中间或开头插入/删除元素时会涉及元素的移动,性能相对较低。
  2. 动态调整大小:

    • list 的大小可以动态增长和缩小,因为它使用链表来存储元素,插入和删除操作的性能与列表的大小无关。
    • vector 的大小也可以动态增长,但在需要重新分配内存时,可能会导致大量的元素复制和内存重分配操作。
  3. 访问效率:

    • list 不支持随机访问,只能通过迭代器进行顺序访问。对于需要频繁插入和删除操作的场景,list 的性能更好。
    • vector 支持随机访问,可以通过下标直接访问元素。对于需要频繁的随机访问操作,vector 的性能更好。
  4. 内存占用:

    • list 在存储元素时,除了元素本身的值外,还需要额外的空间存储指向前一个和后一个元素的指针。因此,它通常比 vector 使用更多的内存。
    • vector 在存储元素时,只需要存储元素的值本身和一些额外的控制信息,因此通常比 list 使用更少的内存。
  5. 插入和删除操作:

    • list 对于在任意位置插入和删除元素来说是高效的,因为它只需要修改相邻元素的指针即可,不需要移动其他元素。list 有一个重要的性质,插入操作和删除操作都不会造成原有list迭代器的失效,这在vector中是不成立的。
    • vector 对于在末尾插入和删除元素来说是高效的,因为它只需要在数组的末尾进行操作,不需要移动其他元素。但在中间或开头插入/删除元素时,需要移动其他元素。

综上所述,选择使用 list 还是 vector 取决于具体的应用场景和需求。如果需要频繁的插入和删除操作,并且不需要频繁的随机访问元素,可以选择 list。如果需要频繁的随机访问元素,而插入和删除操作较少,可以选择 vector。另外,如果需要在容器的中间位置进行插入和删除操作,并且对访问效率要求不高,可以考虑使用 list


三、list 构造函数

构造函数原型 解释
1 list<T> lt 默认构造函数, 采用模板类实现
2 list(lt.begin(), lt.end()) 将lt[begin, end)区间中的元素拷贝给本身
3 list(n, Element) 构造函数将n个Element(元素)拷贝给本身
4 list(const list &lt) 拷贝构造函数

示例:

#include <iostream>
#include <list>     //必须包含该头文件
using namespace std;

void printVec(list<int> &v)
{
    
    
	for (list<int>::iterator At = v.begin(); At != v.end(); At++)
	{
    
    
		cout << *At << " ";
	}
	cout << endl;
}
void printVec(list<double> &v)
{
    
    
	for (list<double>::iterator At = v.begin(); At != v.end(); At++)
	{
    
    
		cout << *At << " ";
	}
	cout << endl;
}

void test01()
{
    
    
	list<int> v1;
	v1.push_back(10);  //添加元素
	v1.push_back(20);
	printVec(v1);

	list<int> v2(v1.begin(), v1.end());
	printVec(v2);

	list<double> v3(5, 6.32);
	printVec(v3);

	list<double> v4(v3);
	printVec(v4);
}

int main()
{
    
    
	test01();
	system("pause");
	return 0;
}
//result
10 20
10 20
6.32 6.32 6.32 6.32 6.32
6.32 6.32 6.32 6.32 6.32

注意:

list 作为函数的参数或者返回值时,不能缺少其中的“&”。


四、list 赋值

函数原型: = 、assign 解释
1 list& operator=(const list &lt) 重载=操作符
2 assign(begin, end) 将[begin, end)区间中的数据拷贝赋值给本身
3 assign(n, Element) 将n个Element拷贝赋值给本身

示例:

#include <iostream>
#include <list>     //必须包含该头文件
using namespace std;

void printVec(list<int> &v)
{
    
    
	for (list<int>::iterator At = v.begin(); At != v.end(); At++)
	{
    
    
		cout << *At << " ";
	}
	cout << endl;
}

void test01()
{
    
    
	list<int> v1;
	v1.push_back(10);  //添加元素
	v1.push_back(20);
	printVec(v1);

	list<int> v2 = v1;
	printVec(v2);

	list<int> v3;
	v3.assign(v1.begin(), v1.end());
	printVec(v3);

	list<int> v4;
	v4.assign(6, 1);
	printVec(v4);
}

int main()
{
    
    
	test01();
	system("pause");
	return 0;
}
//result
10 20
10 20
10 20
1 1 1 1 1 1

五、list 长度操作

函数原型:empty、size、resize 解释
1 empty() 判断容器是否为空
2 size() 返回容器中元素的个数
3 resize(int num) 重新指定容器的长度为num。若容器变长,则以默认值填充新位置; 如果容器变短,则末尾超出容器长度的元素被删除
4 resize(int num, Element) 重新指定容器的长度为num。若容器变长,则以Element值填充新位置; 如果容器变短,则末尾超出容器长度的元素被删除

示例:

#include <iostream>
#include <list>     //必须包含该头文件
using namespace std;

void printVec(list<int> &v)
{
    
    
	for (list<int>::iterator At = v.begin(); At != v.end(); At++)
	{
    
    
		cout << *At << " ";
	}
	cout << endl;
}

void test01()
{
    
    
	list<int> v1;
	if (v1.empty())     //判断是否为空
	{
    
    
		cout << "当前v1为空!" << endl;
	}

	v1.push_back(10);  //添加元素
	v1.push_back(20);
	v1.push_back(30);

	if (!v1.empty())
	{
    
    
		cout << "v1中元素个数:" << v1.size() << endl;
		printVec(v1);
	}

	v1.resize(5);
	printVec(v1);

	v1.resize(10, 1);
	printVec(v1);
}

int main()
{
    
    
	test01();
	system("pause");
	return 0;
}
//result
当前v1为空!
v1中元素个数:3
10 20 30
10 20 30 0 0
10 20 30 0 0 1 1 1 1 1

六、list 插入与删除

函数原型:push_back、pop_back、insert、erase、clear 解释
1 push_back(Element) 尾部插入元素Element
2 pop_back() 删除最后一个元素
3 push_front(Element) 在容器开头插入一个元素
4 pop_front() 从容器开头移除第一个元素
5 insert(iterator p, Element) 迭代器指向位置p插入元素Element
6 insert(iterator p, int n, Element) 迭代器指向位置p插入n个元素Element
7 insert(p,iterator start, iterator end) 在p位置插入[start,end)区间的数据,无返回值
8 erase(iterator p) 删除迭代器指向的元素
9 erase(iterator start, iterator end) 删除迭代器从start到end之间的元素
10 remove(elem) 删除容器中所有与elem值匹配的元素
11 clear() 删除容器中所有元素

示例:

#include <iostream>
#include <list>     //必须包含该头文件
using namespace std;

void printVec(list<int> &v)
{
    
    
	for (list<int>::iterator At = v.begin(); At != v.end(); At++)
	{
    
    
		cout << *At << " ";
	}
	cout << endl;
}

void test01()
{
    
    
	list<int> v1;
	v1.push_back(1);  //尾部添加元素
	v1.push_back(2);
	v1.push_back(3);
	v1.push_back(3);
	cout << "尾部添加元素: " << endl;
	printVec(v1);

	v1.pop_back();    //尾部删除元素
	cout << "尾部删除元素: " << endl;
	printVec(v1);

	v1.push_front(100);  //头部添加元素
	v1.push_front(200);
	v1.push_front(300);
	cout << "头部添加元素: " << endl;
	printVec(v1);

	v1.pop_front();   //头部删除元素
	v1.pop_front();
	cout << "头部删除元素: " << endl;
	printVec(v1);

	v1.insert(v1.begin(), 100);      //插入元素100
	cout << "插入元素100: " << endl;
	printVec(v1);

	v1.insert(v1.begin(), 5, 100);   //插入5个元素100
	cout << "插入5个元素100: " << endl;
	printVec(v1);

	v1.erase(v1.begin());    //删除元素
	cout << "删除元素v1.begin(): " << endl;
	printVec(v1);

	v1.remove(100);
	cout << "删除所有100元素: " << endl;
	printVec(v1);

	v1.clear();				 //清空容器
	printVec(v1);
}

int main()
{
    
    
	test01();
	system("pause");
	return 0;
}
//result
尾部添加元素:
1 2 3 3
尾部删除元素:
1 2 3
头部添加元素:
300 200 100 1 2 3
头部删除元素:
100 1 2 3
插入元素100:
100 100 1 2 3
插入5个元素100:
100 100 100 100 100 100 100 1 2 3
删除元素v1.begin():
100 100 100 100 100 100 1 2 3
删除所有100元素:
1 2 3

七、list 数据获取

函数原型:front()、back 解释
1 front() 返回容器中第一个数据元素
2 back() 返回容器中最后一个数据元素

示例:

#include <iostream>
#include <list>     //必须包含该头文件
using namespace std;

void test01()
{
    
    
	list<int> v1 = {
    
     1, 2, 3, 4, 5, 6 };
	cout << "v1.front() = " << v1.front() << endl;
	cout << "v1.back() = " << v1.back() << endl;
}

int main()
{
    
    
	test01();
	system("pause");
	return 0;
}
//result
v1.front() = 1
v1.back() = 6

八、list 互换、反转、排序

函数原型:swap、reverse、sort 解释
1 swap(list lt) 将lt中元素与本身的元素互换
2 reverse() 反转链表
3 sort() 链表排序

示例:

#include <iostream>
#include <list>     //必须包含该头文件
using namespace std;

void printVec(list<int> &v)
{
    
    
	for (list<int>::iterator At = v.begin(); At != v.end(); At++)
	{
    
    
		cout << *At << " ";
	}
	cout << endl;
}

void test01()
{
    
    
	list<int> v1 = {
    
     9, 5, 7, 8, 6 };
	list<int> v2 = {
    
     5, 4, 3, 2, 1 };

	v1.swap(v2);   //互换v1与v2中的元素
	cout << "list v1 : " ;
	printVec(v1);
	cout << "list v2 : " ;
	printVec(v2);

	v2.sort();  //链表排序
	cout << "v2链表排序 : ";
	printVec(v2);

	v2.reverse();  //反转链表v2
	cout << "v2反转链表 : ";
	printVec(v2);
}

int main()
{
    
    
	test01();
	system("pause");
	return 0;
}
//result
list v1 : 5 4 3 2 1
list v2 : 9 5 7 8 6
v2链表排序 : 5 6 7 8 9
v2反转链表 : 9 8 7 6 5

如果这篇文章对你有所帮助,渴望获得你的一个点赞!

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/AAADiao/article/details/131214952