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

文章目录

  • 前言
  • 一、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.mzph.cn/web/53780.shtml

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

相关文章

影响6个时序Baselines模型的代码Bug

前言 我是从去年年底开始入门时间序列研究&#xff0c;但直到最近我读FITS这篇文章的代码时&#xff0c;才发现从去年12月25号就有人发现了数个时间序列Baseline的代码Bug。如果你已经知道这个Bug了&#xff0c;那可以忽略本文&#xff5e; 这个错误最初在Informer&#xff0…

web入门

什么是spring 特点&#xff1a;配置繁琐&#xff0c;入门难度大&#xff0c;提出了springboot 1.springbootweb入门例子 2.http协议 2.1概述 2.2请求协议 由三部分组成&#xff1a;请求行、请求头、请求体 2.3响应协议 2.4协议解析

云桌面+数字人:开启直播新纪元

随着科技的飞速发展&#xff0c;直播行业也在不断变革。云桌面和数字人直播作为新兴力量&#xff0c;正逐渐崭露头角&#xff0c;受到了广泛关注。 云桌面技术的出现&#xff0c;为直播带来了全新的可能性。它不再依赖传统的本地硬件设备&#xff0c;而是通过云计算提供弹性可…

我与Linux的爱恋:命令行参数|环境变量

​ ​ &#x1f525;个人主页&#xff1a;guoguoqiang. &#x1f525;专栏&#xff1a;Linux的学习 文章目录 一.命令行参数二.环境变量1.环境变量的基本概念2.查看环境变量的方法3.环境变量相关命令4.环境变量的组织方式以及获取环境变量的三种方法 环境变量具有全局属性 一…

C++map与set

文章目录 前言一、map和set基础知识二、set与map使用示例1.set去重操作2.map字典统计 总结 前言 本章主要介绍map和set的基本知识与用法。 一、map和set基础知识 map与set属于STL的一部分&#xff0c;他们底层都是是同红黑树来实现的。 ①set常见用途是去重 &#xff0c;set不…

数据技术进化史:从数据仓库到数据中台再到数据飞轮的旅程

随着大数据时代的到来&#xff0c;数据已经成为企业的核心资产之一。在过去几十年间&#xff0c;数据技术也随之不断演进&#xff0c;从早期的数据仓库到近年来热门的数据中台&#xff0c;再到正在快速发展的数据飞轮概念&#xff0c;每一步都是技术革新的体现。 一、数据仓库&…

电商跨境电商商城系统/网上商城接口/电商数据接口详情

电商API接口背景&#xff1a;电商运营中&#xff0c;数据分析这项工作越来越重要&#xff0c;许多品牌方也越来越热衷去做电商数据分析。不过&#xff0c;全面的数据该如何获取呢&#xff0c;此时&#xff0c;电商数据接口的重要性便凸显出来了。 电商API数据接口主要有以下特…

外包干了两年,收获真不少...

有一种打工人的羡慕&#xff0c;叫做“大厂”。 真是年少不知大厂香&#xff0c;错把青春插稻秧。 但是&#xff0c;在深圳有一群比大厂员工更庞大的群体&#xff0c;他们顶着大厂的“名”&#xff0c;做着大厂的工作&#xff0c;还可以享受大厂的伙食&#xff0c;却没有大厂…

深度伪造语音检测(Deepfake Speech Detection, DSD)全面概述

近期&#xff0c;深度学习技术和神经网络在生成型人工智能领域已取得重大突破。如今&#xff0c;关键的通信媒介&#xff0c;如音频、图像、视频和文本&#xff0c;均能实现自动生成&#xff0c;并广泛应用于诸多领域&#xff0c;包括聊天机器人系统&#xff08;如ChatGPT&…

Kettle9连接mysql8.0.36失败处理

一、问题描述 kettle作为数据转换同步的工具&#xff0c;使用java开发&#xff0c;连接数据库使用jar的驱动包&#xff0c;比如oracle连接使用ojdbc8.jar&#xff0c;mysql连接使用mysql-connect-java-8.0.*,但是截止目前mysql8.0.33到8.0.36在官网是没有mysql驱动包的&#x…

IPD如何解决产品开发的典型问题

