C++模拟实现list:list、list类的初始化和尾插、list的迭代器的基本实现、list的完整实现、测试、整个list类等的介绍

news2024/9/20 23:22:18

文章目录

  • 前言
  • 一、list
  • 二、list类的初始化和尾插
  • 三、list的迭代器的基本实现
  • 四、list的完整实现
  • 五、测试
  • 六、整个list类
  • 总结


前言

C++模拟实现list:list、list类的初始化和尾插、list的迭代器的基本实现、list的完整实现、测试、整个list类等的介绍


一、list

list本质上是一个双向带头循环链表。
实现list类,需要节点类(clase list_node)、迭代器(class __list_iterator);
节点类(clase list_node): 定义每个节点的结构;
迭代器(class __list_iterator): 使用节点的指针封装出一个类,可以使用运算符重载的形式更好的访问链表;

二、list类的初始化和尾插

namespace hhb
{

	// 节点
	template <class T>
	struct list_node
	{
		list_node(const T& val = T())
			: _next(nullptr)
			, _prev(nullptr)
			, _val(val)
		{}

		list_node<T>* _next;
		list_node<T>* _prev;
		T _val;
	};


	// 链表
	 template<class T> 
	class list
	{
		typedef list_node<T> Node;
	public:
		list()
		{
			_head = new Node;
			_head->_next = _head;
			_head->_prev = _head;
		}

		void push_back(const T& x)
		{
			Node* newNode = new Node(x);
			Node* tail = _head->_prev;

			newNode->_next = _head;
			newNode->_prev = tail;

			tail->_next = newNode;
			_head->_prev = newNode;
		}

	private:
		Node* _head;
	};
}

在这里插入图片描述

三、list的迭代器的基本实现

  • 使用链表节点的指针封装出一个类,是list链表的访问可以向vector一样使用++等操作访问
  • vector和list的使用,虽然在形式上一样,但是他们的底层是不一样的
  • (*)vector迭代器是对指针的解引用
  • (*)list迭代器是调用operator(解引用操作符)函数重载,本质是不一样的

对于const迭代器,是operator(*)和 operator(->)的运算符重载函数的返回值不一样,因此需要增加两个模板参数

  • 即: (T& 和 T*)
// 迭代器
template <class T, class Ref, class Ptr>
struct __list_iterator
{
	typedef list_node<T> Node;
	typedef __list_iterator<T, Ref, Ptr> self;
public:
	__list_iterator(Node* node)
		:_node(node)
	{}

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

	Ptr operator->()
	{
		return &_node->_val;
	}

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

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

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

	self operator--(int)
	{
		self tmp(*this);
		_node = _node->_prev;
		return tmp;
	}

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

	Node* _node;
};
  • operator->运算符重载编译器会进行优化, 如下:
struct A
{
public:
	A(int a1 = 0, int a2 = 0)
		: _a1(a1)
		, _a2(a2)
	{}
	int _a1;
	int _a2;
};
void test_list02()
{
	hhb::list<A> lt;

	lt.push_back(A(1, 1));
	lt.push_back(A(2, 2));
	lt.push_back(A(3, 3));
	lt.push_back(A(4, 4));
	lt.push_back(A(5, 5));

	hhb::list<A>::iterator it = lt.begin();

	while (it != lt.end())
	{
		//cout << (*it)._a1 << " " << (*it)._a2 << " " << endl;
		cout << it->_a1 << " " << it->_a2 << " " << endl;
		// 此处编译器进行了优化, it->返回的是T* 也就是 A*, 如果要访问A的成员
		// 按道理来讲,应该是 (it->)->_a1 / (it->)->_a2 来进行访问
		++it;
	}
	cout << endl;

}

在这里插入图片描述

