cpp--实战项目,list的模拟实现,注释超详细!

news/2025/2/11 22:16:04/

list的模拟实现

list_3">list的模拟实现

相信大家看完我的这篇有关list使用的博客cpp–list的介绍及使用,一看就会!之后对于list类的基本使用有了一定的了解,如果大家想对于list的底层有所了解,就可以看看我这篇list的模拟实现!
在这之前我建议大家先掌握以下内容
cpp–vector的介绍及其使用,超详细,一看就会!
C++中的string类使用,看我这一篇就够了!
如果已经对上述使用有所了解,可以看看一下的模拟实现,以便对底层有所了解
cpp–vector的模拟实现,注释超详细!
cpp实战项目—string类的模拟实现

listh_11">list.h

// 防止头文件被重复包含
#pragma once// 定义命名空间 lis
namespace lis
{// 定义双向链表节点的结构体模板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, 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 temp(*this);_node = _node->_next;return temp;}// 后置自减运算符重载,先保存当前迭代器状态,再将迭代器指向前一个节点,最后返回保存的状态self operator--(int){self temp(*this);_node = _node->_prev;return temp;}// 解引用运算符重载,返回当前节点存储的数据的引用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;  // 定义常量迭代器类型// 返回指向链表第一个节点的普通迭代器iterator begin(){return _head->_next;}// 返回指向链表尾节点(哨兵节点)的普通迭代器iterator end(){return _head;}// 返回指向链表第一个节点的常量迭代器const_iterator begin() const{return _head->_next;}// 返回指向链表尾节点(哨兵节点)的常量迭代器const_iterator end() const{return _head;}// 初始化链表,创建哨兵节点,将其前后指针都指向自身,链表大小初始化为 0void empty_init(){_head = new Node;_head->_next = _head;_head->_prev = _head;_size = 0;}// 链表的默认构造函数,调用 empty_init 进行初始化list(){empty_init();}// 拷贝构造函数,先初始化链表,再遍历另一个链表,将其元素依次插入到当前链表中list(const list<T>& lt){empty_init();for (auto e : lt){push_back(e);}}// 交换两个链表的内容,包括头指针和链表大小void swap(list<T>& x){std::swap(_head, x._head);std::swap(_size, x._size);}// 赋值运算符重载,通过交换两个链表的内容实现赋值list<T>& operator=(list<T>& lt){swap(lt);return *this;}// 析构函数,先清空链表,再删除哨兵节点,最后将头指针置为 nullptr~list(){clear();delete _head;_head = nullptr;}// 清空链表,使用迭代器遍历链表,依次删除每个节点void clear(){iterator it = begin();while (it != end()){it = erase(it);}}// 删除指定位置的节点,并返回指向下一个节点的迭代器iterator erase(iterator pos){Node* cur = pos._node;  // 当前要删除的节点Node* back = cur->_next;  // 当前节点的下一个节点Node* front = cur->_prev;  // 当前节点的前一个节点back->_prev = front;  // 调整指针,跳过当前节点front->_next = back;  // 调整指针,跳过当前节点--_size;  // 链表大小减 1return iterator(back);  // 返回指向下一个节点的迭代器}// 在指定位置之前插入一个新节点,并返回指向新节点的迭代器iterator insert(iterator pos, const T& val) // 在 pos 位置之前插入 val{Node* cur = pos._node;  // 当前位置的节点Node* newnode = new Node(val);  // 创建新节点Node* front = cur->_prev;  // 当前节点的前一个节点//Node* back = cur->_next;front->_next = newnode;  // 调整指针,将新节点插入到 front 和 cur 之间newnode->_prev = front;  // 调整指针,将新节点插入到 front 和 cur 之间newnode->_next = cur;  // 调整指针,将新节点插入到 front 和 cur 之间cur->_prev = newnode;  // 调整指针,将新节点插入到 front 和 cur 之间++_size;  // 链表大小加 1return iterator(newnode);  // 返回指向新节点的迭代器}// 在链表尾部插入一个新元素,调用 insert 函数在尾节点之前插入void push_back(const T& x){insert(end(), x);}// 在链表头部插入一个新元素,调用 insert 函数在头节点之后插入void push_front(const T& x){insert(begin(), x);}// 删除链表头部的元素,调用 erase 函数删除头节点之后的节点void pop_front(){erase(begin());}// 删除链表尾部的元素,调用 erase 函数删除尾节点之前的节点void pop_back(){erase(--end());}// 返回链表的大小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()){std::cout << *it << " ";++it;}std::cout << std::endl;// 使用范围 for 循环遍历链表并输出元素for (auto e : lt){std::cout << e << " ";}}// 测试链表的拷贝构造和赋值运算符,创建链表,拷贝链表,赋值链表,分别遍历输出元素void test_list2(){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> lt1(lt);  // 拷贝构造// 遍历输出原链表的元素for (auto e : lt){std::cout << e << " ";}std::cout << std::endl;// 遍历输出拷贝链表的元素for (auto e : lt1){std::cout << e << " ";}std::cout << std::endl;list<int> lt2;lt2.push_back(10);lt2.push_back(200);lt2.push_back(30);lt2.push_back(40);lt2.push_back(50);lt1 = lt2;  // 赋值操作// 遍历输出赋值后链表的元素for (auto e : lt1){std::cout << e << " ";}std::cout << std::endl;// 遍历输出另一个链表的元素for (auto e : lt2){std::cout << e << " ";}std::cout << std::endl;}// 定义一个结构体 AA,包含两个整型成员变量struct AA{AA(int a1 = 0, int a2 = 0):_a1(a1), _a2(a2){}int _a1;  // 成员变量 a1int _a2;  // 成员变量 a2};// 测试链表存储自定义结构体的功能,插入结构体元素,使用迭代器遍历链表并输出结构体成员void test_list3(){list<AA> lt;lt.push_back(AA(1, 1));lt.push_back(AA(2, 2));lt.push_back(AA(3, 3));list<AA>::iterator it = lt.begin();while (it != lt.end()){// 使用箭头运算符输出结构体成员std::cout << it->_a1 << " " << it->_a2 << std::endl;// 显式调用箭头运算符重载函数输出结构体成员//std::cout << it.operator->()->_a1 << " " << it.operator->()->_a2 << std::endl;// 编译器会特殊处理,省略一个 -> 以提高可读性++it;}std::cout << std::endl;}// 泛型函数,用于打印容器中的元素,使用常量迭代器遍历容器并输出元素template<typename Container>void print_container(const Container& con){// 使用 typename 告诉编译器 Container::const_iterator 是一个类型typename Container::const_iterator it = con.begin();while (it != con.end()){// const 迭代器不能修改元素//*it = 1;std::cout << *it << " ";++it;}std::cout << std::endl;// 使用范围 for 循环遍历容器并输出元素/*for (auto e : con){std::cout << e << " ";}std::cout << std::endl;*/}// 测试泛型打印函数,分别使用不同类型的链表和向量容器进行测试void test_list4(){list<int> lt;lt.push_back(1);lt.push_back(2);lt.push_back(3);lt.push_back(4);lt.push_back(5);// 调用泛型打印函数打印整型链表print_container(lt);list<std::string> lt1;lt1.push_back("11111");lt1.push_back("11111");lt1.push_back("11111");lt1.push_back("11111");lt1.push_back("11111");// 调用泛型打印函数打印字符串链表print_container(lt1);std::vector<std::string> v;v.push_back("2222");v.push_back("2222");v.push_back("2222");v.push_back("2222");// 调用泛型打印函数打印字符串向量print_container(v);}// 测试链表的插入、删除、头插、头删、尾删等操作,并使用泛型打印函数输出结果void test_list5(){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();lt.erase(++it);  // 删除第二个元素lt.insert(it, 100);  // 在当前位置插入元素 100print_container(lt);  // 打印链表lt.push_front(-10);  // 在链表头部插入元素 -10print_container(lt);  // 打印链表lt.pop_front();  // 删除链表头部元素print_container(lt);  // 打印链表lt.pop_back();  // 删除链表尾部元素print_container(lt);  // 打印链表}
}

