list的模拟实现

目录

1.默认成员函数模拟实现

1.1 构造函数(头节点)

1.2 析构函数

1.3 拷贝构造函数

1.4 赋值重载函数

2.增删查改模拟实现

2.1 insert

2.2 erase

2.3 push_back、pop

3.前置++、--、后置++、--

3.1前置: 

3.2后置:

3.3 =、!=

4.普通迭代器和const迭代器

4.1 普通迭代器

4.2 const迭代器

1.默认成员函数模拟实现

1.1 构造函数(头节点)

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

1.2 析构函数

~list()
{
	clear();
	delete _head;
	_head = nullptr;
}
void clear()
{
	//清理数据,不清头节点
	iterator it = begin();
	while (it != end())
	{
		it = erase(it);//it就是下一个位置
	}
}

1.3 拷贝构造函数

先搞头节点  

void empty_init()
{
	_head = new Node;
	_head->_next = _head;
	_head->_prev = _head;
}
//lt2(lt1)   lt2拷贝构造lt1,this就是lt2
list(const list<T>& lt)
{
	empty_init();
	for (auto e : lt)
	{
		push_back(e); 
	}
}

1.4 赋值重载函数

void swap(list<T>& lt)
{
	std::swap(_head, lt._head);//交换头指针
	std::swap(_size, lt._size);//交换_size
}
//lt3=lt1  lt就是lt1的拷贝构造  赋值重载
list<int>& operator=(const list<int>& lt)
{
	//现代写法
	swap(lt);
	return *this;
}

2.增删查改模拟实现

2.1 insert

iterator insert(iterator pos, const T& x)//在pos之前插入x
{
	Node* cur = pos._node;
	Node* newnode = new Node(x);
	Node* prev = cur->_prev;
	prev->_next = newnode;
	newnode->_prev = prev;
	newnode->_next = cur;
    cur->_prev = newnode;
    ++_size;
	return iterator(newnode);
}

2.2 erase

iterator erase(iterator pos) //在pos位置删除
{
	Node* cur = pos._node;
	Node* prev = cur->_prev;
	Node* next = cur->_next;
	delete cur;
	prev->_next = next;
	next->_next = prev;
	--_size;
	return iterator(next);
}

2.3 push_back、pop

void push_back(const T& x)
{
	insert(end(), x);
}
void push_front(const T& x)
{
	insert(begin(), x);
}
void pop_front()//头删就是在begin位置删除
{
	erase(begin());
}
void pop_back()//尾删
{
	erase(--end());
}

3.前置++、--、后置++、--

3.1前置: 

self& operator++()
{
	_node = _node->_next;
	return *this;
}
self& operator--()
{
	_node = _node->_prev;
	return *this;
}

3.2后置:

self operator++(int) //能用前置就不要用后置,后置要返回++之后的
{
	self tmp(*this);
	_node = _node->_next;
	return tmp;
}
self operator--(int) 
{
	self tmp(*this);
	_node = _node->_prev;
	return tmp;
}

3.3 =、!=

bool operator!=(const self& s)
{
	return _node != s._node;  //看节点的指针是否相等
}
bool operator==(const self& s)
{
	return _node == s._node;  //看节点的指针是否相等
}

4.普通迭代器和const迭代器

4.1 普通迭代器 iterator

list迭代器不是原生的指针,将节点的指针进行封装,来模拟指针的行为。 普通迭代器是可读可写

template<class T>
	struct list_node
	{
		T _data;
		list_node<T>* _next;
		list_node<T>* _prev;
		list_node(const T& x=T())
			:_data(x)
			,_next(nullptr)
			,_prev(nullptr)
		{}
	};
	template<class T>
	struct __list_iterator
	{
		typedef list_node<T> Node;
		typedef __list_iterator<T> self;
		Node* _node;
		__list_iterator(Node* node)
			:_node(node)
		{}
		self& operator++()
		{
			_node = _node->_next;
			return *this;
		}
		self& operator--()
		{
			_node = _node->_prev;
			return *this;
		}
		self operator++(int) //能用前置就不要用后置,后置要返回++之后的
		{
			self tmp(*this);
			_node = _node->_next;
			return tmp;
		}
		self operator--(int) 
		{
			self tmp(*this);
			_node = _node->_prev;
			return tmp;
		}
		T& operator*()
		{
			return _node->_data;
		}
		T* operator->()
		{
			return &_node->_data;
		}
		bool operator!=(const self& s)
		{
			return _node != s._node;  //看节点的指针是否相等
		}
		bool operator==(const self& s)
		{
			return _node == s._node;  //看节点的指针是否相等
		}
	};

