10,STL——list类

一,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类的使用

#include <iostream>
#include <list>
using namespace std;
	
void test_list1()
{	
	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();
	while (it != lt.end())
	{
		cout << *it << " ";
		++it;
	}
	cout << endl;


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

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


	auto pos = find(lt.begin(), lt.end(), 3);
	if (pos != lt.end())
	{
		//判断pos是否失效?不会
		lt.insert(pos, 30);
		lt.insert(pos, 30);
		lt.insert(pos, 30);
		lt.insert(pos, 30);

		*pos *= 100;
	}
	for (auto e : lt)
	{
		cout << e << " ";
	}
	cout << endl;


	auto post = find(lt.begin(), lt.end(), 4);
	if (post != lt.end())
	{
		lt.erase(pos);
	}
	for (auto e : lt)
	{
		cout << e << " ";
	}
	cout << endl;
}

void test_list3()
{
	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();
	while (it != lt.end())
	{
		cout << *it << " ";
		++it;
	}
	cout << endl;

	lt.remove(3);

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

int main()
{	
	//test_list1();
	//test_list2();
	test_list3();
	
	return 0;
}

二,list类的模拟实现

List 的迭代器有两种实现方式,具体应根据容器底层数据结构实现:

1. 原生态指针,比如:vector

2 将原生态指针进行封装,因迭代器使用形式与指针完全相同,因此在自定义的类中必须实现以下方法:

1). 指针可以解引用,迭代器的类中必须重载operator*()

2). 指针可以通过->访问其所指空间成员,迭代器类中必须重载oprator->()

3). 指针可以++向后移动,迭代器类中必须重载operator++()与operator++(int),至于operator--,()/operator--(int)释放需要重载,根据具体的结构来抉择,双向链表可以向前移动,所以需要重载,如果是forward_list就不需要重载--

4). 迭代器需要进行是否相等的比较,因此还需要重载operator==()与operator!=()

#pragma once
#include <iostream>
#include <list>
#include <assert.h>

namespace csy
{
	//节点类
	template<class T>
	struct list_node
	{
		//节点构造
		//若构造结点时未传入数据
		//则默认以list容器所存储类型的默认构造函数
		//所构造出来的值为传入数据
		list_node(const T& x = T())
			:_data(x)
			, _next(nullptr)
			, _prev(nullptr)
		{}

		//节点成员变量
		T _data;
		list_node<T>* _next;
		list_node<T>* _prev;
	};

	//迭代器类
	template<class T, class Ref, class Ptr>
	struct list_iterator
	{
		//设计三个模板参数,那么就能很好的区分普通迭代器和const迭代器
		//迭代器类的模板参数列表当中的Ref和Ptr分别代表的是引用类型和指针类型
		typedef list_node<T> Node;
		typedef list_iterator<T, Ref, Ptr> iterator;

		// 成员变量就只有一个,那就是结点指针
		Node* _node;
		
		// 迭代器类实际上就是对结点指针进行了封装,
		list_iterator(Node* node)
			:_node(node)
		{}
		
		// 具有指针类似行为
		Ref operator*()
		{
			return _node->_data;
		}
		Ptr operator->()
		{
			return &(operator*());
		}

		// 迭代器支持比较
		bool operator!=(const iterator& it)const
		{
			return _node != it._node;
		}
		bool operator==(const iterator& it)const
		{
			return _node == it._node;
		}

		// 迭代器支持移动
		iterator& operator++()
		{
			_node = _node->_next;
			return *this;
		}
		iterator operator++(int)
		{
			iterator temp(*this);
			_node = _node->_next;
			return temp;
		}
		iterator& operator--()
		{
			_node = _node->_prev;
			return *this;
		}
		iterator operator--(int)
		{
			iterator temp(*this);
			_node = _node->_prev;
			return temp;
		}
	};

	// list底层是双向带头循环链表
	template<class T>
	class list
	{
	public:
		typedef list_node<T> Node;
		typedef list_iterator<T, T& , T*> iterator;
		typedef list_iterator<T,const T& ,const T*> const_iterator;