四、list的完整实现

  • list需要有size()的接口,所以需要对链表节点个数进行计数,增加一个成员变量_size.
  • 实现insert()和erase()接口后,push_back()和push_front()、pop_back()和pop_front()接口都可以复用接口。
  • clear()只清除(不包含哨兵位的头节点)数据,不销毁链表
  • 析构函数调用clear()后,释放_head节点(哨兵位的头节点)
  • 拷贝构造函数在拷贝之前,一定要先自己初始化(创建哨兵位的头节点)
  • 赋值(=)运算符重载使用现代写法,拷贝构造加交换函数加自动调用析构函数。
	// 链表
	 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;


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

		iterator end()
		{
			return _head;
		}

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

		const_iterator end() const
		{
			return _head;
		}

		void emptyInit()
		{
			_head = new Node;
			_head->_next = _head;
			_head->_prev = _head;

			_size = 0;
		}


		list()
		{
			emptyInit();
		}

		list(const list<T>& lt)
		{
			emptyInit();

			for (auto e : lt)
			{
				push_back(e);
			}
		}

		void swap(list<T>& lt)
		{
			std::swap(_head, lt._head);
			std::swap(_size, lt._size);
		}

		list<T> operator=(list<T> lt)
		{
			swap(lt);
			return *this;
		}

		~list()
		{
			clear();

			delete _head;
			_head = nullptr;

			_size = 0;
		}

		void push_back(const T& x)
		{
			//Node* newNode = new Node(x);
			//Node* tail = _head->_prev;

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

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


			insert(end(), x);
		}

		void push_front(const T& x)
		{
			insert(begin(), x);
		}

		void pop_back()
		{
			erase(--end());
		}

		void pos_front()
		{
			erase(begin());
		}

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

			newNode->_next = cur;
			newNode->_prev = prev;

			cur->_prev = newNode;
			prev->_next = newNode;

			++_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;
			cur = nullptr;

			--_size;

			return next;
		}

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

		size_t size()
		{
			return _size;
		}


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

			_size = 0;
		}
	
	private:
		Node* _head;
		size_t _size;
	};
}

五、测试

  • 测试push_back, pop_back可以顺便测试insert, erase函数, 所以不单独测试insert和erase函数
void test_list03()
{
	hhb::list<int> lt;

	lt.push_back(1);
	lt.push_back(2);
	lt.push_back(3);
	lt.push_back(4);
	lt.push_front(5);
	lt.push_front(6);
	lt.push_front(7);
	lt.push_front(8);

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

	lt.pop_back();
	lt.pos_front();

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


	lt.clear();

	lt.push_back(10);
	lt.push_back(20);
	lt.push_back(30);
	lt.push_back(40);
	lt.push_back(50);


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

	cout << lt.size() << endl;


}

在这里插入图片描述

  • 测试拷贝构造和赋值运算符重载
void test_list04()
{
	hhb::list<int> lt;

	lt.push_back(1);
	lt.push_back(2);
	lt.push_back(3);
	lt.push_back(4);

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

	hhb::list<int> lt1(lt);

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

	hhb::list<int> lt2;
	lt2.push_back(10);
	lt2.push_back(20);
	lt2.push_back(30);
	lt2.push_back(40);

	lt1 = lt2;

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

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


}

在这里插入图片描述

六、整个list类

// list.h
#pragma once

#include <assert.h>
namespace hhb
{

	// 节点
	template <class T>
	struct list_node
	{
		list_node(const T& val = T())
			: _next(nullptr)
			, _prev(nullptr)
			, _val(val)
		{}

		list_node<T>* _next;
		list_node<T>* _prev;
		T _val;
	};

	// 迭代器
	template <class T, class Ref, class Ptr>
	struct __list_iterator
	{
		typedef list_node<T> Node;
		typedef __list_iterator<T, Ref, Ptr> self;
	public:
		__list_iterator(Node* node)
			:_node(node)
		{}

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

		Ptr operator->()
		{
			return &_node->_val;
		}

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

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

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

		self operator--(int)
		{
			self tmp(*this);
			_node = _node->_prev;
			return tmp;
		}

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

		Node* _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;


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

		iterator end()
		{
			return _head;
		}

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

		const_iterator end() const
		{
			return _head;
		}

		void emptyInit()
		{
			_head = new Node;
			_head->_next = _head;
			_head->_prev = _head;

			_size = 0;
		}


