C++学习之路,从0到精通的征途:List类的模拟实现

目录

一.list的介绍

二.list的接口实现

1.结点

2.list结构

3.迭代器 

(1)begin

(2)end

 4.修改

(1)insert

(2)push_back

(3)push_front

(4)erase

(5)pop_back

(6)pop_front

(7)swap

(8)clear 

5.默认成员函数

(1)构造函数

(2)拷贝构造函数

(3)赋值重载

(4)析构函数

三.代码总览

list.h

test.cpp


 

一.list的介绍

源文档

二.list的接口实现

1.结点

template<class T>
struct list_node
{list_node* _prev;list_node* _next;T _data;// 由于数据类型由模板参数决定,所以缺省值给匿名对象list_node(const T& x = T()):_prev(nullptr),_next(nullptr),_data(x){}
};

        用一个结构体来封装结点,我们手动写默认构造函数以便在申请结点时调用。

2.list结构

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;
private:// 哨兵位Node* _head;// 有效数据个数size_t _size = 0;
};

3.迭代器 

        list的迭代器与之前的string和vector不同,由于list的数据存储空间并不是连续的,所以我们无法再继续用原生指针来实现迭代器类型,++,解引用等操作并不能实现想要达到的目的,所以我们需要重载这些操作符,并将迭代器封装成一个新的类。

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){}// 比较指向的结点是否相同bool operator!=(const Self& s){return _node != s._node;}bool operator==(const Self& s){return _node == s._node;}// Ref来控制iterator与const_iterator// Ref->T& -- iterator;// Ref->const T& -- const_iterator;// 获取结点存储的数据Ref operator*(){return _node->_data;}// 使迭代器指向下一个结点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;}// 为了可读性进行特殊处理 it->->_a1 被优化为 it->_a1// Ptr来控制iterator与const_iterator// Ptr->T* -- iterator// Ptr->const T* -- const_iteratorPtr operator->(){return &_node->_data;}
};

(1)begin

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

(2)end

iterator end()
{// 返回尾结点的下一个结点,也就是哨兵位return iterator(_head);
}
const_iterator begin() const
{return const_iterator(_head->_next);
}

 4.修改

(1)insert

void insert(iterator pos, const T& x)
{// 申请新结点的空间,调用构造Node* newnode = new Node(x);// 断开旧连接,连接新结点Node* cur = pos._node;Node* prev = cur->_prev;// prev newnode curnewnode->_prev = prev;newnode->_next = cur;prev->_next = newnode;cur->_prev = newnode;++_size;
}

(2)push_back

void push_back(const T& x)
{//Node* newnode = new Node(x);//Node* tail = _head->_prev;tail newnode _head//newnode->_prev = tail;//newnode->_next = _head;//tail->_next = newnode;//_head->_prev = newnode;insert(end(), x);
}

(3)push_front

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

(4)erase

iterator erase(iterator pos)
{Node* cur = pos._node;Node* prev = cur->_prev;Node* next = cur->_next;prev->_next = next;next->_prev = prev;delete cur;--_size;//return iterator(next);// 为防止迭代器失效,返回删除后的下一个结点的迭代器// 单参数构造函数支持隐式转换return next;
}

        为防止erase后,pos依然指向被delete的结点从而导致迭代器失效,erase返回指向下一个结点的迭代器。 

(5)pop_back

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

(6)pop_front

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

(7)swap

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

        交换哨兵位即可交换两个list。

(8)clear 

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

        除了哨兵位,其他结点逐个erase。 

5.默认成员函数

(1)构造函数

空list申请哨兵位:empty_init

// 空list申请哨兵位
void empty_init()
{_head = new Node;_head->_prev = _head;_head->_next = _head;
}// 无参数构造
list()
{//_head = new Node;//_head->_prev = _head;//_head->_next = _head;empty_init();
}// initializer_list构造
list(std::initializer_list<T> il)
{empty_init();for (auto& e : il){push_back(e);}
}

(2)拷贝构造函数

list(const list<T>& lt)
{empty_init();for (auto& e : lt){push_back(e);}
}

        先申请哨兵位,再逐个尾插即可。

(3)赋值重载

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

(4)析构函数

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

三.代码总览

