初阶8 list

news2025/3/31 6:40:14

本章重点

  1. list的介绍
  2. list的基本使用
  3. list的模拟实现

1.list的介绍

  1. list是可以在常数范围内在任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代

  2. list的底层是双向链表结构,双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向其前一个元素和后一个元素。

  3. list与forward_list非常相似:最主要的不同在于forward_list是单链表,只能朝前迭代,已让其更简单高效。

  4. 与其他的序列式容器相比(array,vector,deque),list通常在任意位置进行插入、移除元素的执行效率更好。

  5. 与其他序列式容器相比,list和forward_list最大的缺陷是不支持任意位置的随机访问 比如:要访问list的第6个元素,必须从已知的位置(比如头部或者尾部)迭代到该位置,在这段位置上迭代需要线性的时间开销;list还需要一些额外的空间,以保存每个节点的相关联信息(对于存储类型较小元素的大list来说这可能是一个重要的因素)

2.list的基本使用

2.1 插入结点元素:insert

	list<int> lt;
	lt.push_back(1);
	lt.push_back(2);
	lt.push_back(3);
	lt.push_back(4);
	lt.push_back(5);
	lt.push_back(6);

	for (auto e : lt)
	{
		cout << e << " ";
	}
	cout << endl;
	
	list<int>::iterator it = lt.begin();
	for (size_t i = 0; i < 5; i++)
	{
		it++;
	}
	//在第五个位置的前面插入10
	//第五个位置——是下标为5,也就是第六个元素。
	lt.insert(it,10);


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

说明:因为list不支持随机访问,因此没有+,+=,[] 运算符重载,但支持 ++,–.

这里的迭代器,在插入之后,并没有失效,因为结点的插入是单个申请,单个释放的。不存在 扩容的现象。

2.2 删除结点元素:erase

void test_list()
{
	list<int> lt;
	lt.push_back(2);
	lt.push_back(2);
	lt.push_back(3);
	lt.push_back(4);
	lt.push_back(90);
	lt.push_back(6);
	lt.push_back(7);


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

	//删除所有的偶数结点
	list<int>::iterator it = lt.begin();
	while (it != lt.end())
	{
		if (*it % 2 == 0)
		{
			it = lt.erase(it);
		}
		else
		{
			it++;
		}
	}

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

}

erase在释放之后,迭代器是肯定失效的,因为其所指向的空间都失效了。因此库里采用返回值进行更新迭代器

2.3 链表元素排序:sort

<algorithm>sort只接受随机迭代器,但list的迭代器类型为双向迭代器,因此<algorithm>库中sort(快排)不能使用, 只能用自带的sort(归并排序)

注:list的排序很慢,但需要将大量数据排序(大概大于10万)时,宁愿先拷贝到vector排完再拷回来.

2.4 合并两个有序链表:merge

前提必须有序

void test_list()
{
	list<int> lt;
	lt.push_back(2);
	lt.push_back(2);
	lt.push_back(3);
	lt.push_back(4);
	lt.push_back(5);
	lt.push_back(6);
	lt.push_back(7);


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

	list<int> lt1;
	lt1.push_back(1);
	lt1.push_back(3);
	lt1.push_back(5);
	lt1.push_back(7);
	lt1.push_back(9);

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

	//将lt1合并到lt上
	lt.merge(lt1);
	for (auto e : lt)
	{
		cout << e << " ";
	}
	cout << endl;

}

2.5 对链表排序并去重:unique

unique去重的前提是有序