如果list存的是自定义类型,怎么访问其中的数据呢?

 需要实现重载->  返回的是A对象的指针,在用->访问其中的成员

T* operator->()
{
	return &_node->_data;
}
struct AA
{
	AA(int a1=0,int a2=0)
	:_a1(a1)
	,_a2(a2)
	{}
	int _a1;
	int _a2;
};
void test_list3()
{
	list<AA> lt; //list中存的是自定义类型
	lt.push_back(AA(1, 1));
	lt.push_back(AA(2, 2));
	lt.push_back(AA(1, 3));
	list<AA>::iterator it = lt.begin();
	while (it != lt.end())
	{
	//	cout << *it << " ";//*it是A,A不支持流插入
	//	cout << (*it)._a1 << " " << (*it)._a2<<endl;
		cout << it->_a1 << " " << it->_a2 << endl;
		++it;
	}
	cout << endl;
}

4.2 const迭代器 const_iterator

const对象只能使用const类型的迭代器,const是只读的,模拟const T*,是指向的内容不可改变,而不是本身不可改变。const_iterator是一个全新的类型,不是const iterator

template<class T>
	class list
	{
		typedef list_node<T> Node;
	public:
		typedef __list_iterator<T> iterator;
		typedef __list_const_iterator<T> const_iterator;
		const_iterator begin() const
		{
			return const_iterator(_head->_next);
			//也可以写成 return _head->_next;隐式类型转换,和上面是一样的
		}
		const_iterator end() const//哨兵卫位置
		{
			return const_iterator(_head);
		}
}
template<class T>
	struct __list_const_iterator
	{
		typedef list_node<T> Node;
		typedef __list_const_iterator<T> self;
		Node* _node;
		__list_const_iterator(Node* node)
			:_node(node)
		{}
		self& operator++()
		{
			_node = _node->_next;
			return *this;
		}
		self& operator--()
		{
			_node = _node->_prev;
			return *this;
		}
		self operator++(int) //能用前置就不要用后置,后置要返回++之后的
		{
			self tmp(*this);
			_node = _node->_next;
			return tmp;
		}
		self operator--(int)
		{
			self tmp(*this);
			_node = _node->_prev;
			return tmp;
		}
		//返回的是data的别名
		const T& operator*()
		{
			return _node->_data;
		}
		const T* operator->()
		{
			return &_node->_data;
		}
		bool operator!=(const self& s)
		{
			return _node != s._node;  //看节点的指针是否相等
		}
		bool operator==(const self& s)
		{
			return _node == s._node;  //看节点的指针是否相等
		}
	};

使用:

void print_list(const list<int>&lt)
{
	list<int>::const_iterator it = lt.begin();
	while (it != lt.end())
	{
		//*it = 10;不能修改,调用operator*返回data的别名,加const不能修改
		cout << *it << " ";
		it++;
	}
}
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);
	print_list(lt);
}

但是const迭代器和普通迭代器主要区别就是返回值不一样,所以上面的写法太冗余了。使用模板,交给编译器去做。 

