当前位置: 首页 > news >正文

C++---list常用接口和模拟实现

list---模拟实现

  • list的简介
  • list函数的使用
    • 构造函数
    • 迭代器的使用
    • list的capacity
    • list element access
    • list modifiers
  • list的模拟实现
    • 构造函数,拷贝构造函数和=
    • 迭代器
    • begin和end
    • insert和erase
    • clear和析构函数
  • 源码

list的简介

list是用双向带头联表实现的一个容器,双向联表中每个元素存在互不相关的独立节点中,再节点中通过指针指向其前一个元素和后一个元素,并且可以再常数范围内再任意位置进行插入和删除的序列式容器。

list函数的使用

构造函数

构造函数( (constructor))接口说明
list (size_type n, const value_type& val = value_type())构造的list中包含n个值为val的元素
list()构造空的list
list (const list& x)拷贝构造函数
list (InputIterator first, InputIterator last)用[first, last)区间中的元素构造list
void ListTest2()
{std::list<int> a(4, 5);std::cout << "a的list" << ':';for (auto& e : a){std::cout << e << ' ';}std::cout << std::endl;std::list<int> b;//Emptystd::list<int> c(a.begin(), a.end());std::cout << "c的list" << ':';for (auto& e : c){std::cout << e << ' ';}}

在这里插入图片描述

迭代器的使用

函数声明接口说明
begin + end返回第一个元素的迭代器+返回最后一个元素下一个位置的迭代器
rbegin + rend返回第一个元素的reverse_iterator,即end位置,返回最后一个元素下一个位置的 reverse_iterator,即begin位置
	std::list<int> a(4, 5);std::cout << "a的list" << ':';std::list<int>::iterator it = a.begin();while (it != a.end()){std::cout << *it << ' ';++it;}

在这里插入图片描述

list的capacity

函数声明接口说明
empty检测list是否为空,是返回true,否则返回false
size返回list中有效节点的个数

list element access

函数声明接口说明
front返回list的第一个节点中值的引用
back返回list的最后一个节点中值的引用

list modifiers

函数声明接口说明
push_front在list首元素前插入值为val的元素
pop_front删除list中第一个元素
push_back在list尾部插入值为val的元素
pop_back删除list中最后一个元素
insert在list position 位置中插入值为val的元素
erase删除list position位置的元素
swap交换两个list中的元素
clear清空list中的有效元素

list的模拟实现

要想模拟实现list,首先我们可以定义一个节点类。为什么要定义一个节点类呢,想想数据结构中的双链表,每个元素都在独立的节点中,通过节点的前驱指针和后继指针指向前后位置。

list的模拟实现跟vector和string实现是不一样的,vector本质上是一个数组,数组本身就是一个迭代器,而list是一个个的节点,通过指针联系在一起,所以vector类不用对迭代器进行封装,可以直接使用,list不一样,节点++是什么是不清楚的,这个时候可以使用运算符重载,对++,–,*等进行重载。

	template<class T>struct list_node{list_node<T>* _next;list_node<T>* _prev;T _val;list_node(const T& val = T()):_next(nullptr),_prev(nullptr),_val(val){}};

再定义一个list类,再这个类中,完成其他函数的实现

	template<class T>class list{public:private:Node* _head;size_t _size;};

构造函数,拷贝构造函数和=

list的构造函数实现,跟双链表中的初始化是一样的,将next指针和prev指针都指向头节点,形成一个环。

		void EmptyInit(){_head = new Node();_head->_next = _head;_head->_prev = _head;_size = 0;}

拷贝构造函数再拷贝之前,要先开一个头节点的空间,然后再头节点后面依次把值进行尾插即可。

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

赋值重载=和vector里面的写法是一样的。

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

通过传参创建出一个临时变量,然后将其交换。

迭代器

要想实现list的迭代器,需要将原生态指针进行封装。

list是由一个个的节点组成,节点++,解引用,–,等操作是找不到对应的数据的,所以需要用自定义类型对指针进行封装,从而完成一系列操作。

迭代器有一个const类型的迭代器,有一个无const类型的,再实现一个无const类型的迭代器之后,把代码赋值粘贴,也可以改成带const类型的迭代器,但这样显然是代码冗余的,重复的太多,这个时候,那些大佬们就通过增加模板参数,来解决代码冗余,根据参数的类型,实列化出不同的类。

	
//typedef __list_iterator<T, T&, T*> iterator;
//typedef __list_iterator<T,const T&,const T*> const_iterator;
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){}//对节点解引用,是找不到我们存储的数据的,因为节点里面存的是val,next和prev,重载的目是使其对迭代器解引用可以找到有效数据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 *this;}bool operator !=(const self& it) const{return _node != it._node;}bool operator==(const self& it) const{return _node == it._node;}};

以上就是用自定义的类,对指针进行封装。