void test_list()
{
	list<int> lt;
	lt.push_back(2);
	lt.push_back(1);
	lt.push_back(3);
	lt.push_back(4);
	lt.push_back(2);
	lt.push_back(6);
	lt.push_back(4);
	
	lt.sort();
	for (auto e : lt)
	{
		cout << e << " ";
	}
	cout << endl;

	lt.unique();

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

2.6 删除指定元素:remove

相当于 find+erase

remove 会遍历整个list删除所有指定元素,当list中无指定元素时它会什么也不做

2.7 将链表的某部分转移到另一链表:splic

接口:

void splice (iterator position, list& x);
//将x链表转移到另一条链表的pos位置之前
void splice (iterator position, list& x, iterator i);
//将x链表的某个位置的结点移到另一条链表的pos之前
void splice (iterator position, list& x, iterator first, iterator last);
//将x链表的[first,last)的区间移到另一条链表的pos位置之前。

都是转移到指定位置之前
注意:迭代器/迭代器区间不能重合!

void test_list()
{
list<int> lt;
	lt.push_back(2);
	lt.push_back(2);
	lt.push_back(3);
	lt.push_back(4);
	lt.push_back(5);
	lt.push_back(6);
	lt.push_back(7);


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

	list<int> lt1;
	lt1.push_back(1);
	lt1.push_back(3);
	lt1.push_back(5);
	lt1.push_back(7);
	lt1.push_back(9);

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

	//将lt1转移到到lt的前面
	lt.splice(lt.begin(),lt1);
	for (auto e : lt)
	{
		cout << e << " ";
	}
	cout << endl;

	//将lt的后半部分转移到lt1上
	list<int>::iterator it = lt.begin();
	for (size_t i = 0; i < 5; i++)
	{
		it++;
	}
	lt1.splice(lt1.begin(), lt ,it, lt.end());

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

	//将lt1的第一个结点移到lt的最前面
	lt.splice(lt.begin(), lt1, lt1.begin());

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

3.list的模拟实现

#pragma once
#include<assert.h>
#include<iostream>
using namespace std;

namespace ymz
{
	template<class T>
	struct list_node
	{
		list_node<T>* _next;
		list_node<T>* _prev;
		T _val;

		list_node(const T& val = T())
			:_next(nullptr)
			, _prev(nullptr)
			, _val(val)
		{ }
	};

	template<class T,class Ref,class Ptr>
	struct _list_iterator
	{
		typedef list_node<T> Node;
		typedef _list_iterator<T, Ref, Ptr> self;
		Node* _node;

		_list_iterator(Node* node)
			:_node(node)
		{ }

		Ref operator*()
		{
			return _node->_val;
		}

		Ptr operator->()
		{
			return &_node->_val;
		}
		//在实际使用过程中,如:it->_a1(_a1是结构体A的成员,it是迭代器)
		//语法是不正确的,应为it->->_a1,第1个返回T*(即A*),第2个取_a1
		//但运算符重载要求可读性,编译器进行特殊处理自动省略一个 ->

		self& operator++()
		{
			_node = _node->_next;
			return *this;
		}
		self& operator++(int)
		{
			_list_iterator<T> tmp(*this);
			_node = _node->_next;
			return tmp;
		}
		self& operator--()
		{
			_node = _node->_prev;
			return *this;
		}
		self& operator--(int)
		{
			_list_iterator<T> tmp(*this);
			_node = _node->_prev;
			return tmp;
		}

		//加const,如:it.end()的返回值是临时拷贝具有常性
		bool operator!=(const self& it) const
		{
			return _node != it._node;
		}

		bool operator==(const self& it) const
		{
			return _node == it._node;
		}
	};

	template<class T>
	class list
	{
		typedef list_node<T> Node;

	public:
		//typedef _list_iterator<T> iterator;
		//typedef const _list_iterator<T> const_iterator;
		//vector能用是因为它的iterator就是指针,iterator移动不会解引用(内容不改变,仅指向改变)
		//list不能用是因为它的iterator是结构体,iterator移动 本质是结构体内部成员的改变

		typedef _list_iterator<T,T&,T*> iterator;
		typedef _list_iterator<T,const T&,const T*> const_iterator;

		iterator begin()
		{
			//return iterator(_head->_next);
			//单参数的构造函数(或转换运算符)默认支持隐式类型转换
			return _head->_next;
		}
		iterator end()
		{
			return _head;
		}

		void empty_init()
		{
			_head = new Node;
			_head->_prev = _head;
			_head->_next = _head;
			_size = 0;
		}

		list()
		{
			empty_init();
		}
		list(const list<T>& lt)
		{
			empty_init();

			for (auto& e : lt)
			{
				push_back(e);
			}
		}
		void swap(list<T>& lt)
		{
			std::swap(_head, lt._head);
			std::swap(_size, lt._size);
		}
		//list& operator=(list& lt) 也可以
		list<T>& operator=(list<T>& lt)
		{
			swap(lt);
			return *this;
		}

		~list()
		{
			clear();

			delete _head;
			_head = nullptr;
		}

		void clear()
		{
			iterator it = begin();
			while (it != end())
			{
				it = erase(it);
			}
		}

		void push_back(const T& x)
		{
			insert(end(), x);
		}
		void push_front(const T& x)
		{
			insert(begin(), x);
		}
		void pop_back()
		{
			erase(--end());
		}
		void pop_front()
		{
			erase(begin());
		}

		size_t size()
		{
			/*size_t sz = 0;
			iterator it = begin();
			while (it != end()
			{
				++sz;
				++it;
			}
			return sz;*/
			return _size;
		}

		iterator insert(iterator pos, const T& x)
		{
			Node* cur = pos._node;
			Node* prev = cur->_prev;
			Node* newnode = new Node(x);

			prev->_next = newnode;
			newnode->_next = cur;

			cur->_prev = newnode;
			newnode->_prev = prev;
			++_size;
			return newnode;
		}

		iterator erase(iterator pos)
		{
			assert(pos != end());

			Node* cur = pos._node;
			Node* prev = cur->_prev;
			Node* next = cur->_next;
			prev->_next = next;
			next->_prev = prev;
			delete cur;
			--_size;
			return next;
		}
	private:
		Node* _head;
		size_t _size;
	};
}

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

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

相关文章

在word中使用zotero添加参考文献并附带超链接

一、引言 在写大论文时&#xff0c;为了避免文中引用与文末参考文献频繁对照、修改文中引用顺序/引用文献时手动维护参考文献耗易出错&#xff0c;拟在 word 中使用 zotero 插入参考文献&#xff0c;并为每个参考文献附加超链接&#xff0c;实现交互式阅读。 版本&#xff1a…

性能测试、负载测试、压力测试的全面解析

在软件测试领域&#xff0c;性能测试、负载测试和压力测试是评估系统稳定性和可靠性的关键手段。​它们各自关注不同的测试目标和应用场景&#xff0c;理解这些差异对于制定有效的测试策略至关重要。 本文对性能测试、负载测试和压力测试进行深入分析&#xff0c;探讨其定义、…

Redis中的数据类型与适用场景

目录 前言1. 字符串 (String)1.1 特点1.2 适用场景 2. 哈希 (Hash)2.1 特点2.2 适用场景 3. 列表 (List)3.1 特点3.2 适用场景 4. 集合 (Set)4.1 特点4.2 适用场景 5. 有序集合 (Sorted Set)5.1 特点5.2 适用场景 6. Redis 数据类型的选型建议结语 前言 Redis 作为一款高性能的…

gz sim机器人SDF模型 [持续更新]

机器人SDF模型 linklink的一级pose材质 plugin话题信息通信键盘操作plugin Sensor传感器imu 不算教学&#xff0c;个人的记录 sdf的格式跟urdf有所不同&#xff0c;必须是完整的一个包括&#xff0c;比如< pose></ pose>这样前一个后一个&#xff0c;urdf中是有<…

【MySQL | 六、索引特性(进一步理解)】

目录 索引的理解索引的作用MySQL与磁盘的IOPage单个Page的分类多个Page的组织B树的特点 B树和B树的区别聚簇索引 VS 非聚簇索引聚簇索引的优缺点非聚簇索引的优缺点 创建索引常见索引分为&#xff1a;主键索引InnoDB主键索引的生成过程&#xff08;1&#xff09;初始化&#xf…

计算机网络高频(三)UDP基础

计算机网络高频(三)UDP基础 1.UDP的头部格式是什么样的?⭐ UDP 头部具有以下字段: 源端口(Source Port):16 位字段,表示发送方的端口号。目标端口(Destination Port):16 位字段,表示接收方的端口号。长度(Length):16 位字段,表示 UDP 数据报(包括头部和数据部…

【测试开发】OKR 小程序端黑盒测试报告

【测试报告】OKR 小程序端 项目名称版本号测试负责人测试完成日期联系方式OKR 小程序端4.0马铭胜2025-03-2515362558972 1、项目背景 1.1 OKR 用户端 在如今这个快节奏的时代中&#xff0c;个人和组织的成长往往依赖于清晰、明确且意义深远的目标。然而&#xff0c;如何设定…

部署高可用PostgreSQL14集群

目录 基础依赖包安装 consul配置 patroni配置 vip-manager配置 pgbouncer配置 haproxy配置 验证 本文将介绍如何使用Patroni、Consul、vip-manager、Pgbouncer、HaProxy组件来部署一个3节点的高可用、高吞吐、负载均衡的PostgresSQL集群&#xff08;14版本&#xff09;&…

Vue3中keep-alive缓存组件应用场景。

文章目录 一、KeepAlive是什么&#xff1f;二、基本使用1.例子2.keep-alive使用 三、其他属性3.1 包含/排除3.2 最大缓存实例数3.3 缓存实例的生命周期 总结 一、KeepAlive是什么&#xff1f; 是一个内置组件&#xff0c;它的功能是在多个组件间动态切换时缓存被移除的组件实例…

CosyVoice2在Windows系统上本地部署的详细步骤

CosyVoice2在Windows系统上本地部署的详细步骤&#xff1a; 下载源码并初始化&#xff1a; 确保你的设备上安装了Git。打开命令提示符&#xff08;cmd&#xff09;&#xff0c;执行以下命令来克隆仓库&#xff1a;git clone --recursive https://github.com/FunAudioLLM/CosyVo…

鸿蒙入门——ArkUI 跨页面数据同步和应用全局单例的UI状态存储AppStorage 小结(三)

文章大纲 引言一、AppStorage 应用全局的UI状态存储1、StorageProp和StorageLink装饰器建立联系2、StorageProp2.1、StorageProp使用规则2.2、StorageProp变量的传递/访问规则2.3、StorageProp支持的观察变化2.4、StorageProp 值初始化和更新 3、StorageLink3.1、StorageLink使…

海思烧录工具HITool电视盒子刷机详解

HiTool是华为开发的一款用于海思芯片设备的刷机和调试工具&#xff0c;可对搭载海思芯片的机顶盒、智能电视等设备进行固件烧录、参数配置等操作。以下为你详细介绍&#xff1a; 功能用途 固件烧录&#xff1a;这是HiTool最主要的功能之一。它能够将下载好的适配固件文件烧录到…

使用VS2022编译CEF

前提 选择编译的版本 CEF自动编译&#xff0c;在这里可以看到最新的稳定版和Beta版。 从这里得出&#xff0c;最新的稳定版是134.0.6998.118&#xff0c;对应的cef branch是6998。通过这个信息可以在Build requirements查到相关的软件配置信息。 这里主要看Windows下的编译要…

Pytorch学习笔记(八)Learn the Basics - Save and Load the Model

这篇博客瞄准的是 pytorch 官方教程中 Learn the Basics 章节的 Save and Load the Model 部分。 官网链接&#xff1a;https://pytorch.org/tutorials/beginner/basics/saveloadrun_tutorial.html 完整网盘链接: https://pan.baidu.com/s/1L9PVZ-KRDGVER-AJnXOvlQ?pwdaa2m …

MATLAB 绘制空间分布图 方法总结

方法一&#xff1a;用mapshow函数 figure(1); hold on %% 添加陆地 land shaperead(landareas); mapshow(landareas.shp, FaceColor, [1 1 1], EdgeColor, [0.3 0.3 0.3],FaceAlpha,0)%% 添加站点 for i 1:size(mycmap,1)mapshow(lon(label i),lat(label i),displaytype,po…

Docker+Ollama+Xinference+RAGFlow+Dify+Open webui部署及踩坑问题

目录 一、Xinference部署 &#xff08;一&#xff09;简介 &#xff08;二&#xff09;部署 &#xff08;三&#xff09;参数 &#xff08;四&#xff09;错误问题 &#xff08;五&#xff09;Xinference配置Text-embedding模型 &#xff08;六&#xff09;Xinference配…

Axure项目实战:智慧城市APP(四)医疗信息(动态面板、选中交互应用)

亲爱的小伙伴&#xff0c;在您浏览之前&#xff0c;烦请关注一下&#xff0c;在此深表感谢&#xff01; 课程主题&#xff1a;智慧城市APP医疗信息模块 主要内容&#xff1a;医疗信息模块原型设计与交互 应用场景&#xff1a;医疗信息行业 案例展示&#xff1a; 案例视频&…

【网络通信安全】基于华为 eNSP 的链路聚合、手工负载分担模式与 LACP 扩展配置 全解析

目录 一、引言 二、链路聚合技术基础 2.1 链路聚合的定义与作用 2.2 链路聚合的工作原理 2.3 链路聚合的模式分类 三、华为 eNSP 简介 3.1 eNSP 的概述 3.2 eNSP 的安装与配置 3.2.1 安装环境要求 3.2.2 安装步骤 3.2.3 配置虚拟网卡 四、手工负载分担模式配置 4.…

Transformer 通关秘籍2:利用 BERT 将文本 token 化

前面两节分别通过两个代码示例展示了模型将文本转换为 token 之后是什么样的&#xff0c;希望你可以对此有一个感性的认识。 本节来简要介绍一下将一个连续的文本转换为 token 序列的大致过程&#xff0c;这个过程被称为分词&#xff0c;也叫 tokenization。 在你没了解这方面…

网络运维学习笔记(DeepSeek优化版) 024 HCIP-Datacom OSPF域内路由计算

文章目录 OSPF域内路由计算&#xff1a;单区域的路由计算一、OSPF单区域路由计算原理二、1类LSA详解2.1 1类LSA的作用与结构2.2 1类LSA的四种链路类型 三、OSPF路由表生成验证3.1 查看LSDB3.2 查看OSPF路由表3.3 查看全局路由表 四、2类LSA详解4.1 2类LSA的作用与生成条件4.2 2…