#pragma once
#include<iostream>
using namespace std;
namespace bit
{
	template<class T>
	struct list_node
	{
		T _data;
		list_node<T>* _next;
		list_node<T>* _prev;
		list_node(const T& x=T())
			:_data(x)
			,_next(nullptr)
			,_prev(nullptr)
		{}
	};
	//T T& T*
	//T const T& const T*
	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)
		{}
		self& operator++()
		{
			_node = _node->_next;
			return *this;
		}
		self& operator--()
		{
			_node = _node->_prev;
			return *this;
		}
		self operator++(int) //能用前置就不要用后置,后置要返回++之后的
		{
			self tmp(*this);
			_node = _node->_next;
			return tmp;
		}
		self operator--(int) 
		{
			self tmp(*this);
			_node = _node->_prev;
			return tmp;
		}
		Ref operator*()
		{
			return _node->_data;
		}
		Ptr operator->()
		{
			return &_node->_data;
		}
		bool operator!=(const self& s)
		{
			return _node != s._node;  //看节点的指针是否相等
		}
		bool operator==(const self& s)
		{
			return _node == s._node;  //看节点的指针是否相等
		}
	};
	
	template<class T>
	class list
	{
		typedef list_node<T> Node;
	public:
		typedef __list_iterator<T,T&,T*> iterator;
		typedef __list_iterator<T,const T&,const T*> const_iterator;//通过模板参数去控制是普通迭代器还是const
		const_iterator begin() const
		{
			return const_iterator(_head->_next);
			//也可以写成 return _head->_next;隐式类型转换,和上面是一样的
		}
		const_iterator end() const//哨兵卫位置
		{
			return const_iterator(_head);
		}
		iterator begin()
		{
			return iterator(_head->_next);
		}
		iterator end() //哨兵卫位置
		{
			return iterator(_head);
		}
		void empty_init()
		{
			_head = new Node;
			_head->_next = _head;
			_head->_prev = _head;
			_size = 0;
		}
		list()
		{
			empty_init();
		}
		//lt2(lt1)   lt2拷贝构造lt1,this就是lt2
		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);//交换_size
		}
		//lt3=lt1  lt就是lt1的拷贝构造  赋值重载
		list<int>& operator=(const list<int>& lt)
		{
			//现代写法
			swap(lt);
			return *this;
		}
		~list()
		{
			clear();
			delete _head;
			_head = nullptr;
		}
		void clear()
		{
			//清理数据,不清头节点
			iterator it = begin();
			while (it != end())
			{
				it = erase(it);//it就是下一个位置
			}
		}
		void push_back(const T& x)
		{
			/*Node* tail = _head->_prev;
			Node* newnode = new Node(x);
			tail->_next = newnode;
			newnode->_prev = tail;
			newnode->_next = _head;
			_head->_prev = newnode;*/
		    insert(end(), x);
		}
		void push_front(const T& x)
		{
			insert(begin(), x);
		}
		void pop_front()//头删就是在begin位置删除
		{
			erase(begin());
		}
		void pop_back()//尾删
		{
			erase(--end());
		}
		iterator insert(iterator pos, const T& x)//在pos之前插入x
		{
			Node* cur = pos._node;
			Node* newnode = new Node(x);
			Node* prev = cur->_prev;
			prev->_next = newnode;
			newnode->_prev = prev;
			newnode->_next = cur;
			cur->_prev = newnode;
			++_size;
			return iterator(newnode);
		}
		iterator erase(iterator pos) //在pos位置删除
		{
			Node* cur = pos._node;
			Node* prev = cur->_prev;
			Node* next = cur->_next;
			delete cur;
			prev->_next = next;
			next->_next = prev;
			--_size;
			return iterator(next);
		}
		size_t size()
		{
			return _size;
		}
	private:
		Node* _head;
		size_t _size;
	};
	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;
	}
	struct AA
	{
		AA(int a1=0,int a2=0)
			:_a1(a1)
			,_a2(a2)
		{}
		int _a1;
		int _a2;
	};
	void test_list2()
	{
		list<AA> lt; //list中存的是自定义类型
		lt.push_back(AA(1, 1));
		lt.push_back(AA(2, 2));
		lt.push_back(AA(1, 3));
		list<AA>::iterator it = lt.begin();
		while (it != lt.end())
		{
		//	cout << *it << " ";//*it是A,A不支持流插入
		//	cout << (*it)._a1 << " " << (*it)._a2<<endl;
			cout << it->_a1 << " " << it->_a2 << endl;
			++it;
		}
		cout << endl;
	}
	void print_list(const list<int>&lt)
	{
		list<int>::const_iterator it = lt.begin();
		while (it != lt.end())
		{
			//*it = 10;不能修改,调用operator*返回data的别名,加const不能修改
			cout << *it << " ";
			it++;
		}
	}
	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);
		print_list(lt);
	}
}

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

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