begin和end

对指针进行封装之后,就可以实现begin和end了。

begin只要返回头节点的下一个节点即可

end就是头节点

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

insert和erase

有一个insert,就可以完成再任意位置插入。

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

先找到当前节点cur和当前节点的上一个节点prev,再new出一个要插入的节点newnode,使得cur和newnode进行双向连接,prev和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;--_size;return next;}

clear和析构函数

		void clear(){iterator it = begin();while (it != end()){it = earse(it);}_size = 0;}~list(){}

源码

#pragma once#include <assert.h>
#include <algorithm>namespace HaiFan
{template<class T>struct list_node{list_node<T>* _next;list_node<T>* _prev;T _val;list_node(const T& val = T()):_next(nullptr),_prev(nullptr),_val(val){}};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){}T& operator*(){return _node->_val;}T* operator->(){return &(_node->val);}T& operator++(){_node = _node->_next;return *this;}T operator++(int){self tmp(*this);_node = _node->_next;return tmp;}T& operator--(){_node = _node->_prev;return *this;}T operator--(int){self tmp(*this);_node = _node->prev;return *this;}bool operator !=(const self& it) const{return _node != it._node;}bool operator==(const self& it) const{return _node == it._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;}list(){EmptyInit();}list(const list<T>& it){EmptyInit();for (auto& e : it){push_back(e);}}list<T>& operator=(list<T> it){swap(it);return *this;}void swap(list<T>& it){std::swap(_head, it._head);std::swap(_size, it._size);}void clear(){iterator it = begin();while (it != end()){it = earse(it);}_size = 0;}void push_back(const T& x){insert(end(), x);}void push_front(const T& x){insert(begin(), x);}void pop_back(){erase(--end());}void pop_front(){erase(begin());}iterator insert(iterator pos, const T& x){Node* cur = pos._node;Node* prev = cur->_prev;Node* newnode = new Node(x);prev->_next = newnode;newnode->_next = cur;newnode->_prev = prev;cur->_prev = newnode;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;--_size;return next;}size_t size(){return _size;}void EmptyInit(){_head = new Node();_head->_next = _head;_head->_prev = _head;_size = 0;}~list(){}private:Node* _head;size_t _size;};
}

相关文章:

C++---list常用接口和模拟实现

list---模拟实现 list的简介list函数的使用构造函数迭代器的使用list的capacitylist element accesslist modifiers list的模拟实现构造函数&#xff0c;拷贝构造函数和迭代器begin和endinsert和eraseclear和析构函数 源码 list的简介 list是用双向带头联表实现的一个容器&…...

[openCV]基于赛道追踪的智能车巡线方案V1

import cv2 as cv import os import numpy as npimport time# 遍历文件夹函数 def getFileList(dir, Filelist, extNone):"""获取文件夹及其子文件夹中文件列表输入 dir&#xff1a;文件夹根目录输入 ext: 扩展名返回&#xff1a; 文件路径列表""&quo…...

SpringIoc-个人学习笔记

Spring的Ioc、DI、AOP思想 Ioc Ioc思想&#xff1a;Inversion of Control&#xff0c;控制反转&#xff0c;在创建Bean的权利反转给第三方 DI DI思想&#xff1a;Dependency Injection&#xff0c;依赖注入&#xff0c;强调Bean之间的关系&#xff0c;这种关系由第三方负责去设…...

【一文搞懂泛型】

3.3泛型 3.3.1泛型出现的背景 泛型出现的背景有两点&#xff1a; 第一点是在集合容器中&#xff0c;如果没有指定对应类型的话&#xff0c;那么底层的元素就是object&#xff0c;要对容器中的元素进行存取的时候&#xff0c;取出来的同时需要进行类型转换&#xff0c;如果有…...

概念解析 | 利用MIMO雷达技术实现高性能目标检测的关键技术解析

注1:本文系“概念解析”系列之一,致力于简洁清晰地解释、辨析复杂而专业的概念。本次辨析的概念是:MIMO雷达目标检测技术 参考资料:何子述, 程子扬, 李军, 等. 集中式 MIMO 雷达研究综述[J]. 雷达学报, 2022, 11(5): 805-829. 利用MIMO雷达技术实现高性能目标检测的关键技术解…...

Grafana制作图表-自定义Flink监控图表

简要 有时候我们在官网的Grafana下载的图表是这样的&#xff0c;如下图 #算子的处理时间&#xff0c;就是处理数据的延迟数据抓取&#xff0c;这个的说明看下下面的文章 metrics.latency.interval: 60 metrics.reporter.promgateway.class: org.apache.flink.metrics.prometh…...

【TypeScript】初识TypeScript和变量类型介绍

