C++模拟实现——list

news2024/12/23 13:42:50

一、成员变量及其基本结构

1.基本结构模型

本质是一个带头双向循环列表,将节点进行封装,并且为了方便使用,进行重定义

2.节点的封装定义

	template<class T>
	//定义节点
	struct list_node
	{
		list_node<T>* _prev;
		list_node<T>* _next;
		T _data;

		list_node(const T& x = T()) :
			_prev(nullptr),
			_next(nullptr),
			_data(x)
		{}
	};

在定义节点时,要注意将初始化一起进行封装完成,提供默认构造函数

3.成员变量的定义

成员变量是一个哨兵位的头结点

typedef list_node<T> node;//对节点重命名,方便使用
private:
	list_node<T>* _head;

二、迭代器(重点)

1.介绍

list的迭代器用原生指针无法实现,需要对原生指针进行封装,然后对顺序表指针的行为操作进行模拟实现,是list模拟实现中最大的重点难点,此时从使用者的角度上看,依然能将iterator看作为指针去使用,但设计者的角度上看,其本质是一个指针的封装,是个自定义类型。

2.对指针的基本封装

template<class T>
struct __list_iterator
{
    typedef list_node<int> node;//将节点重定义方便使用
    typedef __list_iterator<int> self;//将类型重定义方便使用

    //成员变量
    node* _node;

    //初始化
    __list_iterator(node* n)
    :_node(n)
    {}
    //模拟实现指针操作
    ...
}

以上对节点指针进行了封装处理,之后逐一实现常用的功能,例如:++ 、--、* 、 -> 、== 、!= 等等

3.++和--

要提供迭代器++和--的操作,需要对运算符进行重载,链表迭代器的++本质上是获得下一个节点的地址,--则是前一个节点的地址,并且要区分前置和后置

        //++
        slef& operator++()
        {
            _node = _node->_next;
            return *this;
        }
        slef operator++(int)//后置
        {
            slef 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;
		}

4.== 和 !=

迭代器的比较,本质是要比较其封装在内部的指针是否同一个

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

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

5. * 和 ->

对解引用操作符的重载,则需要考虑到常量迭代器的调用,常量迭代器去本质是对迭代器所指向的内容进行常量化,因此在这里,const_iterator 和 iterator 的核心区别在于解引用后返回的值是否常量,其他功能相同,因此可以使用类模板去控制这两个运算符重载返回值的区别,在定义部分加上两个新的模板参数即可。

template<class T,class Ref,class Ptr>
strucr __list_iterator
{
    ...//定义和重命名等等
    
    Ref operator*()//  Ref == T&(迭代器) / const T&(常量迭代器)
    {
        return _node->_data;
    }

//对于->的重载,存在特殊处理,只需要返回
    Ptr operator->()// Ptr == T*(迭代器)/ const T*(常量迭代器)
    {
        return& _node->_data;
    }
}

// 迭代器定义部分,在list类内定义
// typedef __list_iterator<T,T&,T*> iterator;
// typedef __list_con_iterator<T,const T&,const T*>;

三、构造与析构

1.默认构造函数

默认构造需要初始化出一个哨兵位的头结点,并且让节点指针指向自己,为了方便其他构造函数初始化哨兵位的头结点,可以单独写一个函数进行复用

		void empty_init()
		{
			_head = new node;
			_head->_next = _head;
			_head->_prev = _head;
		}
		list()//直接的初始化
		{
			empty_init();
		}

2.用迭代器区间去构造

迭代器区间构造需要借助函数模板,任意类型的迭代器都可以将值拷贝到容器中

template<class Iterator>
list(Iterator first,Iterator last)
{
    //先得初始化容器
    empty_init();
    while(first != last)
    {
        push_back(*first); // 底层是
        ++first;
    }
}

3.拷贝构造

拷贝构造这里选择对上面的构造函数进行复用,深拷贝出一个tmp,在进行交换

		void swap(list<T>& lt)
		{
			std::swap(_head, lt._head);
		}
		list(const list<T>& lt)//拷贝构造
		{
			empty_init();
			list<T> tmp(lt.begin(), lt.end());
			swap(tmp);
		}

4.赋值重载

赋值重载的底层实现,也是在传参的时候,调用了拷贝构造实现深拷贝后,在进行交换

		list<T>& operator=(list<T> lt)//赋值重载
		{
			swap(lt);
			return *this;
		}

5.析构函数