相关文章

STC89C52驱动XPT2046AD转换

目录 简介封装接线&#xff08;单端&#xff09;时序以及命令字SPI时序命令字 程序XPT2046.CXPT2046.hmain.c测试 简介 XPT2046是一款4线电阻式触摸屏控制器&#xff0c;采用12位125 kHz采样SAR类型A / D转换器。XPT2046工作电压低至2.2V&#xff0c;支持1.5V至VCC的数字I/O接…

休斯《公共管理导论》第5版/考研真题解析/章节题库

第一部分 考研真题精选 一、概念题二、简答题三、论述题四、案例分析题第二部分 章节题库 第1章 一个变革的时代第2章 政府的角色第3章 传统的公共行政模式第4章 公共管理第5章 公共政策第6章 治 理第7章 问 责第8章 利害关系人和外部环境第9章 管制、外包和公共企…

jenkins目录下的vue3项目——pnpm install后运行报错——奇葩问题解决

昨天到今天&#xff0c;同事那边遇到一个问题&#xff0c;就是关于vue3vite的项目&#xff0c;在执行了自动打包后&#xff0c;运行代码会提示报错的问题。 报错信息如下&#xff1a; 具体错误信息如下&#xff1a; ERROR 11:28:14 [vite] Pre-transform error: Cannot find …

Xshell连接提示“SSH服务器拒绝了密码”

原因1&#xff1a;数字锁没有打开 没有打开NumLock&#xff08;数字小键盘上面有一个【Num】按键&#xff09;&#xff0c;需要按键开启。 注意要检查NumLock灯是否亮起。 或者改成用字母键上面的数字键输入就好了。 原因2&#xff1a;root密码设置错误&#xff08;这个是比较常…

frp内网穿透服务搭建与使用

frp内网穿透服务搭建与使用 1、frp简介 frp 是一个专注于内网穿透的高性能的反向代理应用&#xff0c;支持 TCP、UDP、HTTP、HTTPS 等多种协议。 可以将内网服务以安全、便捷的方式通过具有公网 IP 节点的中转暴露到公网。frp工作原理 服务端运行&#xff0c;监听一个主端口…

深入Django:用户认证与权限控制实战指南

title: 深入Django&#xff1a;用户认证与权限控制实战指南 date: 2024/5/7 18:50:33 updated: 2024/5/7 18:50:33 categories: 后端开发 tags: AuthDecoratorsPermissionsGuardianRESTAuthSessionMgmtMFA 第1章&#xff1a;入门Django与设置 1.1 Django安装与环境配置 在…

netty 高性能架构设计--零拷贝

文章目录 前言一、直接内存1.1 什么是直接内存1.2 代码实现1.3 使用直接内存的优缺点 二、netty 零拷贝设计2.1 netty 直接内存2.2 netty 内存池 三、零拷贝的两种方式 前言 本篇从源码层面剖析 netty 高性能架构设计之零拷贝&#xff0c;并且扩展讲述零拷贝的两种实现方式。 …

并发编程之阻塞队列BlockingQueue实战及其原理分析

1. 阻塞队列介绍 1.1 队列 是限定在一端进行插入&#xff0c;另一端进行删除的特殊线性表。 先进先出(FIFO)线性表。 允许出队的一端称为队头&#xff0c;允许入队的一端称为队尾。

机器学习第二天(监督学习,无监督学习,强化学习,混合学习)

1.是什么 基于数据寻找规律从而建立关系&#xff0c;进行升级&#xff0c;如果是以前的固定算式那就是符号学习了 2.基本框架 3.监督学习和无监督式学习&#xff1a; 监督学习&#xff1a;根据正确结果进行数据的训练&#xff1b; 在监督式学习中&#xff0c;训练数据包括输…

简易录制视频做3D高斯

系统环境 ubuntu20 &#xff0c;cuda11.8&#xff0c;anaconda配置好了3D高斯的环境。 具体参考3D高斯环境配置&#xff1a;https://blog.csdn.net/Son_of_the_Bronx/article/details/138527329?spm1001.2014.3001.5501 colmap安装&#xff1a;https://blog.csdn.net/Son_of…

W801学习笔记二十一:英语背单词学习应用——上

