STL容器--list

1. list的介绍及使用
1.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来说这可能是一个重要的因素)

1.2 list的使用

list中的接口比较多,此处类似,只需要掌握如何正确的使用,然后再去深入研究背后的原理,已达到可扩展的能力。以下为list中一些常见的重要接口:

1.2.1 list的构造
 

1.2.2 list iterator的使用

list迭代器可以理解成一个指针,该指针指向list中的某个节点。实际它是指针的封装。

void testlist1()
	{
		list<int> lt;
		lt.push_back(1);
		lt.push_back(2);
		lt.push_back(3);
		lt.push_back(4);
		lt.push_back(5);

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

		cout << endl;

	}


1.2.3 list capacity

1.2.4 list element access

int main()
{

	//list<int> lt(3);
	vector<int> v{ 4,5 };

    vector<string> tokens{ "4","13","5","/","+" };
    cout<<evalRPN(tokens)<<endl;

    list<int> lt;
    lt.push_back(1);
    lt.push_back(2);
    lt.push_back(3);
    lt.push_back(4);
    lt.push_back(5);
    //这里可以直接修改里面第一个元素的值
    lt.front() = 10;  
    for (auto e : lt)
    {
        cout << e << " ";
    }
    cout << endl;
    
	return 0;
}

1.2.5 list modifiers

