C++ list容器的底层实现

一.list是什么

  list 是 C++容器中的带头双向链表,头结点不存储数据,头结点的下一个元素是第一个存储数据的元素,头结点的前一个元素连接着最后一个存储数据的元素。(结构如下图所示)

 其中链表里每一个节点的结构分为,数据部分,前指针和后指针构成(下面是结构图和代码)

二.list 代码实现和语法解析

2.1 定义结点的结构

链表中的数据和前后指针的类型都是模板生成的,可以适配内置类型和自定义类型。这里用struct来定义类的原因是struct默认的成员变量类型都是public,其他函数可以很方便的进行调用。在这里还有一个list_node的构造函数 T()是一个匿名变量,其作用不止是用于存放数据,此外如果调用list_node构造函数时没有写参数的话,这里也会有一个默认的值。

 2.2 定义链表的结构

 在list中,有两个成员变量的存在一个是节点类型的指针_node 和计算节点数量的_size。

template<class T>
class list
{
typedef list_node<T> Node;
void empty_init()
{_head = new Node;_head -> next = _head;_head -> prev = _head;_size = 0;
}
list()
{empty_init();
}private:Node* _node;size_t _size;
}

2.3 添加链表功能(插入 push_back)

 我们已经定义好了list的基础结构,下面我们就要添加一些基本的功能了,例如往list中插入数据,用迭代器来遍历list链表之类的操作。

Push_back 函数:首先构建一个新的节点newnode,然后把需要存放的数据X存到newnode中,找到尾结点并且将newnode插入到尾节点的下一个节点。

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 list
{
typedef list_node<T> Node;
void empty_init()
{_head = new Node;_head -> next = _head;_head -> prev = _head;_size = 0;
}
list()
{empty_init();
}
void push_back(const T& x)
{Node* newnode = new Node(x);Node* tail = _head->prev;tail->_next = newnode;newnode->prev = tail;newnode->_next = _head;_head->prev = newnode;_size++; 
}private:Node* _node;size_t _size;
}

2.4 添加链表功能(迭代器和迭代器的运算符重载)

和顺序表不同,因为链表的节点不是存放在一起的连续空间,所以指针的++和解引用都没有办法直接的获取到数据,因此在这里我们需要自己去重载 *  ->  ++ --等等的运算符。

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>
struct __list_iterator
{typedef list_node<T> Node;typedef __list_iterator self;Node* _node;__list_iterator(Node* node):_node(node){}T& operator *(Node * node){return _node->_data;}T* operator(Node * node){return &_node->_data;}self& operator++(){_node = _node->next;return *this;}self& operator--(){_node = _node->prev;return *this;}bool operator!=(const self& s){return _node != s._node;}
}template<class T>
class list
{
typedef list_node<T> Node;
typedef __list_iterator<T> iterator;iterator begin()
{return iterator(_head->next);
}iterator end()
{return iterator(_head);
}void empty_init()
{_head = new Node;_head -> next = _head;_head -> prev = _head;_size = 0;
}list()
{empty_init();
}void push_back(const T& x)
{Node* newnode = new Node(x);Node* tail = _head->prev;tail->_next = newnode;newnode->prev = tail;newnode->_next = _head;_head->prev = newnode;_size++; 
}private:Node* _node;size_t _size;
}

做完了以上的操作以后,我们就可以这样来调试程序了,虽然List并不是数组,但是我们可以用相似的方式来对List内部的元素进行访问。虽然迭代器迭代容器各个元素的方式是一样的,但是迭代器屏蔽了底层实现的细节,提供了统一访问的方式

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

2.5 添加链表功能(插入操作的升级 insert()和 eraser()删除)

首先我们可以写一个 insert()插入的函数,这个函数可以被其他的函数所复用例如push_back和push_front ,也可以在任意的位置插入数据。

iterator insert(iterator pos , const T& x)
{Node* newnode = new Node(x);Node* cur = pos._node;Node* prev = cur ->_prev;prev->_next = newnode;newnode->_prev = prev;newnode->_next = cur;cur->_prev = newnode;return newnode; 
}iterator erase(iterator pos)
{Node* cur = pos._node;Node* prev = cur->_prev;Node* next = cur->_next;delete cur;prev->_next = next;next->_prev = prev;return next;
}void push_back(const T& x)
{insert(this.end(),x);
}void push_front(const T& x)
{insert(begin(),x);
}void pop_back()
{erase(--end());
}void pop_front()
{erase(begin());
}