英语背单词是比较常见的学习APP&#xff0c;参考唐诗宋词应用&#xff0c;本章做一个类似的应用。 一、单词数据清洗及格式转换 诗词数据的获取渠道很多&#xff0c;一般可以按照年级来分文件。如一到九年级&#xff0c;四六级&#xff0c;雅思等等。 1、先从网上某某地方下载…

硬件设计细节1-缓冲驱动器使用注意事项

目录 一、缓冲驱动器二、实例分析1.硬件结构2.问题描述3.原因分析4.原因定位 三、结论 一、缓冲驱动器 缓冲驱动器通常用于隔离、电平转换等应用场景。在使用时&#xff0c;需要关注的点较多&#xff0c;如电平范围、频率范围、延时、控制方式、方向以及输入输出状态。通常&am…

JavaScript异步编程——03-Ajax传输json和XML

Ajax 传输 JSON JSON 的语法 JSON(JavaScript Object Notation)&#xff1a;是 ECMAScript 的子集。作用是进行数据的交换。语法更为简洁&#xff0c;网络传输、机器解析都更为迅速。 语法规则&#xff1a; 数据在键值对中 数据由逗号分隔 花括号保存对象 方括号保存数组…

弹性云服务器是什么,为何如此受欢迎

云计算作为当下炙手可热的技术领域&#xff0c;已然成为现代企业不可或缺的核心能力。云服务器作为云计算的基石之一&#xff0c;在这个数字化时代发挥着至关重要的作用。而弹性云服务器&#xff0c;作为云服务器的一种演进形式&#xff0c;更是备受瞩目。 弹性云服务器&#…

使用 GPT-4-turbo+Streamlit+wiki+calculator构建Math Agents应用【Step by Step】

&#x1f496; Brief&#xff1a;大家好&#xff0c;我是Zeeland。Tags: 大模型创业、LangChain Top Contributor、算法工程师、Promptulate founder、Python开发者。&#x1f4dd; CSDN主页&#xff1a;Zeeland&#x1f525;&#x1f4e3; 个人说明书&#xff1a;Zeeland&…

自动化运维管理工具 Ansible-----【inventory 主机清单和playbook剧本】

目录 一、inventory 主机清单 1.1inventory 中的变量 1.1.1主机变量 1.1.2组变量 1.1.3组嵌套 二、Ansible 的脚本 ------ playbook&#xff08;剧本&#xff09; 2.1 playbook介绍 2.2playbook格式 2.3playbooks 的组成 2.4playbook编写 2.5运行playbook 2.5.1ans…

学习笔记:【QC】Android Q qmi扩展nvReadItem/nvWriteItem

一、qmi初始化 流程图 初始化流程: 1、主入口&#xff1a; vendor/qcom/proprietary/qcril-hal/qcrild/qcrild/rild.c int main(int argc, char **argv) { const RIL_RadioFunctions *(*rilInit)(const struct RIL_Env *, int, char **); rilInit RIL_Init; funcs rilInit…

【Linux】Linux线程

一、Linux线程的概念 1.什么是线程 1.一个进程的一个执行线路叫做线程&#xff0c;线程的一个进程内部的控制序列。 2.一个进程至少有一个执行线程 3.线程在进程内部&#xff0c;本质是在进程地址空间内运行 4.操作系统将进程虚拟地址空间的资源分配给每个执行流&#xff0…

基于51单片机的闭环反馈直流电机PWM控制电机转速测量( proteus仿真+程序+设计报告+原理图+讲解视频)

基于51单片机的闭环反馈直流电机PWM控制转速测量( proteus仿真程序设计报告原理图讲解视频&#xff09; 仿真图proteus7.8及以上 程序编译器&#xff1a;keil 4/keil 5 编程语言&#xff1a;C语言 设计编号&#xff1a;S0086 1. 主要功能&#xff1a; 基于51单片机的闭环…

js宏任务微任务输出解析

第一种情况 setTimeout(function () {console.log(setTimeout 1) //11 宏任务new Promise(function (resolve) {console.log(promise 1) //12 同步函数resolve()}).then(function () {console.log(promise then) //13 微任务})})async function async1() {console.log(async1 s…