以下代码对部分接口进行测试:

	void testlist3()
	{
		list<int> lt;
		lt.push_front(1);
		lt.push_front(2);
		lt.push_front(3);
		lt.push_front(4);
		lt.push_front(5);
		for (auto e : lt)
		{
			cout << e << " ";
		}
		cout << endl;
		list<int> lt1;
		lt1.push_front(10);
		lt1.push_front(20);
		lt1.push_front(30);
		lt1.push_front(40);
		lt.swap(lt1);
		for (auto e : lt)
		{
			cout << e << " ";
		}
		cout << endl<<"头删后:"<<endl;

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

1.2.6 list的迭代器失效

迭代器失效即迭代器所指向的节点的无效,即该节点被删除了。因为list的底层结构为带头结点的双向循环链表,因此在list中进行插入时是不会导致list的迭代器失效的,只有在删除时才会失效,并且失效的只是指向被删除节点的迭代器,其他迭代器不会受到影响。

删除list容器的所有值 正确写法:

void TestListIterator()
{
    int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
    list<int> l(array, array + sizeof(array) / sizeof(array[0]));
    for (auto e : l)
    {
        cout << e <<" ";
    }
    auto it = l.begin();
    while (it != l.end())
    {
        //此时it已经指向原来it的下一个迭代器位置
        l.erase(it++); // it = l.erase(it);

        //下面两行为错误写法

        //l.erase(it);
        //++it;
    }
    for (auto e : l)
    {
        cout << e <<endl;
    }
}

2. list的模拟实现

2.1 模拟实现list

要模拟实现list,必须要熟悉list的底层结构以及其接口的含义,通过上面的学习,这些内容已基本掌握,现在我们来模拟实现list。

namespace xwy {
	template<typename T>
	struct listNode
	{
		T _data;
		listNode<T>* _pre;
		listNode<T>* _next;
		//单参数构造函数
		listNode(const T& val = T())
			:_data(val),
			_pre(nullptr),
			_next(nullptr)
		{

		}

		
	};
	template<typename T, class Ref, class Ptr>
	struct _list_iterator
	{
		//  受类域的限制
		typedef listNode<T> Node;
		typedef _list_iterator<T,Ref,Ptr> self;
		Node* _node;
		_list_iterator(Node *node=nullptr):
			_node(node)
		{

		}
		//操作符重载
		Ref operator*()
		{
			return _node->_data;
		}
		Ptr operator->()
		{
			return &(_node->_data);
		}

		self& operator--()
		{
			_node = _node->_pre;
			return *this;
		}
		self operator-(int a)
		{
			Node* ptr = _node;

			while (a--&&ptr)
			{
				ptr = ptr->_pre;
			}
			return ptr;
		}

		self& operator++()
		{
			_node = _node->_next;
			return *this;
		}
		self operator++(int)
		{
			//  self tmp(*this)  拷贝构造自己
			Node* tmp = _node;
			_node = _node->_next;
			return tmp;
			
		}

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

	};
	// 适配器 -- 复用
	template<class Iterator, class Ref, class Ptr>
	struct Reverse_iterator
	{
		Iterator _it;
		typedef  Reverse_iterator<Iterator, Ref, Ptr> self;
		Reverse_iterator(const Iterator &it):
			_it(it)
		{

		}
		//操作符重载
		Ref operator*()
		{
			return *_it;
		}
		self& operator--()
		{
			++_it;
			return *this;
		}

		Ptr operator->()
		{
			return &(*_it);
		}

		self& operator++()
		{
			--_it;
			return *this;
		}
		self operator++(int)
		{
			//  self tmp(*this)  拷贝构造自己
			Iterator it = _it;
			--_it;
			return it;

		}

		bool operator!=(const self& lt) const   //const和const比较 ,非const和const比较
		{
			return lt._it != _it;   //不支持那两种类型的比较,是因为不存在那两种类型比较的重载
		}


	};

	template<typename T>
	class list
	{
	public:
		typedef listNode<T> Node;
		typedef _list_iterator<T,T&,T*> iterator;   
		typedef _list_iterator<T, const T&, const T*> const_iterator;
		typedef Reverse_iterator<iterator,T&,T*> reverse_iterator;
		typedef Reverse_iterator<const_iterator, const T&, const T*> const_reverse_iterator;
		//无参构造函数
		list()
		{
			empty_init();
			
		}
		template<class iterator>
		list(iterator first,iterator last)
		{
			empty_init();
			while (first != last)
			{
				push_back(*first);
				first++;
			}
		}
		//拷贝构造
		list(const list& lt)
		{
			empty_init();
			auto it = lt.begin();
			while (it != lt.end())
			{
				push_back(*it);
				it++;
			}

		}

		//迭代器的实现
		iterator begin() 
		{
			return _head->_next;
		}

		iterator end() 
		{
			return _head;
		}
		const_iterator begin() const
		{
			return _head->_next;
		}

		const_iterator end() const
		{
			return _head;
		}


		//反向迭代器
		reverse_iterator rbegin()
		{
			return --end();
		}
		reverse_iterator rend()
		{
			return --begin();
		}

		const_reverse_iterator rbegin() const
		{
			return --end();
		}
		const_reverse_iterator rend() const
		{
			return --begin();
		}

		

		void push_back(const T& val)
		{
			Node* newnode = new Node(val);
			newnode->_next = _head;
			_head->_pre->_next = newnode;
			newnode->_pre = _head->_pre;
			_head->_pre = newnode;
		}


		iterator erase(iterator pos) //在pos位置删除
		{
			Node* cur = pos._node;
			Node* prev = cur->_pre;
			Node* next = cur->_next;
			delete cur;
			prev->_next = next;
			next->_pre = prev;
		
			return next;
		}
		// 在pos位置前插入值为val的节点
		iterator insert(iterator pos, const T& val)
		{
			Node* cur = pos._node;
			Node* newNode = new Node(val);
			newNode->_next = cur;
			newNode->_pre = cur->_pre;
			cur->_pre->_next = newNode;
			cur->_pre = newNode;
			return pos;
		}
		/*void push_back(const T& val)
		{
			insert(_head, val);
		}*/
		void push_front(const T& val)
		{
			insert(_head->_next, val);
		}


		void swap(list<T>& l)
		{
			std::swap(l._head, _head);
		}
	
		void clear()
		{
			//清理数据,不清头节点
			iterator it = begin();
			while (it != end())
			{
				it = erase(it);//it就是下一个位置
			}
		}

		~list()
		{
			clear();
			delete _head;		// 只有节点是new出来,需要delete,但这个只delete 了一个节点
		}

	private:
		void empty_init()
		{
			_head = new Node();
			_head->_next = _head->_pre = _head;
		}
		Node* _head;  
	};

2.2 list的反向迭代器

反向迭代器的++就是正向迭代器的--,反向迭代器的--就是正向迭代器的++,因此反向迭代器的实现可以借助正向迭代器,即:反向迭代器内部可以包含一个正向迭代器,对正向迭代器的接口进行包装即可.

template<class Iterator>
class ReverseListIterator
{
    // 注意:此处typename的作用是明确告诉编译器,Ref是Iterator类中的类型,而不是静态成员变量
    // 否则编译器编译时就不知道Ref是Iterator中的类型还是静态成员变量
    // 因为静态成员变量也是按照 类名::静态成员变量名 的方式访问的
public:
    typedef typename Iterator::Ref Ref;
    typedef typename Iterator::Ptr Ptr;
    typedef ReverseListIterator<Iterator> Self;
public:
//
    // 构造
    ReverseListIterator(Iterator it): _it(it){}
    //
    // 具有指针类似行为
    Ref operator*(){
    Iterator temp(_it);
    --temp;
    return *temp;
}
Ptr operator->(){ return &(operator*());}
//
// 迭代器支持移动
Self& operator++(){
--_it;
return *this;
}
Self operator++(int){
Self temp(*this);
--_it;
return temp;
}
Self& operator--(){
++_it;
return *this;
}
Self operator--(int)
{
Self temp(*this);
++_it;
return temp;
}
//
// 迭代器支持比较
bool operator!=(const Self& l)const{ return _it != l._it;}
bool operator==(const Self& l)const{ return _it != l._it;}
Iterator _it;
};

3. list与vector的对比

vector与list都是STL中非常重要的序列式容器,由于两个容器的底层结构不同,导致其特性以及应用场景不同,其主要不同如下:

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

2.3 OpenCV随手简记(四)

阈值处理是很多高级算法底层处理的预方法之一。 自己求图像平均阈值&#xff1a; # -*- codingGBK -*- import cv2 as cv import numpy as np #求出图像均值作为阈值来二值化 def custom_image(image): gray cv.cvtColor(image, cv.COLOR_BGR2GRAY) cv.imshow("原来&qu…

微服务网关Gateway(下)

CSDN 的小伙伴们&#xff0c;大家好呀&#xff0c;我是苍何。 这篇文章我们继续来说下我们项目中用到的微服务网关 Gateway 的技术点。主要涵盖过滤器&#xff0c;限流处理以及黑白名单配置。 过滤器 网关中的过滤器&#xff0c;有点类似 SpringMVC 里面的拦截器 Intercepto…

面试官:什么是Redis持久化—>AOF持久化

&#x1f604;作者简介&#xff1a; 小曾同学.com,一个致力于测试开发的博主⛽️&#xff0c;主要职责&#xff1a;测试开发、CI/CD 如果文章知识点有错误的地方&#xff0c;还请大家指正&#xff0c;让我们一起学习&#xff0c;一起进步。 &#x1f60a; 座右铭&#xff1a;不…

Python | Leetcode Python题解之第130题被围绕的区域

题目&#xff1a; 题解&#xff1a; class Solution:def solve(self, board: List[List[str]]) -> None:if not board:returnn, m len(board), len(board[0])que collections.deque()for i in range(n):if board[i][0] "O":que.append((i, 0))board[i][0] &q…

C语言 | Leetcode C语言题解之第129题求根节点到叶节点数字之和

题目&#xff1a; 题解&#xff1a; int sumNumbers(struct TreeNode* root) {if (root NULL) {return 0;}int sum 0;struct TreeNode* nodeQueue[2000];int numQueue[2000];int leftQueue 0, rightQueue 0;nodeQueue[rightQueue] root;numQueue[rightQueue] root->v…

MPEG-TS 封装格式详解

MPEG-TS 封装格式详解 MPEG-TS 封装格式详解简介基本概念TS 文件格式PSI&#xff08;Program Specific Information&#xff09;节目关联表&#xff08;PAT&#xff0c;Program Association Table&#xff09;节目映射表&#xff08;PMT&#xff0c;Program Map Table&#xff…

探索k8s集群的配置资源(secret和configmap)

目录 ConfigMap ConfigMap&#xff08;主要是将配置目录或者文件挂载到k8s里面使用&#xff09; 与Secret类似&#xff0c;区别在于ConfigMap保存的是不需要加密配置的信息。&#xff08;例如&#xff1a;配置文件&#xff09; ConfigMap 功能在 Kubernetes1.2 版本中引入&…

算法 java 排序和查找

排序和查找 冒泡排序&#xff08;稳定&#xff09;选择排序&#xff08;不稳定&#xff09;插入排序&#xff08;稳定&#xff09;希尔排序&#xff08;不稳定&#xff09;归并排序&#xff08;稳定&#xff09;快速排序&#xff08;不稳定&#xff09;堆排序计数排序桶排序基数…

Scikit-Learn随机森林分类

Scikit-Learn随机森林分类 1、随机森林分类1.1、随机森林分类概述1.2、随机森林分类的优缺点2、Scikit-Learn随机森林分类2.1、Scikit-Learn随机森林分类API2.2、Scikit-Learn随机森林分类初体验(葡萄酒分类)2.3、Scikit-Learn随机森林分类实践(鸢尾花分类)2.4、参数调优与…

undefined symbol: _ZN3c104impl8GPUTrace13gpu mmcv

这里写自定义目录标题 ImportError: //python3.8/site-packages/mmcv/_ext.cpython-38-x86_64-linux-gnu.so: undefined symbol: _ZN3c104impl8GPUTrace13gpuTraceStateEERROR conda.cli.main_run:execute(49): 这样的问题往往都是版本不匹配导致的 pytorch的版本&#xff0c;m…

为Android组件化项目搭建Maven私服

概览 文章目录 概览前言搭建 maven 私服服务器环境jdk安装配置nexus安装配置管理创建存储点、仓库 项目中使用 maven 私服上传 module 到仓库自动发布 module手动上传单个aar包 引用仓库中的 modulebuild.gradle引入远程module FAQ开发阶段有些module用远程依赖&#xff0c;有些…

构建大型语言模型(LLM)产品的实战指南

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

#13前端后花园周刊-10个现代 Node.js 运行时新特性、Nextjs15、Astro4.9、CSS压缩

⚡️行业动态 JavaScript 的创建者 Brendan Eich 在 Twitter/X 上出现&#xff0c;反驳了 JS 是“最邋遢的”的说法&#xff0c;称其只有 50% 。 &#x1f4c6;发布 Next.js 15 RC 流行的 React 元框架已经准备好迎接一个主要的新版本&#xff0c;它有一个 RC&#xff0c;让…

YOLOv9改进策略 | 添加注意力篇 | 利用YOLOv10提出的PSA注意力机制助力YOLOv9有效涨点(附代码 + 详细修改教程)

一、本文介绍 本文给大家带来的改进机制是YOLOv10提出的PSA注意力机制&#xff0c;自注意力在各种视觉任务中得到了广泛应用&#xff0c;因为它具有显著的全局建模能力。然而&#xff0c;自注意力机制表现出较高的计算复杂度和内存占用。为了解决这个问题&#xff0c;鉴于注意…

群体优化算法---蝙蝠优化算法分类Iris数据集

介绍 蝙蝠算法&#xff08;Bat Algorithm, BA&#xff09;是一种基于蝙蝠回声定位行为的优化算法。要将蝙蝠算法应用于分类问题&#xff0c;可以通过将蝙蝠算法用于优化分类器的参数&#xff0c;图像分割等 本文示例 我们使用一个经典的分类数据集&#xff0c;如Iris数据集&…

基于深度学习的CT影像肺癌检测识别

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长 QQ 名片 :) 1. 项目简介 肺癌是全球范围内导致癌症死亡的主要原因之一&#xff0c;早期检测和诊断对于提高患者生存率至关重要。随着深度学习技术的迅猛发展&#xff0c;基于CT影像的肺癌检测识别成为了研究热点。本文介绍…

Spire.PDF for .NET【文档操作】演示:在 C# 中向 PDF 文件添加图层

Spire.PDF 完美支持将多页 PDF 拆分为单页。但是&#xff0c;更常见的情况是&#xff0c;您可能希望提取选定的页面范围并保存为新的 PDF 文档。在本文中&#xff0c;您将学习如何通过 Spire.PDF 在 C#、VB.NET 中根据页面范围拆分 PDF 文件。 Spire.PDF for .NET 是一款独立 …

wireshark 二次开发

一、 Windows 准备 1、源代码下载 Git&#xff1a;https://github.com/wireshark/wireshark 2、 准备Visual C 要编译wireshark&#xff0c;开发电脑上应该安装了Visual Studio并包括了Visual C&#xff0c;请至少安装Visual Studio 2010以减少不必要的麻烦。 visual studio …

英码科技推出鸿蒙边缘计算盒子:提升国产化水平,增强AI应用效能,保障数据安全

当前&#xff0c;随着国产化替代趋势的加强&#xff0c;鸿蒙系统Harmony OS也日趋成熟和完善&#xff0c;各行各业都在积极拥抱鸿蒙&#xff1b;那么&#xff0c;边缘计算要加快实现全面国产化&#xff0c;基于鸿蒙系统开发AI应用势在必行。 关于鸿蒙系统及其优势 鸿蒙系统是华…

友顺科技(UTC)分立器件与集成IC产品选型和应用

友顺科技股份有限公司成立于1990年&#xff0c;是全球领先的集成电路与功率半导体厂商 ,集团总部位于台北&#xff0c;生产基地位于福州、厦门。 友顺科技具有完整模拟组件产品线&#xff0c;其中类比IC涵盖各种稳压器、PWM控制IC, 放大器、比较器、逻辑IC、Voltage Translato…