test.cpp

#include <iostream>
#include <string>
#include <vector>
#include <list>
using namespace std;
#include "list.h"
int main()
{lis::test_list4();return 0;
}

http://www.ppmy.cn/news/1571261.html

相关文章

Java爬虫获取微店店铺所有商品API接口设计与实现

一、引言 在当今的互联网时代&#xff0c;电商平台的数据对于商家、市场分析师以及消费者来说都具有巨大的价值。微店作为一个知名的电商平台&#xff0c;拥有海量的商品信息。通过爬虫技术获取微店店铺的所有商品信息&#xff0c;不仅可以帮助商家更好地了解竞争对手&#xf…

基于SpringBoot1de1宠物猫认养系统设计与实现(LW+源码+讲解)

专注于大学生项目实战开发,讲解,毕业答疑辅导&#xff0c;欢迎高校老师/同行前辈交流合作✌。 技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;…

探寻制造型企业MES管理系统:功能、架构与应用全解析

在当今制造业蓬勃发展的背景下&#xff0c;制造执行MES系统对于制造型企业的高效运营起着举足轻重的作用。MES管理系统作为连接企业上层管理与底层生产的关键桥梁&#xff0c;其功能模块设计、架构搭建、系统集成以及实际应用都对企业的生产效能和竞争力有着深远影响。 一、MES…

Oracle中与 NLS(National Language Support,国家语言支持) 相关的参数

在Oracle中&#xff0c;NLS_DATABASE_PARAMETERS 和 NLS_INSTANCE_PARAMETERS 是两个重要的视图&#xff0c;用于存储与 NLS&#xff08;National Language Support&#xff0c;国家语言支持&#xff09; 相关的参数。它们的作用和区别如下&#xff1a; 1. NLS_DATABASE_PARAME…

301.华为交换机堆叠技术基础

华为交换机堆叠技术基础 一、概念及原理部分1.堆叠简介1.1 什么是堆叠1.2 可靠性网络架构1.3 华为堆叠设备1.4 其他厂商的堆叠2.堆叠的示意图3.堆叠的应用3.1 中小企业3.2 园区网4.堆叠的原理4.1基本的概念4.2 堆叠建立4.3 角色选举4.4 版本同步4.5 配置同步4.6 堆叠系统的登录…

DeepSeek 助力 Vue 开发:打造丝滑的步骤条

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;今天给大家分享一篇文章&#xff01;并提供具体代码帮助大家深入理解&#xff0c;彻底掌握&#xff01;创作不易&#xff0c;如果能帮助到大家或者给大家一些灵感和启发&#xff0c;欢迎收藏关注哦 &#x1f495; 目录 Deep…

uniappX开发是否需要安卓调试

需要安卓调试&#xff0c; 使用web环境调试通过&#xff0c;打包安卓时出现问题。

STC 51单片机62——极简 4x4x4光立方

本次设计一个非常简洁的光立方&#xff0c;省略了限流电阻&#xff0c;用两节1.5V干电池直接驱动。 主控芯片&#xff1a;STC8H1K28&#xff0c;属于STC中比较新的系列单片机&#xff0c;管脚够用&#xff0c;也没有很多的空余。 电源直接使用带开关的电池盒&#xff0c;内含2…