list.h

#include<iostream>
#include<initializer_list>namespace my_list
{template<class T>struct list_node{list_node* _prev;list_node* _next;T _data;// 由于数据类型由模板参数决定,所以缺省值给匿名对象list_node(const T& x = T()):_prev(nullptr),_next(nullptr),_data(x){}};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){}// 比较指向的结点是否相同bool operator!=(const Self& s){return _node != s._node;}bool operator==(const Self& s){return _node == s._node;}// Ref来控制iterator与const_iterator// Ref->T& -- iterator;// Ref->const T& -- const_iterator;// 获取结点存储的数据Ref operator*(){return _node->_data;}// 使迭代器指向下一个结点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;}// 为了可读性进行特殊处理 it->->_a1 被优化为 it->_a1// Ptr来控制iterator与const_iterator// Ptr->T* -- iterator// Ptr->const T* -- const_iteratorPtr operator->(){return &_node->_data;}};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;// 空list申请哨兵位void empty_init(){_head = new Node;_head->_prev = _head;_head->_next = _head;}// 无参数构造list(){//_head = new Node;//_head->_prev = _head;//_head->_next = _head;empty_init();}// initializer_list构造list(std::initializer_list<T> il){empty_init();for (auto& e : il){push_back(e);}}list(const list<T>& lt){empty_init();for (auto& e : lt){push_back(e);}}// lt2 = lt1list<T>& operator=(list<T> lt){swap(lt);return *this;}~list(){clear();delete _head;_head = nullptr;}void clear(){auto it = begin();while (it != end()){it = erase(it);}}void swap(list<T>& lt){std::swap(_head, lt._head);std::swap(_size, lt._size);}size_t size(){return _size;}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* newnode = new Node(x);//Node* tail = _head->_prev;tail newnode _head//newnode->_prev = tail;//newnode->_next = _head;//tail->_next = newnode;//_head->_prev = newnode;insert(end(), x);}void push_front(const T& x){insert(begin(), x);}void pop_back(){erase(--end());}void pop_front(){erase(begin());}void insert(iterator pos, const T& x){// 申请新结点的空间,调用构造Node* newnode = new Node(x);// 断开旧连接,连接新结点Node* cur = pos._node;Node* prev = cur->_prev;// prev newnode curnewnode->_prev = prev;newnode->_next = cur;prev->_next = newnode;cur->_prev = newnode;++_size;}iterator erase(iterator pos){Node* cur = pos._node;Node* prev = cur->_prev;Node* next = cur->_next;prev->_next = next;next->_prev = prev;delete cur;--_size;//return iterator(next);// 为防止迭代器失效,返回删除后的下一个结点的迭代器// 单参数构造函数支持隐式转换return next;}private:// 哨兵位Node* _head;// 有效数据个数size_t _size = 0;};
}

test.cpp

#include"list.h"
using namespace std;namespace my_list
{void test_list1(){list<int> lt1;lt1.push_back(1);lt1.push_back(2);lt1.push_back(3);lt1.push_back(4);list<int>::iterator it = lt1.begin();while (it != lt1.end()){*it += 10;cout << *it << " ";++it;}cout << endl;lt1.push_back(1);lt1.push_back(2);lt1.push_front(3);lt1.push_front(4);for (auto& e : lt1){cout << e << " ";}cout << endl;lt1.pop_back();lt1.pop_front();for (auto& e : lt1){cout << e << " ";}cout << endl;cout << lt1.size() << endl;}void test_list2(){list<int> lt1;lt1.push_back(1);lt1.push_back(2);lt1.push_front(3);lt1.push_front(4);for (auto& e : lt1){cout << e << " ";}cout << endl;list<int> lt2(lt1);for (auto& e : lt1){cout << e << " ";}cout << endl;list<int> lt3;lt3 = lt1;for (auto& e : lt1){cout << e << " ";}}struct AA{int _a1;int _a2;AA(int a1 = 1, int a2 = 1):_a1(a1), _a2(a2){}};void test_list3(){list<int> lt1 = { 1,2,3,4 };for (auto& e : lt1){cout << e << " ";}cout << endl;list<AA> lt2 = { {1,1},{2,2},{3,3},{4,4} };list<AA>::iterator it = lt2.begin();while (it != lt2.end()){//cout << (*it)._a1 << ":" << (*it)._a2 << endl;//cout << it->->_a1 << ":" << it->->_a2 << endl;cout << it->_a1 << ":" << it->_a2 << endl;++it;}list<AA>::iterator lit = lt2.begin();while (lit != lt2.end()){cout << lit.operator->()->_a1 << ":" << lit.operator->()->_a2 << endl;++lit;}}
}int main()
{my_list::test_list3();return 0;
}

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

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

相关文章

【游戏ai】从强化学习开始自学游戏ai-2 使用IPPO自博弈对抗pongv3环境

文章目录 前言一、环境设计二、动作设计三、状态设计四、神经网路设计五、效果展示其他问题总结 前言 本学期的大作业&#xff0c;要求完成多智能体PPO的乒乓球对抗环境&#xff0c;这里我使用IPPO的方法来实现。 正好之前做过这个单个PPO与pong环境内置的ai对抗的训练&#…

计算机考研精炼 操作系统

第 14 章 操作系统概述 14.1 基本概念 14.1.1 操作系统的基本概念 如图 14 - 1 所示&#xff0c;操作系统是计算机系统中的一个重要组成部分&#xff0c;它位于计算机硬件和用户程序&#xff08;用户&#xff09;之间&#xff0c;负责管理计算机的硬件资源&#xff0c;为用户和…

什么是基尔霍夫第一定律

基尔霍夫第一定律&#xff08;Kirchhoffs First Law&#xff09;&#xff0c;也称为基尔霍夫电流定律&#xff08;Kirchhoffs Current Law&#xff0c;简称 KCL&#xff09;&#xff0c;是电路分析中最基础的定律之一。它描述了电路中电流的守恒特性&#xff0c;适用于任何集总…

解决 RN Switch 组件在安卓端样式很丑的问题

解决此种问题的方式有很多 可以导入原生库react-native-switch 切图 (会缺少动画) 使用 js 组件 这里使用 js 绘制组件&#xff08;原生体验&#xff09;解决此类问题 Switch.tsx import React, { useEffect, useRef, useState } from react; import { Animated, Pressabl…

【AI】【MCP】搭建私人王炸MCP自动化工作流

目录 一、什么是MCP 二、MCP大集合 三、准备工作 3.1 安装node.js 3.2 安装vscode 3.3 安装cline插件 3.3.1 安装 3.3.2 配置Cline 四、配置MCP服务 4.1 Search-mcp服务 4.2 playwright-mcp 服务 前言&#xff1a;梦想组合&#xff0c;轻松办公&#xff0c;告别手动&a…

Git 实操:如何使用交互式 Rebase 移除指定提交(真实案例分享)

在日常开发中&#xff0c;有时候我们提交了一些不想保留的记录&#xff0c;比如测试代码、错误的功能提交等。 ⚠️ 在操作 4. 强制推送到远程仓库前的注意事项 强制推送&#xff08;git push --force 或 git push -f&#xff09;确实很强大但也危险&#xff0c;因为它会重写…

11.Excel:函数

一 函数是什么 函数是定义好的公式。 单元格内输入sum然后tab&#xff0c;框选要求和的范围&#xff0c;然后回车键。 补充&#xff1a;公式。 公式以开头&#xff0c;可以用于计算&#xff0c;返回数值。 分别点击各个数值&#xff0c;中间用加号连接。这样很不方便&#xff…

Springboot使用ThreadLocal提供线程局部变量,传递登录用户名

文章目录 概述使用创建ThreadLocalUtil工具类在登录拦截器中使用ThreadLocal存储登录用户名在/userInfo接口中获取登录用户名 注意事项参考视频 概述 使用 创建ThreadLocalUtil工具类 utils/ThreadLocalUtil.java package org.example.utils;/*** ThreadLocal 工具类*/ Supp…

1399. 统计最大组的数目

1399. 统计最大组的数目 题目链接&#xff1a;1399. 统计最大组的数目 代码如下&#xff1a; class Solution { public:int countLargestGroup(int n) {int res 0;unordered_map<int, int> um;int maxValue 0;for (int i 1;i < n;i) {string value to_string(i);…

VS Code 插件Git History Diff 使用

右上角 查看单个文件记录

数学建模论文手的学习日常01

目录 一.要写的内容&#xff1a; 二.文章标题&#xff1a; 三.摘要&#xff08;非常非常非常重要&#xff09; 四、关键词&#xff1a; 五、问题重述 六、模型假设 七、符号说明 八、模型的建立与求解 九、模型的分析与检验 十、模型的评价、改进与推广 十一、参考…

深度学习: AI 体育领域

一、引言 在科技与体育深度融合的当下&#xff0c;AI 体育逐渐成为推动体育行业变革的重要力量。深度学习凭借其强大的数据分析与模式识别能力&#xff0c;为 AI 体育带来了全新的发展机遇。从运动员动作分析到智能健身指导&#xff0c;从赛事预测到运动康复辅助&#xff0c;深…

在 Ubuntu24.04 LTS 上 Docker 部署英文版 n8n 和 部署中文版 n8n-i18n-chinese

一、n8n 简介 n8n 是一个低代码&#xff08;Low-Code&#xff09;工作流自动化平台&#xff0c;可以帮助用户以非常简单的方式创建自动化流程&#xff0c;连接不同的应用程序和服务。n8n的设计理念是为了让复杂的工作流变得简单易用&#xff0c;同时也支持高度的自定义&#xf…

《系统分析师-第三阶段—总结(八)》

背景 采用三遍读书法进行阅读&#xff0c;此阶段是第三遍。 过程 本篇总结第15章的内容 第15章 总结 系统运行与维护&#xff0c;系统经过测试交付之后&#xff0c;进入运行维护阶段&#xff0c;维护分为系统运行、故障维护、系统评价和系统相关的策略。 疑问&#xff1a;…

LeetCode 1295.统计位数为偶数的数字:模拟

【LetMeFly】1295.统计位数为偶数的数字&#xff1a;模拟 力扣题目链接&#xff1a;https://leetcode.cn/problems/find-numbers-with-even-number-of-digits/ 给你一个整数数组 nums&#xff0c;请你返回其中位数为 偶数 的数字的个数。 示例 1&#xff1a; 输入&#xff1…

DDD是什么?电商系统举例

一、DDD的基本概念 领域驱动设计&#xff08;Domain-Driven Design&#xff0c;简称DDD&#xff09;是由Eric Evans提出的一种软件开发方法论&#xff0c;旨在应对复杂业务系统的设计和实现。它的核心思想是将软件的设计与业务领域紧密结合&#xff0c;通过深入理解业务需求&a…

K8S ConfigMap 快速开始

一、什么是 ConfigMap&#xff1f; ConfigMap 是 Kubernetes 中用于存储非敏感配置数据的 API 对象&#xff0c;支持以键值对&#xff08;Key-Value&#xff09;或文件的形式存储配置&#xff0c;允许将配置与镜像解耦&#xff0c;实现配置的集中管理和动态更新。 二、主要用…

Prometheus使用Recoding Rules优化性能

通过PromQL可以实时对Prometheus中采集到的样本数据进行查询&#xff0c;聚合以及其它各种运算操作。而在某些PromQL较为复杂且计算量较大时&#xff0c;直接使用PromQL可能会导致Prometheus响应超时的情况。这时需要一种能够类似于后台批处理的机制能够在后台完成这些复杂运算…

C++ RAII 编程范式详解

C RAII 编程范式详解 一、RAII 核心概念 RAII&#xff08;Resource Acquisition Is Initialization&#xff0c;资源获取即初始化&#xff09; 是 C 的核心编程范式&#xff0c;通过将资源生命周期与对象生命周期绑定实现安全、自动化的资源管理。 核心原则&#xff1a; 资源…

Rust 学习笔记:枚举与模式匹配

Rust 学习笔记&#xff1a;枚举与模式匹配 Rust 学习笔记&#xff1a;枚举与模式匹配定义枚举&#xff08;Enum&#xff09;枚举变量Option 枚举及其相对于 NULL 的优势match 和枚举与 Option\<T\> 匹配match 应该是详尽的Catch-all 模式和 _ 占位符使用 if let 和 let e…