		// 默认成员函数
		list()
    {
			_head = new Node;
			_head->_next = _head;
			_head->_prev = _head;
		}
    		list(const list<T>& lt)
		{
			_head = new Node;
			_head->_next = _head;
			_head->_prev = _head;

			//将容器lt当中的数据一个个尾插到新构造的容器后面
			for (const auto& e : lt)
			{
				push_back(e); 
			}
		}
		list<T>& operator=(const list<T>& lt)
		{
			if (this != &lt) //避免自己给自己赋值
			{
				clear(); //清空容器
				for (const auto& e : lt)
				{
					//将容器lt当中的数据一个个尾插到链表后面
					push_back(e); 
				}
			}
			return *this; //支持连续赋值
		}
		template <class Iterator>
		list(Iterator first, Iterator last)
		{
			_head = new Node;
			_head->_prev = _head;
			_head->_next = _head;
			while (first != last)
			{
				push_back(*first);
				++first;
			}
		}
		~list()
		{
			clear(); //清理容器
			delete _head; //释放头结点
			_head = nullptr; //头指针置空
		}

		// 迭代器相关函数
		iterator begin()
		{
			return iterator(_head->_next);
		}
		iterator end()
		{
			return iterator(_head);
		}
		const_iterator begin() const
		{
			return const_iterator(_head->_next);
		}
		const_iterator end() const
		{
			return const_iterator(_head);
		}

		// 插入、删除函数
		void push_back(const T& x)
		{
			//Node* tail = _head->_prev;
			//Node* newnode = new Node(x);

			//tail->_next = newnode;
			//newnode->_next = _head;
			//newnode->_prev = tail;
			//_head->_prev = newnode;

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

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

			// prev new cur
			prev->_next = newnode;
			newnode->_next = cur;
			newnode->_prev = prev;
			cur->_prev = newnode;

			return iterator(newnode);
		}
		iterator erase(iterator pos)
		{
			Node* cur = pos._node; 
			Node* prev = cur->_prev; 
			Node* next = cur->_next; 

			delete cur; //释放cur结点

			//建立prev与next之间的双向关系
			prev->_next = next;
			next->_prev = prev;

			//返回pos的下一个位置
			return iterator(next); 
		}

    		//其他函数
		void clear()
		{
			iterator it = begin();
			while (it != end())
			{
				erase(it);
			}
		}

		size_t size()const
		{
			Node* cur = _head->_next;
			size_t count = 0;
			while (cur != _head)
			{
				count++;
				cur = cur->_next;
			}

			return count;
		}

	private:
		Node* _head;// 指向链表头结点的指针
	};
	
	template<class T>
	void PrintList(const csy::list<T>& lt)
	{
		auto it = lt.begin();
		while (it != lt.end())
		{
			cout << *it << " ";
			++it;
		}
		cout << endl;
	}

	void test_list()
	{
		// 测试List的构造
		list<int> lt;
		lt.push_back(1);
		lt.push_back(2);
		lt.push_back(3);
		lt.push_back(4);
		lt.push_back(5);
		PrintList(lt);

		list<int> l2(lt);
		PrintList(l2);

		list<int> l3 = l2;
		PrintList(l3);

		int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
		list<int> l4(array, array + sizeof(array) / sizeof(array[0]));
		PrintList(l4);

		// 测试PushBack与PopBack
		list<int> l;
		l.push_back(1);
		l.push_back(2);
		l.push_back(3);
		PrintList(l);

		l.pop_back();
		l.pop_back();
		PrintList(l);

		l.pop_back();
		cout << l.size() << endl;

		// 测试PushFront与PopFront
		l.push_front(1);
		l.push_front(2);
		l.push_front(3);
		PrintList(l);

		l.pop_front();
		l.pop_front();
		PrintList(l);

		l.pop_front();
		cout << l.size() << endl;

		// 测试insert和erase
		int arr[] = { 1, 2, 3, 4, 5 };
		list<int> ll(arr, arr + sizeof(arr) / sizeof(arr[0]));

		auto pos = ll.begin();
		ll.insert(ll.begin(), 0);
		PrintList(ll);

		++pos;
		ll.insert(pos, 2);
		PrintList(ll);

		ll.erase(ll.begin());
		ll.erase(pos);
		PrintList(ll);

		// pos指向的节点已经被删除,pos迭代器失效
		cout << *pos << endl;

		auto it = ll.begin();
		while (it != ll.end())
		{
			it = ll.erase(it);
		}
		cout << ll.size() << endl;
	}
}

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

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