TypeScript 1&#xff0c;TypeScript是什么?2&#xff0c;类型的缺失带来的影响3&#xff0c;Ts搭建环境-本博主有专门的文章专说明这个4&#xff0c;使用tsc对ts文件进行编译5&#xff0c;TS运行初体验简化Ts运行步骤解决方案1解决方案2&#xff08;常见&#xff09; 开始学习…...

阿里云瑶池 PolarDB 开源官网焕新升级上线

导读近日&#xff0c;阿里云开源云原生数据库 PolarDB 官方网站全新升级上线。作为 PolarDB 开源项目与开发者、生态伙伴、用户沟通的平台&#xff0c;将以开放、共享、促进交流为宗旨&#xff0c;打造开放多元的环境&#xff0c;以实现共享共赢的目标。 立即体验全新官网&…...

泡水书为什么不能再出售

近日&#xff0c;京津冀持续强降雨&#xff0c;多家出版机构位于涿州等地的图书库房受到影响。 中图网11日发文称&#xff0c;其位于涿州的仓储中心被洪水淹了&#xff0c;一库房有400多万册的书籍。 网友纷纷在文章下暖心留言&#xff1a;注意人身安全&#xff0c;泡水的书也…...

Mac 执行 .sh命令报错 command not found

使用终端执行.sh命令&#xff0c;可输入&#xff1a; ./FileName.sh如果提示 Permission denied 权限不足&#xff0c;可增加sudo&#xff0c;命令如下&#xff1a; sudo ./FileName.sh如果提示 command not found 可以这样: chmod ux *.sh sudo ./FileName.sh...

postgresql 使用之 存储架构 触摸真实数据的存储结构以及组织形式,存入数据库的数据原来在这里

存储架构 ​专栏内容&#xff1a; postgresql内核源码分析 手写数据库toadb 并发编程 个人主页&#xff1a;我的主页 座右铭&#xff1a;天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物. 概述 postgresql 数据库服务运行时&#xff0c;数据在磁…...

Node.Js安装与配置教程

目录 1.下载官网 2.选择安装路径 3.添加环境变量 4.验证是否安装成功 5.修改模块下载位置 (1)查看npm默认存放位置 6.在node.js安装目录下&#xff0c;创建两个文件夹 7.修改默认文件夹 8.测试默认位置是否更改成功 9.安装报错解决办法 10.路径未更改成功解决办法 …...

Element-Plus DatePicker获取时间戳

文章目录 0、先上答案1、渔&#xff1f;1-1 Element-Plus 官网1-2 溯源 Day.js 0、先上答案 <!-- 秒 --><el-date-pickerv-model"timeStamp"type"datetime"value-format"X"/><!-- 毫秒 --><el-date-pickerv-model"tim…...

【算法第十五天7.29】513.找树左下角的值 112. 路径总和 106.从中序与后序遍历序列构造二叉树