2.6 添加链表功能(clear函数和析构函数)

因为erase函数的返回值是被删除数据的下一个位置,所以这里不写++ 也会有++的效果。

~list()
{clear();delete _head;_head = nullpre;
}void clear()
{iterator it = begin();while(it != end()){it = erase(*it);}
}    

2.7 添加链表功能(拷贝构造和赋值重载)

(1)拷贝构造

list( list<int> lt )
{empty_init();for(auto e : lt){this.push_back(e);}
}

(2)赋值重载

		void swap(list<T>& lt){std::swap(_head, lt._head);std::swap(_size, lt._size);}list<int>& operator=(list<int> lt){swap(lt);return *this;}

2.8 const 类型的迭代器

对于const类型的迭代器,我们需要了解,const 类型的迭代器不可以修改迭代器所指向的数据,而不是迭代器本身不可修改,迭代器本身需要完成++,--等操作进行遍历操作,所以在写const类型的迭代器时,我只对迭代器返回指向的内容的函数进行const修饰即可,其余函数均不改变。

template<class T>
struct __list_const_iterator
{typedef list_node<T> Node;typedef __list_const_iterator<T> self;Node* _node;__list_const_iterator(Node* node):_node(node){}const T& operator *(){return _node->_data;}const T* operator->(){return &_node->_data;}
};

三.完整代码

#pragma once
#include<iostream>
using namespace std;
namespace hjy
{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 tmp(*this);_node = _node->_next;return tmp;}self operator --(int){self tmp(*this);_node = _node->_prev;return tmp;}Ref operator *(){return _node->_data;}Ptr operator->(){return &_node->_data;}bool operator!=(const self& s){return _node != s._node;}};/*template<class T>struct __list_const_iterator{typedef list_node<T> Node;typedef __list_const_iterator<T> self;Node* _node;__list_const_iterator(Node* node):_node(node){}self& operator ++(){_node = _node->_next;return *this;}self& operator --(){_node = _node->_prev;return *this;}self operator ++(int){self tmp(*this);_node = _node->_next;return tmp;}self operator --(int){self tmp(*this);_node = _node->_prev;return tmp;}const T& operator *(){return _node->_data;}const T* operator->(){return &_node->_data;}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;//typedef __list_const_iterator<T> const_iterator;const_iterator begin()const{return const_iterator(_head->_next);}const_iterator end()const{return const_iterator(_head);}iterator begin(){return _head->_next;}iterator end(){return _head;}void empty_init(){_head = new Node;_head->_next = _head;_head->_prev = _head;_size = 0;}list(){empty_init();}//list<int>& operator=(const list<int>& lt) 传统写法//{//	if (this != &lt)//		clear();//	for (auto e : lt)//	{//		push_back(e);//	}//	return *this;//}void swap(list<T>& lt){std::swap(_head, lt._head);std::swap(_size, lt._size);}list<int>& operator=(list<int> lt){swap(lt);return *this;}~list(){clear();delete _head;_head = nullptr;}//list(const list<T>& lt)//没有const迭代器所以这样写不行//{//	empty_init();//	for (auto e : lt)//	{//		push_back(e);//	}//}list( list<T>& lt){empty_init();for (auto e : lt){push_back(e);}}void push_back(const T& x){insert(end(), x);}void push_front(const T& x){insert(begin(), x);}void pop_front(){erase(begin());}void pop_back(){erase(end()--);}void clear(){iterator it = begin();while (it != end()){it = erase(it);}}iterator insert(iterator pos, const T& val){Node* cur = pos._node;Node* newnode = new Node(val);Node* prev = cur->_prev;prev->_next = newnode;newnode->_prev = prev;newnode->_next = cur;cur->_prev = newnode;++_size;return iterator(newnode);}iterator erase(iterator pos){Node* cur = pos._node;Node* prev = cur->_prev;Node* next = cur->_next;delete cur;prev->_next = next;next->_prev = prev;--_size;return iterator(next);}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);for (auto e : lt)cout << e << " ";cout << endl;list<int>lt1 = lt;for (auto e : lt1)cout << e << " ";cout << endl;}/*void print_list(const list<int>& lt){list<int>::const_iterator it = lt.begin();while (it != lt.end()){cout << *it << " ";++it;}cout << endl;for (auto e : lt){cout << e << " ";}cout << endl;}*/template<typename T>void print_list(const list<T>& lt){typename list<T>::const_iterator it = lt.begin();while (it != lt.end()){cout << *it << " ";++it;}cout << endl;}void test_list2(){list<string>lt;lt.push_back("111");lt.push_back("111");lt.push_back("111");print_list(lt);}
}

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

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