相关文章

Guilite字库工具

目录 前言 使用方法 离线字库解析 工具链接 前言 最近通过Qt写了一个Guilite字库工具&#xff0c;相比原始工具&#xff0c;主要有以下几个优点&#xff1a; &#xff08;1&#xff09;支持同时生成多套字库 &#xff08;2&#xff09;支持离线字库生成 &#xff08;3&a…

【C++】深入解析pop_back()方法及其应用

博客主页&#xff1a; [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: C 文章目录 &#x1f4af;前言&#x1f4af;什么是 pop_back()&#xff1f;定义与功能使用场景 &#x1f4af;深入解析代码示例基础示例分析示例代码分析 空字符串上的 pop_back() 调用错误示例错误原因分析 &#x1…

Java Web开发基础:HTML的深度解析与应用

文章目录 前言&#x1f30d;一.B/S 软件开发架构简述&#x1f30d;二.HTML 介绍❄️2.1 官方文档❄️2.2 网页的组成❄️2.3 HTML 是什么❄️2.4html基本结构 &#x1f30d;三.HTML标签1.html 的标签/元素-说明2. html 标签注意事项和细节3.font 字体标签4.标题标签5.超链接标签…

第三十六章 Spring之假如让你来写MVC——拦截器篇

Spring源码阅读目录 第一部分——IOC篇 第一章 Spring之最熟悉的陌生人——IOC 第二章 Spring之假如让你来写IOC容器——加载资源篇 第三章 Spring之假如让你来写IOC容器——解析配置文件篇 第四章 Spring之假如让你来写IOC容器——XML配置文件篇 第五章 Spring之假如让你来写…

IDEA中创建maven项目

1. IDEA中创建maven项目 在IDEA中创建Maven项目&#xff0c;前提是已经安装配置好Maven环境。如还未配置安装Maven的&#xff0c;请先下载安装。如何下载安装&#xff0c;可参考我另外篇文章&#xff1a;maven的下载与安装教程本篇教程是以创建基于servlet的JavaWeb项目为例子&…

MACPA:fMRI连接性分析的新工具

摘要 不同脑区的共同激活为它们之间的功能交互或连接提供了一个有价值的衡量指标。元分析连接模型(MACM)是一种经过充分验证的研究某一特定区域共激活模式的方法&#xff0c;该方法对基于任务的功能磁共振成像(task-fMRI)数据进行种子点(seed-based)元分析。虽然MACM是一种强大…

React中createRoot函数原理解读——Element对象与Fiber对象、FiberRootNode与HostRootNode

【2024最新版】React18 核心源码分析教程&#xff08;全61集&#xff09; Element对象与Fiber对象 在 React 中&#xff0c;Element 对象 和 Fiber 对象 是核心概念&#xff0c;用于实现 React 的高效渲染和更新机制。以下是它们的详细解读&#xff1a; 1. Element 对象 定…

【C】初阶数据结构1 -- 时间复杂度与空间复杂度

目录 1 数据结构 2 算法 3 复杂度 1&#xff09; 时间复杂度 2&#xff09; 空间复杂度 4 提升算法能力的两点建议 1&#xff09; 画图 2&#xff09; 多实践&#xff0c;多上手写代码 重点一 数据结构的定义 1 数据结构 数据结构是计算机存储、组织数据的…

TypeScript Jest 单元测试 搭建