可以先实现clear,然后复用,底层就是将所有节点全部逐一释放,用迭代器遍历释放即可

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


        ~list()//析构
		{
			clear();
			delete _head;
			_head = nullptr;
		}

四、增删操作

对应增删操作,只需要实现insert和erase,其余的头插头删等等都可以对其进行复用,这里是用迭代器去实现的。

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

			//链接
			new_node->_prev = prev;
			prev->_next = new_node;
			new_node->_next = cur;
			cur->_prev = new_node;
		}

		iterator erase(iterator pos)
		{
			assert(pos != end());
			node* cur = pos._node;
			node* prev = cur->_prev;
			node* next = cur->_next;
			delete cur;
			//链接
			prev->_next = next;
			next->_prev = prev;
			return iterator(next);
		}

需要注意的是,erase后迭代器会失效,因此为了部分场景下的方便,erase是有一个返回值的,返回的是下一个节点的迭代器;

总结

本章通过自行模拟实现了list,加深了类和对象以及list的相关知识,其中很重要的一个知识点就是对与list迭代器的封装和实现,本篇博客整理了整个实现过程的思路,方便今后复习和其他同学参考学习

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

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

相关文章

linux性能分析(三)CPU篇(一)基础

一 CPU篇 遗留&#xff1a; 负载与cpu关系、负载与线程的关系? ① CPU 相关概念 1、physical 物理CPU个数 --> 一般一个实体 2、cpu 核数 3、逻辑CPU个数 逻辑核 4、超线程 super thread 技术 5、各种cpu的计算方式物理 physical CPU的个数&#xff1a; physical id逻…

易点易动固定资产管理系统引入RFID手持终端助力固定资产盘点

在现代商业环境中&#xff0c;固定资产盘点和管理对企业的运营至关重要。然而&#xff0c;传统的手工盘点方法已经无法满足企业对效率和准确性的要求。为了解决这一问题&#xff0c;易点易动固定资产管理系统引入RFID&#xff08;射频识别&#xff09;手持终端&#xff0c;为固…

北京卫视《为你喝彩》——星辰天合 CEO 胥昕,他专攻 SDS 让“数据常青”

10 月 18 日晚&#xff0c;北京卫视《为你喝彩》栏目播出&#xff0c;主题为《你有没有为梦想拼过命&#xff1f;听创业者说》&#xff0c;星辰天合 CEO 胥昕作为主人公之一&#xff0c;讲述了自己的创业故事。 如下内容摘自北京卫视&#xff1a; 青春总有着万般姿态&#xf…

图数据库实践 - 如何将图数据库应用于对公信贷

导读 日前&#xff0c;在经济形势和政策环境下&#xff0c;银行信贷结构进一步调整&#xff0c;民营企业、小微企业、绿色信贷投放力度持续加大。而坚持金融服务实体经济是政府的一贯主张&#xff0c;据相关工作报告指出&#xff0c;要求用好普惠小微贷款支持工具&#xff0c;…

为什么需要协调能力?如何提高协调能力?

协调能力指的是协作与调和&#xff0c;属于综合性能力的体现&#xff0c;涉及到表达&#xff0c;沟通&#xff0c;逻辑等方面&#xff0c;在日常生活中缺乏协调能力&#xff0c;也许影响并不太大&#xff0c;但是如果在职业发展中&#xff0c;协调能力就尤为重要&#xff0c;尤…

【公益案例展】广碳所——恒生电子基于区块链技术打造区域性碳中和登记系统...

‍ 恒生电子公益案例 本项目案例由恒生电子投递并参与数据猿与上海大数据联盟联合推出的 #榜样的力量# 《2023中国数据智能产业最具社会责任感企业》榜单/奖项”评选。 ‍数据智能产业创新服务媒体 ——聚焦数智 改变商业 全球气候变暖、温室效应明显、二氧化碳排放增多&#…

virtualBox虚拟机安装多个+主机访问虚拟机+虚拟机访问外网配置

目的&#xff1a;本机安装3个虚拟机 一、虚拟机安装&#xff1a;Oracle VM VirtualBox (https://www.virtualbox.org/)源代码可下载&#xff0c;且免费使用 1、https://www.virtualbox.org/ 进入网站中Download 模块选择与自己电脑系统相应的下载包下载即可 如果安装过程报错如…

京东数据分析:2023厨房小电市场遇冷,空气炸锅等明星产品被抛弃

过去几年间&#xff0c;宅经济的爆发带火了酸奶机、煮蛋器、豆浆机、空气炸锅、养生壶等&#xff0c;一众外观小巧、功能丰富、价格相对便宜的厨房小家电。但随着年轻人走出家门回归工作岗位&#xff0c;厨房小家电们却步入了艰难时刻。 如今&#xff0c;厨房小家电们似乎正在经…