相关文章

PyQt5开发笔记:2. 2D与3D散点图、水平布局和边框修饰

一、装pyqtgraph和PyOpenGL库 pip install pyqtgraph pip install PyOpenGL 注意&#xff1a;一定不要pip install OpenGL&#xff0c;否则会找不到 二、3D散点图效果 import pyqtgraph as pg import pyqtgraph.opengl as gl import numpy as np# 创建应用程序 app pg.mkQ…

【计算机组成原理 | 第二篇】计算机硬件架构的发展

目录 前言&#xff1a; 冯诺依曼计算机架构 现代计算机架构&#xff1a; 总结&#xff1a; 前言&#xff1a; 在当今数字化时代&#xff0c;计算机硬件不仅是技术进步的见证者&#xff0c;更是推动这一进步的基石。它们构成了我们日常生活中不可或缺的数字生态系统的核心&a…

数据失踪了?小米手机数据恢复并不难,3个方法就能搞定

手机数据就如同我们的“数字生命线”&#xff0c;一旦失去&#xff0c;便仿佛陷入了一片数据的荒漠&#xff0c;感到无助与迷茫。小米手机用户们&#xff0c;你是否曾遭遇过这样的困境&#xff1a;打开手机&#xff0c;却发现重要的照片、联系人、短信等数据不见了&#xff0c;…

Flutter和React Native(RN)的比较

Flutter和React Native&#xff08;RN&#xff09;都是用于构建跨平台移动应用程序的流行框架。两者都具有各自的优势和劣势&#xff0c;选择哪个框架取决于您的具体需求和项目。北京木奇移动技术有限公司&#xff0c;专业的软件外包开发公司&#xff0c;欢迎交流合作。 以下是…

乐财业:打造财税服务的“硬核“竞争力

乐财业 智慧财税赋能平台 乐财业是目前市面上唯一一家真正实现“业财税”"三位一体全面融合的综合赋能平台&#xff0c;全新打造一站式、流程化、生态化的全产品供应链&#xff0c;立足于企业“业财"融合的发展趋势&#xff0c;凭借20年的财税服务经验&#xff0c;站…

CoreDump使用与实现原理

一、背景 系统发生native crash时&#xff0c;针对内存异常访问、内存踩踏等疑难问题&#xff0c;由于tombstone信息量不足无法精确定位分析这类问题。 二、coredump介绍 2.1 什么是coredump 当用户程序运行过程中发生异常, 程序异常退出时, 由Linux内核把程序当前的内存状…

ss工具dump出vsock 端口号异常分析

端口冲突时&#xff0c;会出现bind fail异常&#xff0c;这时可以用ss --vsock -pl命令dump出所有listen状态的vsock,但实际发现传入的9000端口&#xff0c;dump出来却是10275&#xff0c;如下图&#xff1a; 难道是内核把端口改了&#xff1f;分析内核态源码&#xff0c;ss最终…

模拟器大揭秘:功能多样,热门APP一网打尽

在咱们日常的数字生活中&#xff0c;模拟器这个词儿你可能不陌生&#xff0c;但它到底能干啥&#xff1f;又有哪些好用的模拟器APP呢&#xff1f; 今天&#xff0c;咱们就来聊聊模拟器的功能&#xff0c;并推荐几款热门的模拟器APP&#xff0c;帮助大家更好地利用这一技术。 …

Math/System/Runtime/Object

1、Math &#xff08;1&#xff09;常用方法 类型方法名说明public static intabs (int a)返回整数的绝对值public static doublepow (double a,double b)计算a的b次幂的值public static int max (int a,int b) 获取两个int值中的较大值public static intmin (int a,int…

java读取配置文件(包含国家于二字码对应关系文件)

