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

植物大战 List——C++

这里写目录标题

  • vector和stirng的细节
    • 对于string
  • list的使用
    • list的迭代器
    • 反向迭代器
    • 构造函数
    • 关于list::sort的排序
    • unique
  • list的底层模拟实现
    • 结点类的实现
    • 迭代器模拟实现
    • list实现
  • 插入的实现
  • 迭代器失效
    • insert
    • erase
  • 析构函数
  • 拷贝构造
  • 赋值构造函数

vector和stirng的细节

复习vector的深浅拷贝。

下图是vector<vector< int>> 的底层模型
在这里插入图片描述实际和动态二维数组的图一样。

vv[i][j] 表示什么意思?
vv[ i]表示访问第几个vector,
vv[i][ j]表示访问第i个vector的第j个下表的元素。

对于string

class string
{
private:char _buf[16];char* _ptr;size_t _size;size_t _capacity;
}

string设计如下,string在设计时用了一个buf的数组,buf大小是16,最后一个空间是给\0的。

这样设计的目的是小于16byte的字符串,存在buf数组中。大于等于16的字符串存在_ptr指向的空间。

list的使用

概念:list是一个容器,允许在常数O(1)时间,在任意位置进行insert和erase。他的迭代器是双向的

链表在使用上和vector和string差不多。

因为支持O(1)的时间,所以它是双向循环链表的数据结构。

如图

对于迭代器的位置,begin()是第一个元素的位置,end()是最后一个元素的下一个位置,也就是哨兵位头结点。

在这里插入图片描述

list的迭代器

对于list为什么要学迭代器?
对于string和vector来说,使用的是原生指针,所以迭代器是原生的,对于list,我们也要封装迭代器,因为list底层是地址,不是连续的地址。为了方便用户操作,比如for循环遍历,范围for等。

小细节:因为list的结构,所以while循环内不能用小于<,因为都是地址,地址不能比大小,迭代器的条件都是不等于!=

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

反向迭代器

rbegin()就是最后一个元素的下一个位置。

在这里插入图片描述

auto rit = lt.rbegin();while (rit != lt.rend()){cout << *rit << " ";++rit;}

构造函数

四个:无参的构造,n个value的构造,迭代器区间构造,拷贝构造。

和vector非常相似不说,查文档。

关于list::sort的排序

如果大量的排序不建议用list自带的。可以用vector进行排序。
对于std算法库里面的sort,需要传随机迭代器才可以使用。

但是list不支持随机访问,list的迭代器是双向迭代器。

list lt;
lt.sort();

对于迭代器实际上分为三类。
1.单向。++ forward_list
2.双向。致辞 ++ – list
3.随机。支持++ – + - vector

所以要求传双向迭代器的,也可以传随机迭代器。

总结:list不支持随机迭代器,他是双向迭代器,不能用库的sort的原因是因为,库里的sort用的快排,快排用的是随机访问,所以一般不用链表进行排序

解决方法:可以先把数据转移到vector中排序后,再转移到list中。

unique

这个函数的作用是用来去重。

但是去重是有条件的,他只能对排序的list进行去重

list的底层模拟实现

结点类的实现

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

迭代器模拟实现

因为底层空间不连续,地址不连续,所以需要封装迭代器

用模板T的原因是迭代器里封装了结点的指针。

版本1

template <class T>
struct _list_iterator
{typedef list_node<T> Node;Node* _node;T& operator*(){return _node->_data;}}

const迭代器,一般写法就是再定义一个const迭代器的类。这样复用性很差。达不到软件工程复用的思想。

大神写法就是用模板参数 来控制。

这里不用管第一个参数T,第一个参数是数据类型,比如int,只用控制解引用和箭头访问数值的就行。也就是控制Ref和 Ptr

const迭代器第一个位置不加const的原因是因为:需要保持一致的类型。因为在begin()函数中用结点的指针构造迭代器时,传递的是int的类型。但是模板传递过去是cosnt int类型。这时候类型不匹配。