IPD&#xff08;Integrated Product Development&#xff0c;集成产品开发&#xff09;是一种领先的、成熟的产品开发的管理思想和管理模式。它是根据大量成功的产品开发管理实践总结出来的&#xff0c;并被大量实践证明的高效的产品开发模式。从汉捷咨询二十多年来为五百多家企…

18724 二叉树的遍历运算

### 思路 1. **递归构建树**&#xff1a; - 先序遍历的第一个节点是根节点。 - 在中序遍历中找到根节点的位置&#xff0c;左边部分是左子树&#xff0c;右边部分是右子树。 - 递归构建左子树和右子树。 2. **递归生成后序遍历**&#xff1a; - 递归生成左子树的…

飞睿智能实时雷达活体探测传感器模块,智能家居静止检测实时感知人员有无

随着科技的飞速发展&#xff0c;我们的生活正在经历着未有的创新。在这个创新的浪潮中&#xff0c;实时雷达活体探测传感器模块的技术正逐渐崭露头角&#xff0c;以其独特的优势为我们的生活带来安全与便捷。今天&#xff0c;我们就来详细探讨一下这项技术&#xff0c;看看它是…

【DP解密多重背包问题】:优化策略与实现

文章目录 什么是多重背包问题&#xff1f;多重背包问题的数学模型 例题多重背包问题Ⅰ多重背包问题Ⅱ 总结 什么是多重背包问题&#xff1f; 多重背包问题是一个经典的组合优化问题。与标准背包问题不同&#xff0c;在多重背包问题中&#xff0c;每种物品可以选择多个&#xf…

蓝桥杯15届C/C++B组省赛题目

问题描述 小蓝组织了一场算法交流会议&#xff0c;总共有 5050 人参加了本次会议。在会议上&#xff0c;大家进行了握手交流。按照惯例他们每个人都要与除自己以外的其他所有人进行一次握手 (且仅有一次)。但有 77 个人&#xff0c;这 77 人彼此之间没有进行握手 (但这 77 人与…

langchain v0.3更新了什么?

版本改动 这是具体改动的链接 官方blog首先说明了&#xff1a; 所有软件包已在内部从 Pydantic 1 升级到 Pydantic 2。 所有软件包都完全支持在用户代码中使用 Pydantic 2&#xff0c;而无需使用 langchain_core.pydantic_v1 或 pydantic.v1 等桥接程序。 由于 Pydantic 1 已…

【HTTP】请求“报头”(Host、Content-Length/Content-Type、User-Agent(简称 UA))

Host 表示服务器主机的地址和端口号 URL 里面不是已经有 Host 了吗&#xff0c;为什么还要写一次&#xff1f; 这里的 Host 和 URL 中的 IP 地址、端口什么的&#xff0c;绝大部分情况下是一样的&#xff0c;少数情况下可能不同当前我们经过某个代理进行转发。过程中&#xf…

2024年项目经理不能错过的开源项目管理系统大盘点:全面指南

在2024年&#xff0c;随着项目管理领域的不断发展&#xff0c;开源项目管理系统成为了项目经理们提升工作效率的利器。本文将全面盘点几款备受推荐的开源项目管理系统&#xff0c;帮助项目经理们找到最佳选择&#xff0c;不容错过。 在项目管理日益复杂的今天&#xff0c;开源项…

腾讯云点播及声音上传

文章目录 1、开通腾讯云点播2、获取腾讯云API密钥3、完成声音上传3.1、引入依赖3.2、参考&#xff1a;接入点地域3.3、参考&#xff1a;任务流设置3.4、首先修改配置&#xff1a;3.4.1、 3.5、TrackInfoApiController --》 uploadTrack()3.6、VodServiceImpl --》 uploadTrack(…

SOLIDWORKS Flow Simulation对几何模型都有哪些要求?

SOLIDWORKS Flow Simulation 是一款集设计与仿真于一体的流体仿真软件&#xff08;EFD&#xff0c;CFD&#xff09;&#xff0c;以其操作简便、建模快捷和快速收敛等优点&#xff0c;深受广大初学者的喜爱。 在模型建立方面&#xff0c;Flow Simulation 能够直接利用 SOLIDWOR…