链接力扣513-找树左下角的值 思路 class Solution {public int findBottomLeftValue(TreeNode root) {Queue<TreeNode> queue new LinkedList<>();queue.offer(root);int res 0;while(!queue.isEmpty()){int size queue.size();for(int i 0; i < size; i)…...

Java thymeleaf bug排查记录

刚学Java 做项目时报了一个错误 一时间看的莫名其妙 EL1008E: Property or field createTime cannot be found on object of type java.util.HashMap - maybe not public or not valid? 随即向上排查至第一个报错&#xff0c;发现是thymeleaf渲染时报错。 Exception proces…...

互感和励磁电感(激磁电感)的关系

互感器&#xff0c;变压器&#xff0c;他们之间有着千丝万缕的联系&#xff0c;自感&#xff0c;互感&#xff0c;激磁电感&#xff0c;漏感、耦合系数、理想互感器、理想变压器&#xff0c;这些东西的概念理解和相互之间的关系式。都搞明白了吗&#xff1f;...

stdexcept和exception,两个头文件的区别?

stdexcept和exception是C标准库中的两个头文件&#xff0c;它们的区别如下&#xff1a; 1. 引用方式&#xff1a;stdexcept是exception的父类&#xff0c;引用时可以通过引用stdexcept来自动引用exception&#xff0c;也可以直接引用exception。 2. 异常处理&#xff1a;std…...

openCV图像的读写操作

文章目录 一、数组下标二、指针 void QuickDemo::pixel_visit_demo(cv::Mat &image) {int w image.cols;int h image.rows;int dim image.channels();for (int row 0; row < h; row){for (int col 0; col < w; col){if (dim 1)//灰度图像{int pv image.at<…...

Android平台GB28181设备接入端如何降低资源占用和性能消耗

背景 我们在做GB28181设备接入模块的时候&#xff0c;考虑到好多设备性能一般&#xff0c;我们一般的设计思路是&#xff0c;先注册设备到平台侧&#xff0c;平台侧发calalog过来&#xff0c;获取设备信息&#xff0c;然后&#xff0c;设备侧和国标平台侧维持心跳&#xff0c;…...

Android Studio安装AI编程助手Github Copilot

csdn原创谢绝转载 简介 文档链接 https://docs.github.com/en/copilot/getting-started-with-github-copilot 它是个很牛B的编程辅助工具&#xff0c;装它&#xff0c;快装它&#xff0e; 支持以下IDE: IntelliJ IDEA (Ultimate, Community, Educational)Android StudioAppC…...

MCP服务器构建指南:安全连接AI与外部工具的核心架构与实战

1. 项目概述&#xff1a;MCP服务器生态的构建者如果你最近在关注AI智能体开发&#xff0c;尤其是围绕Claude、Cursor这类工具的生态&#xff0c;那么“MCP”这个词大概率已经在你耳边出现了无数次。ViswaSrimaan/mcp_servers这个项目&#xff0c;正是这个新兴浪潮中的一个关键基…...

Ubuntu系统部署Cursor AI编辑器:从安装配置到实战优化全指南

1. 项目概述&#xff1a;在Ubuntu上快速部署Cursor AI编辑器最近在开发者圈子里&#xff0c;Cursor这款AI驱动的代码编辑器热度持续攀升。作为一个深度依赖Ubuntu进行日常开发的程序员&#xff0c;我自然也第一时间尝试了在Ubuntu 22.04 LTS上安装和配置Cursor。整个过程比预想…...

用Python从零复现混沌博弈算法(CGO):一个骰子如何玩转优化问题?

用Python从零复现混沌博弈算法&#xff08;CGO&#xff09;&#xff1a;一个骰子如何玩转优化问题&#xff1f; 混沌博弈算法&#xff08;Chaos Game Optimization, CGO&#xff09;是近年来兴起的一种新型智能优化算法&#xff0c;它将混沌理论与博弈思想巧妙结合&#xff0c;…...

卫星通信安全认证技术解析与应用实践

1. 卫星通信安全认证技术概述卫星通信作为现代通信体系的重要组成部分&#xff0c;其安全性直接关系到国家安全和经济发展。在开放的空间环境中&#xff0c;通信信号极易被截获和干扰&#xff0c;这使得安全认证技术成为卫星通信系统设计的核心环节。当前主流的卫星通信安全认证…...

SAP ECC6 2027年停服倒计时:中小企业主必看的4条务实出路与成本分析

SAP ECC6 2027年停服倒计时&#xff1a;中小企业主必看的4条务实出路与成本分析 当2027年的钟声敲响时&#xff0c;全球数十万家企业将面临一个关键抉择&#xff1a;是继续坚守已有二十年历史的SAP ECC6系统&#xff0c;还是踏上数字化转型的新征程&#xff1f;对于资源有限的中…...

终极免费MGit:在手机上管理Git仓库的完整解决方案

终极免费MGit&#xff1a;在手机上管理Git仓库的完整解决方案 【免费下载链接】MGit A Git client for Android. 项目地址: https://gitcode.com/gh_mirrors/mg/MGit 你是否曾经在通勤路上灵感迸发&#xff0c;却苦于无法立即提交代码&#xff1f;或者需要在移动设备上快…...

单卡训练mmsegmentation模型?先把这个SyncBN改成BN(附完整配置文件修改指南)

单卡训练mmsegmentation模型&#xff1f;先解决SyncBN这个关键配置 当你第一次在个人电脑或实验室的单一GPU设备上运行mmsegmentation训练脚本时&#xff0c;屏幕上突然弹出的SyncBN相关错误信息可能会让兴奋的心情瞬间跌入谷底。这个看似简单的配置问题&#xff0c;实际上反映…...

递归的终极形态:彻底搞懂尾递归优化 (TCO)

&#x1f504; 递归的终极形态&#xff1a;彻底搞懂尾递归优化 (TCO) &#x1f914; 为什么普通递归会“爆栈”&#xff1f; 在理解尾递归之前&#xff0c;先看看普通递归发生了什么。 通俗比喻&#xff1a; 想象你在玩一个“传话游戏”&#xff0c;需要计算 1 2 3 ... n…...

现有基准任务(如操纵、导航)是否足够

在人工智能与机器人技术飞速迭代的今天&#xff0c;基准任务作为衡量模型与系统能力的核心标尺&#xff0c;贯穿于技术研发、性能评估与落地应用的全流程。操纵、导航作为两类最基础、最核心的基准任务&#xff0c;长期以来支撑着机器人、具身智能等领域的进步&#xff0c;成为…...

多语言支持秘籍:validatorjs国际化错误消息配置终极指南

多语言支持秘籍&#xff1a;validatorjs国际化错误消息配置终极指南 【免费下载链接】validatorjs A data validation library in JavaScript for the browser and Node.js, inspired by Laravels Validator. 项目地址: https://gitcode.com/gh_mirrors/va/validatorjs …...