NPM TypeScript 项目搭建 创建目录 mkdir mockprojectcd mockproject初始化NPM项目 npm init -y安装TypeScript npm i -D typescript使用VSCode 打开项目 创建TS配置文件tsconfig.json {"compilerOptions": {"target": "es5","module&…

一.项目课题 <基于TCP的文件传输协议实现>

客户端代码 需要cJSON.c文件和cJSON.h文件 在这里插入代码片#include "myheadth.h" #include "myfun.h"#define TIME 10 int sockfd; void heartbeat(int signum) {cJSON* root cJSON_CreateObject();cJSON_AddStringToObject(root,"request"…

C#调用OpenCvSharp实现图像的膨胀和腐蚀

图像膨胀和腐蚀操作属于图像处理中常用的形态学操作&#xff0c;其原理都是采用特定小矩形&#xff08;核矩形&#xff09;&#xff0c;将其中心位置与图像中的每个像素对齐后&#xff0c;对重合位置的像素执行特定处理后&#xff0c;将处理结果保存到中心位置对应的像素处&…

新活动平台建设历程与架构演进

01 前言 历时近两年的重新设计和迭代重构&#xff0c;用户技术中心的新活动平台建设bilibili活动中台终于落地完成&#xff01;并迎来了里程碑时刻 —— 接过新老迭代的历史交接棒&#xff0c;从内到外、从开发到搭建实现全面升级&#xff0c;开启了活动生产工业化新时代&#…

一个好用的C++数据库操作库:OTL

目录 1.简介 2.OTL库的核心类 3.OTL使用 4.使用OTL时注意事项 4.1.多线程初始化 4.2.OTL支持连接池 4.3.大字段的读取方式 4.4.指定数据库类型 4.5.异常处理 5.下载地址 6.总结 1.简介 OTL&#xff08;Oracle, ODBC and DB2-CLI Template Library&#xff09;是一个…

高级生化大纲

一&#xff0c;蛋白质化学&#xff1a; 蛋白质分离是生物化学和分子生物学研究中的一项基本技术&#xff0c;用于根据蛋白质的物理和化学特性将其从混合物中分离出来。 1. 离心分离法 离心分离法利用离心力来分离不同质量或密度的颗粒和分子。 差速离心&#xff1a;通过逐…

linux网络 | http结尾、理解长连接短链接与cookie

前言&#xff1a;本节是http章节的最后一部分&#xff0c;主要解释一些小概念。讲解到了HTTP的方法&#xff0c;表单&#xff0c; 重定向等等。 现在废话不多说&#xff0c; 开始我们的学习吧。 ps&#xff1a;本节内容都是概念&#xff0c; 知道就行&#xff0c; 友友们放心观…

金融项目实战 03|JMeter脚本实现手工接口测试

目录 一、环境说明 1、项目环境搭建 2、Mock说明 二、构造测试数据 1、通过系统页面构造 2、通过接口构造 3、通过数据库构造【推荐】 4、案例&#xff1a;构造借款业务数据 三、JMeter执行接口测试用例 1、获取图片验证码、获取短信验证码 2、注册脚本 3、登录脚本…

点赞系统设计(微服务)

点赞业务是一个常见的社交功能&#xff0c;它允许用户对其他用户的内容&#xff08;如帖子、评论、图片等&#xff09;表示喜欢或支持。在设计点赞业务时&#xff0c;需要考虑以下几个方面&#xff1a; 一、业务需求 点赞业务需要满足以下特性&#xff1a; 通用&#xff1a;…

网络原理一>UDP协议详解

UDP和TCP都是应用层中的重要协议&#xff0c;如果做基础架构开发&#xff0c;会用得多一些。 这一篇我们先简单聊一下的UDP TCP格式呈现&#xff1a; 我们知道UDP是一种无连接&#xff0c;面向数据报&#xff0c;全双工&#xff0c;不可靠传输特性的网络协议。 基本格式如图…

时空笔记:CBEngine(微观交通模拟引擎)

CBEngine 是一个微观交通模拟引擎&#xff0c;可以支持城市规模的道路网络交通模拟。CBEngine 能够快速模拟拥有数千个交叉路口和数十万辆车辆的道路网络交通。 以下内容基本翻译自CBEngine — CBLab 1.0.0 documentation 1 模拟演示 1.0 模拟演示结构 config.cfg 定义了 roa…

金融项目实战 04|JMeter实现自动化脚本接口测试及持续集成

目录 一、⾃动化测试理论 二、自动化脚本 1、添加断言 1️⃣注册、登录 2️⃣认证、充值、开户、投资 2、可重复执行&#xff1a;清除测试数据脚本按指定顺序执行 1️⃣如何可以做到可重复执⾏&#xff1f; 2️⃣清除测试数据&#xff1a;连接数据库setup线程组 ①明确…