//迭代器实现

	// 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){}// 析构函数  -- 节点不属于迭代器,不需要迭代器释放// 拷贝构造和赋值重载 -- 默认生成的浅拷贝就可以// *itRef operator*(){return _node->_data;}Ptr operator->(){ //return &(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;}bool operator!=(const self& it){return _node != it._node;}bool operator==(const self& it){return _node == it._node;}};

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;const_iterator begin() const{// list_node<int>*return const_iterator(_head->_next);}const_iterator end() const{return const_iterator(_head);}iterator begin(){return iterator(_head->_next);//return _head->_next;}iterator end(){return iterator(_head);}list(){_head = new Node();_head->_next = _head;_head->_prev = _head;}// lt2(lt1)/*list(const list<T>& lt){_head = new Node();_head->_next = _head;_head->_prev = _head;for (auto e : lt){push_back(e);}}*/void empty_init(){_head = new Node();_head->_next = _head;_head->_prev = _head;}template <class InputIterator>list(InputIterator first, InputIterator last){empty_init();while (first != last){push_back(*first);++first;}}// 17:00 继续void swap(list<T>& lt){std::swap(_head, lt._head);}// lt2(lt1) -- 现代写法list(const list<T>& lt){empty_init();list<T> tmp(lt.begin(), lt.end());swap(tmp);}// lt2 = lt1list<T>& operator=(list<T> lt){swap(lt);return *this;}~list(){clear();delete _head;_head = nullptr;}void clear(){iterator it = begin();while (it != end()){it = erase(it);}}void push_back(const T& x){//Node* tail = _head->_prev;//Node* newnode = new Node(x); _head       tail  newnode//tail->_next = newnode;//newnode->_prev = tail;//newnode->_next = _head;//_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());}// 插入在pos位置之前iterator insert(iterator pos, const T& x){Node* newNode = new Node(x);Node* cur = pos._node;Node* prev = cur->_prev;// prev  newnode  curprev->_next = newNode;newNode->_prev = prev;newNode->_next = cur;cur->_prev = newNode;return iterator(newNode);}iterator erase(iterator pos){assert(pos != end());Node* cur = pos._node;Node* prev = cur->_prev;Node* next = cur->_next;// prev  nextprev->_next = next;next->_prev = prev;delete cur;return iterator(next);}private:Node* _head;};void print_list(const list<int>& lt){list<int>::const_iterator it = lt.begin();while (it != lt.end()){//*it = 10; // 不允许修改cout << *it << " ";++it;}cout << endl;}

插入的实现

只用实现insert就好,头插尾插复用即可。

这个很简单,轻松实现

迭代器失效

insert

list的insert不存在迭代器失效的问题。因为list不需要像vector一样挪动数据,也不像vector一样扩容出现野指针。lsit的每个结点都是独立的。

erase

erase删掉一个结点时,已经delete了,空间已经被释放了。所以会导致迭代器失效。经典野指针失效

所以erase返回删除位置的下一个位置的迭代器。所以需要重新接收迭代器。

析构函数

析构函数内部直接调用clear(),因为析构时指这个结构不要了,所以直接delete哨兵位结点。

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

拷贝构造

拷贝构造函数的规则:我们不写,完成浅拷贝。所以_head被拷贝了一份,指向了同一块空间。

浅拷贝不一定有问题,看对应场合,比如在迭代器中,浅拷贝没有错。因为不用析构。

lsit中我们要完成深拷贝。这里需要析构。

这里先用迭代器区间进行拷贝构造

void empty_init()
{_head = new Node();_head ->_next = _head;_head->_prev = _head;
}template <class InputIterator>
list(InputIterator first, InputIterator last)
{//哨兵位结点必须有empty_init();while(first != last){push_pack(*first);++first;}
}

void swap(list<T>& lt)
{std::swap(_head, lt._head);
}
//lt2(lt1)
//现代写法
list(const list<T>& lt)
{empty_init();list<T> tmp(lt.begin(), lt.end());swap(tmp);
}

赋值构造函数

赋值构造函数返回引用,减少拷贝。返回list的原因是支持连续赋值。

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

相关文章:

植物大战 List——C++

这里写目录标题vector和stirng的细节对于stringlist的使用list的迭代器反向迭代器构造函数关于list::sort的排序uniquelist的底层模拟实现结点类的实现迭代器模拟实现list实现插入的实现迭代器失效inserterase析构函数拷贝构造赋值构造函数vector和stirng的细节 复习vector的深…...

安灯(andon)系统是车间现场管理的必备工具

安灯&#xff08;andon&#xff09;系统应用越来越广泛&#xff0c;不单单局限于汽车行业&#xff0c;更多生产型企业意识到了提高工作效率的重要性&#xff0c;提高工作效率根本的能提高生产水平&#xff0c;提高产量&#xff0c;而且安灯&#xff08;andon&#xff09;系统不…...

Hazel游戏引擎(004)

本人菜鸟&#xff0c;文中若有代码、术语等错误&#xff0c;欢迎指正 我写的项目地址&#xff1a;https://github.com/liujianjie/GameEngineLightWeight&#xff08;中文的注释适合中国人的你&#xff09; 文章目录前言操作步骤讲解GitHubHazel项目此项目定位项目属性修改Sand…...

【CS224W】(task4)图嵌入表示学习

note node2vec&#xff1a; 计算随机游走概率从节点uuu开始模拟rrr条长度为lll的游走链路使用 Stochastic Gradient Descent 优化损失函数 Node2vec在节点分类方面表现更好&#xff1b;而其他方法在链路预测上效果更好&#xff0c;如random walk效率更高&#xff1b;graph emb…...

分享111个HTML医疗保健模板,总有一款适合您

分享111个HTML医疗保健模板&#xff0c;总有一款适合您 111个HTML医疗保健模板下载链接&#xff1a;https://pan.baidu.com/s/1YInaQDnUVsXYtMh1Ls-BHg?pwdxvfc 提取码&#xff1a;xvfc Python采集代码下载链接&#xff1a;采集代码.zip - 蓝奏云 import os import shuti…...

山东大学2022操作系统期末

接力&#xff1a;山东大学2021操作系统期末 2022—2023山东大学计算机操作系统期末考试回忆版 简答题(4 10 points) &#xff08;1&#xff09;用户态&#xff0c;核心态是什么 &#xff08;2&#xff09;这种区分对现代操作系统的意义 &#xff08;3&#xff09;printf(“…...

Hadoop高可用搭建(一)

目录 创建多台虚拟机 修改计算机名称 快速生效 修改网络信息 重启网络服务 关闭和禁用每台机的防火墙 同步时间 安装ntpdate 定时更新时间 启动定时任务 设置集群中每台机器的/etc/hosts 把hosts拷贝发送到每一台虚拟机 配置免密登陆 将本机的公钥拷贝到要免密登…...

算法 - 剑指Offer 重建二叉树

题目 输入某二叉树的前序遍历和中序遍历的结果&#xff0c;请构建该二叉树并返回其根节点。 假设输入的前序遍历和中序遍历的结果中都不含重复的数字。 解题思路 这题较为复杂&#xff0c; 首先审题&#xff0c;前序遍历规则&#xff1a;根左右&#xff0c; 中序遍历&#x…...

手写JavaScript常见5种设计模式

想分享的几种设计模式 目前模式&#xff1a;工厂模式&#xff0c;单例模式&#xff0c;适配器模式&#xff0c;装饰者模式&#xff0c;建造者模式 建造者模式 简介&#xff1a;建造者模式&#xff08;builder pattern&#xff09;比较简单&#xff0c;它属于创建型模式的一种…...

Python 异步: 当前和正在运行的任务(9)

我们可以反省在 asyncio 事件循环中运行的任务。这可以通过为当前运行的任务和所有正在运行的任务获取一个 asyncio.Task 对象来实现。 1. 如何获取当前任务 我们可以通过 asyncio.current_task() 函数获取当前任务。此函数将为当前正在运行的任务返回一个任务对象。 ... # …...

REDIS-雪崩、击穿、穿透

直接发车&#x1f697; 一.雪崩 1.触发原因 A.大量缓存数据在同一时间过期(失效) B.redis故障宕机 上述均导致全部请求去访问数据库&#xff0c;导致DB压力骤增&#xff0c;严重则导致数据库宕机/系统宕机 2.应对策略 不同触发原因&#xff0c;应对策略也不一致 应对A&a…...

什么人合适学习Python

发了几天的Python基础&#xff0c;也认识了一些朋友&#xff0c;忽然有人问起&#xff0c;说为啥学Python&#xff0c;或者说啥人学习Python&#xff0c;作为一个教龄8年从Python一线讲师到Python教学主管的我和大家分享一下个人的看法&#xff0c;还是提前说一下&#xff0c;个…...

greenDao的使用文档

介绍&#xff1a;greenDAO 是一款轻量级的 Android ORM 框架&#xff0c;将 Java 对象映射到 SQLite 数据库中&#xff0c;我们操作数据库的时候&#xff0c;不在需要编写复杂的 SQL语句&#xff0c; 在性能方面&#xff0c;greenDAO 针对 Android 进行了高度优化&#xff0c; …...

基于JAVA+SpringBoot+LayUI+Shiro的仓库管理系统

基于JAVASpringBootLayUIShiro的仓库管理系统 ✌全网粉丝20W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取项目下载方式&#x1f345; 一、项…...

金三银四面试必看,复盘字节测试开发面试:一次测试负责人岗位面试总结

最近面试了某企业的测试负责人岗位&#xff0c;历经四面&#xff0c;收获蛮多的。 这篇文章&#xff0c;我想聊聊这次面试过程中的一些经历&#xff0c;以及些许经验和教训。 岗位要求 岗位名称&#xff1a;测试负责人 岗位要求&#xff1a;1、扎实的技术以及丰富的技术项目…...

【算法自由之路】 贪心算法

贪心算法 局部最右得到全局最右难点在于如何证明局部最优可以得到全局最优堆 和 排序 是贪心算法最常用的实现算法 贪心算法作为最符合自然智慧的算法&#xff0c;思路是从小部分取最优从而获得最终的最优&#xff0c;但是难得是怎样获取部分最优才能得到全局最优。 有时候我…...

Scratch少儿编程案例-水果忍者-学生作业

专栏分享 点击跳转=>Unity3D特效百例点击跳转=>案例项目实战源码点击跳转=>游戏脚本-辅助自动化点击跳转=>Android控件全解手册点击跳转=>Scratch编程案例👉关于作者...

7.Docker Compose

Docker Compose 介绍 Docker Compose是Docker官方编排&#xff08;Orchestration&#xff09;项目之一&#xff0c;负责快速的部署分布式应用。其代码目前在https://github.com/docker/compose上开源。Compose 定位是 「定义和运行多个 Docker 容器的应用&#xff08;Definin…...

GitHub访问问题与 Steam++下载及使用(适合小白)

前言 &#x1f4dc; “ 作者 久绊A ” 专注记录自己所整理的Java、web、sql等&#xff0c;IT技术干货、学习经验、面试资料、刷题记录&#xff0c;以及遇到的问题和解决方案&#xff0c;记录自己成长的点滴 ​ 目录 前言 一、Steam的介绍 1、大概介绍 2、详细介绍 二、Ste…...

Oracle对象——视图之简单视图与视图约束

文章目录什么是视图为什么会使用视图视图语法案例简单视图的创建更改数据基表&#xff0c;视图数据会变化么&#xff1f;更改视图数据&#xff0c;基表数据会变更么&#xff1f;带检查约束的视图结论创建只读视图&#xff08;MySQL不支持&#xff09;总结什么是视图 视图是一种…...

Java 语言特性(面试系列2)

一、SQL 基础 1. 复杂查询 &#xff08;1&#xff09;连接查询&#xff08;JOIN&#xff09; 内连接&#xff08;INNER JOIN&#xff09;&#xff1a;返回两表匹配的记录。 SELECT e.name, d.dept_name FROM employees e INNER JOIN departments d ON e.dept_id d.dept_id; 左…...

基于大模型的 UI 自动化系统

基于大模型的 UI 自动化系统 下面是一个完整的 Python 系统,利用大模型实现智能 UI 自动化,结合计算机视觉和自然语言处理技术,实现"看屏操作"的能力。 系统架构设计 #mermaid-svg-2gn2GRvh5WCP2ktF {font-family:"trebuchet ms",verdana,arial,sans-…...

vue3+vite项目中使用.env文件环境变量方法

vue3vite项目中使用.env文件环境变量方法 .env文件作用命名规则常用的配置项示例使用方法注意事项在vite.config.js文件中读取环境变量方法 .env文件作用 .env 文件用于定义环境变量&#xff0c;这些变量可以在项目中通过 import.meta.env 进行访问。Vite 会自动加载这些环境变…...

AI语音助手的Python实现

引言 语音助手(如小爱同学、Siri)通过语音识别、自然语言处理(NLP)和语音合成技术,为用户提供直观、高效的交互体验。随着人工智能的普及,Python开发者可以利用开源库和AI模型,快速构建自定义语音助手。本文由浅入深,详细介绍如何使用Python开发AI语音助手,涵盖基础功…...

tauri项目,如何在rust端读取电脑环境变量

如果想在前端通过调用来获取环境变量的值&#xff0c;可以通过标准的依赖&#xff1a; std::env::var(name).ok() 想在前端通过调用来获取&#xff0c;可以写一个command函数&#xff1a; #[tauri::command] pub fn get_env_var(name: String) -> Result<String, Stri…...

ZYNQ学习记录FPGA(一)ZYNQ简介

一、知识准备 1.一些术语,缩写和概念&#xff1a; 1&#xff09;ZYNQ全称&#xff1a;ZYNQ7000 All Pgrammable SoC 2&#xff09;SoC:system on chips(片上系统)&#xff0c;对比集成电路的SoB&#xff08;system on board&#xff09; 3&#xff09;ARM&#xff1a;处理器…...

PH热榜 | 2025-06-08

1. Thiings 标语&#xff1a;一套超过1900个免费AI生成的3D图标集合 介绍&#xff1a;Thiings是一个不断扩展的免费AI生成3D图标库&#xff0c;目前已有超过1900个图标。你可以按照主题浏览&#xff0c;生成自己的图标&#xff0c;或者下载整个图标集。所有图标都可以在个人或…...

__VUE_PROD_HYDRATION_MISMATCH_DETAILS__ is not explicitly defined.

这个警告表明您在使用Vue的esm-bundler构建版本时&#xff0c;未明确定义编译时特性标志。以下是详细解释和解决方案&#xff1a; ‌问题原因‌&#xff1a; 该标志是Vue 3.4引入的编译时特性标志&#xff0c;用于控制生产环境下SSR水合不匹配错误的详细报告1使用esm-bundler…...

Java设计模式:责任链模式

一、什么是责任链模式&#xff1f; 责任链模式&#xff08;Chain of Responsibility Pattern&#xff09; 是一种 行为型设计模式&#xff0c;它通过将请求沿着一条处理链传递&#xff0c;直到某个对象处理它为止。这种模式的核心思想是 解耦请求的发送者和接收者&#xff0c;…...

2025 后端自学UNIAPP【项目实战:旅游项目】7、景点详情页面【完结】

1、获取景点详情的请求【my_api.js】 // 引入公共的请求封装 import http from ./my_http.js// 登录接口&#xff08;适配服务端返回 Token&#xff09; export const login async (code, avatar) > {const res await http(/login/getWXSessionKey, {code,avatar}); };//…...