		list()
		{
			emptyInit();
		}

		list(const list<T>& lt)
		{
			emptyInit();

			for (auto e : lt)
			{
				push_back(e);
			}
		}

		void swap(list<T>& lt)
		{
			std::swap(_head, lt._head);
			std::swap(_size, lt._size);
		}

		list<T> operator=(list<T> lt)
		{
			swap(lt);
			return *this;
		}

		~list()
		{
			clear();

			delete _head;
			_head = nullptr;

			_size = 0;
		}

		void push_back(const T& x)
		{
			//Node* newNode = new Node(x);
			//Node* tail = _head->_prev;

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

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


			insert(end(), x);
		}

		void push_front(const T& x)
		{
			insert(begin(), x);
		}

		void pop_back()
		{
			erase(--end());
		}

		void pos_front()
		{
			erase(begin());
		}

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

			newNode->_next = cur;
			newNode->_prev = prev;

			cur->_prev = newNode;
			prev->_next = newNode;

			++_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;
			cur = nullptr;

			--_size;

			return next;
		}

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

		size_t size()
		{
			return _size;
		}


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

			_size = 0;
		}
	
	private:
		Node* _head;
		size_t _size;
	};
}
  • 整个测试
#define  _CRT_SECURE_NO_WARNINGS

#include <iostream>
#include <list>
using namespace std;
#include "list.h"


void print1(const hhb::list<int>& lt)
{
	hhb::list<int>::const_iterator it = lt.begin();
	while (it != lt.end())
	{
		cout << *it << " ";
		++it;
	}
	cout << endl;
}

void test_list01()
{
	hhb::list<int> lt;

	lt.push_back(1);
	lt.push_back(2);
	lt.push_back(3);
	lt.push_back(4);
	lt.push_back(5);

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


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


	print1(lt);
}

struct A
{
public:
	A(int a1 = 0, int a2 = 0)
		: _a1(a1)
		, _a2(a2)
	{}
	int _a1;
	int _a2;
};



void test_list02()
{
	hhb::list<A> lt;

	lt.push_back(A(1, 1));
	lt.push_back(A(2, 2));
	lt.push_back(A(3, 3));
	lt.push_back(A(4, 4));
	lt.push_back(A(5, 5));

	hhb::list<A>::iterator it = lt.begin();

	while (it != lt.end())
	{
		//cout << (*it)._a1 << " " << (*it)._a2 << " " << endl;
		cout << it->_a1 << " " << it->_a2 << " " << endl;
		// 此处编译器进行了优化, it->返回的是T* 也就是 A*, 如果要访问A的成员
		// 按道理来讲,应该是 (it->)->_a1 / (it->)->_a2 来进行访问
		++it;
	}
	cout << endl;

}

void test_list03()
{
	hhb::list<int> lt;

	lt.push_back(1);
	lt.push_back(2);
	lt.push_back(3);
	lt.push_back(4);
	lt.push_front(5);
	lt.push_front(6);
	lt.push_front(7);
	lt.push_front(8);

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

	lt.pop_back();
	lt.pos_front();

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


	lt.clear();

	lt.push_back(10);
	lt.push_back(20);
	lt.push_back(30);
	lt.push_back(40);
	lt.push_back(50);


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

	cout << lt.size() << endl;


}


void test_list04()
{
	hhb::list<int> lt;

	lt.push_back(1);
	lt.push_back(2);
	lt.push_back(3);
	lt.push_back(4);

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

	hhb::list<int> lt1(lt);

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

	hhb::list<int> lt2;
	lt2.push_back(10);
	lt2.push_back(20);
	lt2.push_back(30);
	lt2.push_back(40);

	lt1 = lt2;

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

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


}


int main()
{

	//test_list01();

	test_list02();

	//test_list03();

	//test_list04();

	return 0;
}

总结

C++模拟实现list:list、list类的初始化和尾插、list的迭代器的基本实现、list的完整实现、测试、整个list类等的介绍

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

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

相关文章