读取配置文件 1.java文件 import com.google.common.collect.Maps; import lombok.extern.slf4j.Slf4j; import org.springframework.core.io.ClassPathResource;import java.io.BufferedReader; import java.io.InputStreamReader; import java.util.Map; Slf4j public class…

数据结构笔记之连通图与强连通图

一、引言 在图论中&#xff0c;我们常常会遇到连通图和强连通图的概念。它们描述了图中顶点之间的连接情况&#xff0c;对于理解和分析复杂网络具有重要意义。 二、连通图 定义&#xff1a;若图G中任意两个顶点都是连通的&#xff0c;则称图G为连通图&#xff1b;否则称为非…

如何使用可道云结合内网穿透工具实现远程访问打造私人云盘

文章目录 1.前言2. Kodcloud网站搭建2.1. Kodcloud下载和安装2.2 Kodcloud网页测试 3. cpolar内网穿透的安装和注册4. 本地网页发布4.1 Cpolar云端设置4.2 Cpolar本地设置 5. 公网访问测试6.结语 &#x1f4a1; 推荐 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易…

【HTML入门】第十课 - 表格,也就是table标签

这一小节&#xff0c;我们说一下HTML中的表格。比如我们常常看见的学生成绩单&#xff0c;比如excel一个单元格一个单元格的&#xff0c;这些都是表格。 表格的标签名是 table 。 目录 1 表格中的一些子标签 1.1 表头区域 1.2 表格内容区域 1.3 行和列 2 实战一小下 2.…

JavaWeb(一:基础知识和环境搭建)

一、基本概念 1.前言 JavaWeb&#xff1a;在Java中&#xff0c;动态web资源开发网页的技术。 web应用分两种&#xff1a;静态web资源和动态web资源 Ⅰ. 静态web资源&#xff08;如html 页面&#xff09;&#xff1a; 指web页面中的数据始终是不变。 所有用户看到都是同一个…

python编程实例 输出两个数之间的素数

#输出两个数之间有多少素数 import math mint(input("开始&#xff1a;")) nint(input("结束&#xff1a;")) for i in range(m,n1):for j in range(2,int(math.sqrt(i))1):if i%j0:breakif(jint(math.sqrt(i))):print(str(i),"是一个素数")

DP(2) | Java | LeetCode 62, 63, 343, 96 做题总结(96 未完)

62.不同路径 我的代码&#xff08;报错&#xff09; 写的过程中感到很迷惑的点&#xff1a;①二维数组和这道题目的对应弄不清除&#xff0c;m n的初始化 是 dp[m][n] 还是 dp[n][m] ② class Solution {public int uniquePaths(int m, int n) {int[][]dp new int[m1][n1];d…

单目3D和bev综述

文章目录 SOTA2D 检测单目3d检测单目bev&#xff0c;一般是多目&#xff0c;小鹅通3d bev cam范式Transformer attention is all you need 2017ViT vision transformer ICLR 2021googleDETR 2020DETR3D 2021PETR 2022bevformerLSSbevdetcaddn指标 mAP NDS标注&#xff1a;基于点…

利用js实现图片压缩功能

图片压缩在众多应用场景中扮演着至关重要的角色&#xff0c;尤其是在客户端上传图片时。原始图片往往体积庞大&#xff0c;直接上传不仅消耗大量带宽资源&#xff0c;还可能导致上传速度缓慢&#xff0c;严重影响用户体验。因此&#xff0c;在图片上传至服务器前对其进行压缩处…

嵌入式开发过程中,常见报错以及解决方法

编写不易&#xff0c;仅供学习&#xff0c;参考谢谢&#xff0c;还望理解。 #常见报错 文件最后一行没有新行 翻译&#xff1a;文件的最后一行结束时没有新行 解决方法&#xff1a;定位到&#xff0c;提示报错的 .h 文件 报错行 &#xff0c;加上一个新行 函数定义时与官方提…

网信大数据信用报告查询怎么查?网信大数据有什么作用?

随着互联网的快速发展&#xff0c;大数据技术已经广泛应用于各行各业。其中&#xff0c;网信大数据信用报告查询成为了许多人关注的焦点。那么&#xff0c;如何查询网信大数据信用报告呢?网信大数据又有哪些作用呢?本文将为您一一解答。 一、如何查询网信大数据信用报告? 要…