论坛介绍 | COSCon'23 人工智能(A)

众多开源爱好者翘首期盼的开源盛会&#xff1a;第八届中国开源年会&#xff08;COSCon23&#xff09;将于 10月28-29日在四川成都市高新区菁蓉汇举办。本次大会的主题是&#xff1a;“开源&#xff1a;川流不息、山海相映”&#xff01;各位新老朋友们&#xff0c;欢迎到成都&a…

NET7下用WebSocket做简易聊天室

NET7下用WebSocket做简易聊天室 步骤&#xff1a; 建立NET7的MVC视图模型控制器项目创建websocket之间通信的JSON字符串对应的实体类一个房间用同一个Websocketwebsocket集合类&#xff0c;N个房间创建websocket中间件代码Program.cs中的核心代码&#xff0c;使用Websocket聊…

C语言利用已知公式估算e的近似值

编写一个函数&#xff0c;由公式e11/1&#xff01;1/2! 1/3!…&#xff0c;计算不同精确度下e的近似值。要求能够用键盘揄入指定的精确度&#xff0c;并输出该精确度下的e的近似值 例如&#xff1a;输入精确度为10e-6&#xff0c;则输出结果&#xff1a;2.718279。 #include &…

原来你根本不会找资源~

作为一名合格的传媒工作者&#xff0c;我不允许还有人不会找资源&#xff0c;下面这个四个网站必须码住&#xff0c;百分之八十的素材都来源于这些&#xff01;一、XDown【xdown.chuangzuoniu.com】 在线视频下载器&#xff0c;支持1000主流在线视频网站&#xff0c;一键下载多…

iOS原生、Android 原生, flutter 三种方式给照片流添加文字(水印)

效果图:三中代码实现的效果差不多 Swift:代码 import UIKitclass ImageWatermarking: NSObject {static func textToImage(drawText text: String, inImage initImage: UIImage, atPoint point: CGPoint) -> UIImage {let textColor = UIColor.whitelet textFont = UIFon…

如何选择一款好的护眼台灯?双十一必入护眼台灯推荐

随着科技的不断发展&#xff0c;工作时使用电子设备越来越普遍,如何保护我们的眼睛不受蓝光、频闪等危害就变得极其重要了。护眼台灯&#xff0c;顾名思义就是保护眼睛的台灯&#xff0c;其工作原理是在光源处使用特殊的防蓝光灯珠&#xff0c;并通过控制电流的稳定性来达到防频…

easyrecovery2024数据恢复软件最新版本下载

easyrecovery是PC上数据恢复领域相当给力的应用软件之一&#xff0c;它具有操作安全&#xff0c;价格便宜&#xff0c;支持用户自主操作等特点&#xff0c;能支持从各种存储介质恢复删除、格式化或者丢失的文件&#xff0c;从任何存储介质设备上的损坏&#xff0c;删除&#xf…

最简网卡驱动

在内核注册自定义的网卡驱动&#xff0c;并通过打印用户空间和内核的交互数据&#xff0c;可以更深层次的理解网络协议。 驱动代码&#xff1a; #include <linux/module.h> #include <linux/init.h> #include <linux/kernel.h> #include <linux/netdevi…

每日一题 2525. 根据规则将箱子分类 (简单)

简单题&#xff0c;直接分类就好 class Solution:def categorizeBox(self, length: int, width: int, height: int, mass: int) -> str:if length > 10**4 or width > 10**4 or height > 10**4 or length*width*height > 10**9:return "Both" if mas…

短链服务如何定制域名

短链接不仅方便推广&#xff0c;而且还能能够保护原来的落地域名&#xff0c;为落地域名提供一个屏障&#xff0c;那么短链接的自定义域名怎么绑定呢&#xff1f;接下来就为大家带来详细的绑定步骤&#xff0c;需要的伙伴可以来看看。 域名绑定步骤 首先您或您的公司团队需要拥…

易点易动:一周完成数万件固定资产管理盘点的解决方案

在现代商业环境中&#xff0c;固定资产管理盘点是企业不可或缺的重要环节。然而&#xff0c;传统的手工盘点方法往往效率低下、耗时费力&#xff0c;且容易出现错误。为了解决这一难题&#xff0c;易点易动固定资产管理系统提供了一种高效、准确的解决方案&#xff0c;使企业能…