LeetCode讲解篇之220. 存在重复元素 III

文章目录 题目描述题解思路题解代码 题目描述 题解思路 我们可以考虑存储数组中连续indexDiff个数字&#xff0c;这样我们只需要在这连续的indexDiff个数字中查找相差小于等于valueDiff的两个数字的问题 对于该查找问题&#xff0c;我们可以考虑使用以valueDiff大小为一个桶&a…

自动化测试常用函数

目录 一、元素的定位 1、cssSelector 2、xpath &#xff08;1&#xff09;xpath 语法 1、获取HTML页面所有的节点 2、获取HTML页面指定的节点 3、获取一个节点中的直接子节点 4、获取一个节点的父节点 5、实现节点属性的匹配 6、使用指定索引的方式获取对应的节点内容…

MYSQL面试知识点手册

第一部分&#xff1a;MySQL 基础知识 1.1 MySQL 简介 MySQL 是世界上最流行的开源关系型数据库管理系统之一&#xff0c;它以性能卓越、稳定可靠和易用性而闻名。MySQL 主要应用在 Web 开发、大型互联网公司、企业级应用等场景&#xff0c;且广泛用于构建高并发、高可用的数据…

动态线程池(四)

动态线程池 dtp生命周期管理 生命周期相关类图 DtpExecutor EagerEtpExecutor OrderedDtpExecutor TaskWrapper任务包装器 MdcRunnable TaskWrappers NotifyEnum NoticeManager通知管理器 InvokerChain调用链

AI与量化投资人才培养计划-连接职场 助力走在金融行业前沿

AI与量化投资人才培养计划-连接职场 助力走在金融行业前沿 人工智能&#xff08;AI&#xff09;的快速发展&#xff0c;量化投资已逐渐成为金融行业的新趋势&#xff0c;对专业人才的需求日益迫切。本文将深入探讨一项针对AI与量化投资的人才培养计划&#xff0c;旨在为金融专业…

No operations allowed after statement closed

错误信息&#xff1a; The last packet successfully received from the server was 3,576,246 milliseconds ago. The last packet sent successfully to the server was 3,576,247 milliseconds ago. 参考解决方案 https://github.com/alibaba/druid/issues/5549 如果修改…

誉龙视音频 Third/TimeSyn 远程命令执行复现

0x01 漏洞描述&#xff1a; 誉龙公司定位为系统级的移动视音频记录解决方案提供商&#xff0c;凭借其深厚的行业经验&#xff0c;坚持自主研发&#xff0c;匠心打造记录仪领域行业生态&#xff0c;提供开放式的记录仪APK、GB28181 SDK、国网B协议、管理平台软件OEM。誉龙视音频…

leaflet加载GeoServer的WMS地图服务.md

leaflet加载GeoServer的WMS地图服务&#xff0c;该示例涵盖了涵盖了 “WMS图层加载、WMS图层动态投影、图层index顺序调整、图层添加、高德地图、腾讯地图OpenStreet地图”&#xff0c;WMS图层加载看代码中标注的核心代码部分即可。 <!DOCTYPE html> <html xmlns&qu…

湖南(用户访谈)源点咨询 市场调研中何种情况下选择定性方式?

湖南&#xff08;市场调研&#xff09;源点咨询认为&#xff0c;很多调研方法被分组为"定性调研方法"或"收集资料的定性方法"。 这反映了对定性调研的继承&#xfe63;&#xfe63;它的根源在于社会科学&#xff0c;尤其在社会学和人类学&#xff0c;还有…

AI大模型之旅-langchain结合glm4,faiss构建本地知识库

所需依赖如下&#xff1a; _libgcc_mutex0.1main _openmp_mutex5.11_gnu accelerate0.34.2pypi_0 aiofiles23.2.1pypi_0 aiohappyeyeballs2.4.0pypi_0 aiohttp3.10.5pypi_0 aiosignal1.3.1pypi_0 annotated-types0.7.0pypi_0 anyio4.4.0pypi_0 attrs24.2.0pypi_0 bitsandbytes…

Web开发:ABP框架3——入门级别的接口增删改查实现原理

一、上节回顾 运用了ABP框架&#xff0c;使用了EFcore进行增删改查 二、程序的入口 代码解说&#xff1a; public class Program // 定义程序主类 {public async static Task<int> Main(string[] args) // 主方法&#xff0c;返回状态码{// 配置Serilog日志Log.Logger…

如何给zip文件设置自动加密,保护压缩包不被随意打开

ZIP是日常生活和工作中经常用到的压缩文件格式&#xff0c;对于重要的文件&#xff0c;我们往往还会设置打开密码&#xff0c;保护压缩包不被随意打开。 如果每次压缩文件都要设置一次密码&#xff0c;操作久了还是有点麻烦&#xff0c;那有没有一种方法&#xff0c;只要压缩文…

数据库系统原理与应用【笔记总结】

笔记链接&#xff1a;CongSec电脑端可能需要科学上网&#xff0c;手机端不用 笔记部分展示&#xff1a; 笔记列表形式&#xff1a; 数据库系统概述 数据与信息 数据信息数据处理 数据管理技术的发展 人工管理阶段文件系统阶段数据库系统阶段 数据库系统的基本概念 数据库数据…

C#自定义曲线绘图面板

一、实现功能 1、显示面板绘制。 2、拖动面板&#xff0c;X轴、Y轴都可以拖动。 3、显示面板缩放&#xff0c;放大或者缩小。 4、鼠标在面板中对应的XY轴数值。 5、自动生成的数据数组&#xff0c;曲线显示。 6、鼠标是否在曲线上检测。 二、界面 拖动面板 鼠标在曲线上…

2024年亲测好用的四大在线翻译工具大盘点!

在互联网技术飞速发展的今天&#xff0c;各种在线翻译工具应运而生&#xff0c;它们不仅能够帮助我们跨越语言障碍&#xff0c;还能让我们更加便捷地获取世界各地的信息。接下来&#xff0c;我将结合自己的实际体验&#xff0c;为大家详细介绍几款优秀的在线翻译工具&#xff0…

15.多线程概述一(下篇)

目录 1.进程与线程 2.实现多线程方式一&#xff1a;继承Thread类【应用】 3.实现多线程方式二&#xff1a;实现Runnable接口【应用】 4.实现多线程方式三&#xff1a;实现Callable接口【应用】 5.三种实现方式的对比与套路 6.设置和获取线程名称/线程对象【应用】 7.线程优先级…

芹菜麦饭的做法

蒸煮时间&#xff1a; 芹菜麦饭的蒸煮时间因做法和食材的不同而有所差异&#xff0c;但一般在‌8到15分钟‌之间。具体蒸煮时间取决于芹菜的大小、切段的长度以及蒸锅的火力等因素。例如&#xff0c;将裹好面粉的芹菜段放入蒸锅&#xff0c;大火烧开后转中火蒸10~15分钟&#x…

LeetCode118:杨辉三角

题目链接&#xff1a;118. 杨辉三角 - 力扣&#xff08;LeetCode&#xff09; 代码如下 class Solution {public:vector<vector<int>> generate(int numRows) {vector<vector<int>> dp(numRows);vector<int> temp(numRows);for (int i 0; i &…

数据中台建设(六)—— 数据开发-提取数据价值

数据开发-提取数据价值 数据开发涉及的产品能力主要包括三部分&#xff1a;离线开发、实时开发和算法开发。 离线开发主要包括离线数据的加工、发布、运维管理&#xff0c;以及数据分析、数据探索、在线查询和及时分析相关工作。实时开发主要涉及数据的实时接入和实时处理。算…

Jmeter 线程组解析

1.seUp线程组 一种特殊的 threadGroup &#xff0c;可用于执行预测试操作&#xff1b;它的行为完全像一个正常的线程组元件&#xff0c;不同的是执行顺序。 它会在普通线程组执行之前被触发。 应用场景&#xff1a; 测试数据库操作功能时&#xff0c;用于执行打开数据库连接的…