当前位置: 首页 > 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;总结什么是视图 视图是一种…...

通过Wrangler CLI在worker中创建数据库和表

官方使用文档&#xff1a;Getting started Cloudflare D1 docs 创建数据库 在命令行中执行完成之后&#xff0c;会在本地和远程创建数据库&#xff1a; npx wranglerlatest d1 create prod-d1-tutorial 在cf中就可以看到数据库&#xff1a; 现在&#xff0c;您的Cloudfla…...

【RockeMQ】第2节|RocketMQ快速实战以及核⼼概念详解(二)

升级Dledger高可用集群 一、主从架构的不足与Dledger的定位 主从架构缺陷 数据备份依赖Slave节点&#xff0c;但无自动故障转移能力&#xff0c;Master宕机后需人工切换&#xff0c;期间消息可能无法读取。Slave仅存储数据&#xff0c;无法主动升级为Master响应请求&#xff…...

如何在最短时间内提升打ctf(web)的水平?

刚刚刷完2遍 bugku 的 web 题&#xff0c;前来答题。 每个人对刷题理解是不同&#xff0c;有的人是看了writeup就等于刷了&#xff0c;有的人是收藏了writeup就等于刷了&#xff0c;有的人是跟着writeup做了一遍就等于刷了&#xff0c;还有的人是独立思考做了一遍就等于刷了。…...

Python 训练营打卡 Day 47

注意力热力图可视化 在day 46代码的基础上&#xff0c;对比不同卷积层热力图可视化的结果 import torch import torch.nn as nn import torch.optim as optim from torchvision import datasets, transforms from torch.utils.data import DataLoader import matplotlib.pypl…...

Ubuntu系统复制(U盘-电脑硬盘)

所需环境 电脑自带硬盘&#xff1a;1块 (1T) U盘1&#xff1a;Ubuntu系统引导盘&#xff08;用于“U盘2”复制到“电脑自带硬盘”&#xff09; U盘2&#xff1a;Ubuntu系统盘&#xff08;1T&#xff0c;用于被复制&#xff09; &#xff01;&#xff01;&#xff01;建议“电脑…...

水泥厂自动化升级利器:Devicenet转Modbus rtu协议转换网关

在水泥厂的生产流程中&#xff0c;工业自动化网关起着至关重要的作用&#xff0c;尤其是JH-DVN-RTU疆鸿智能Devicenet转Modbus rtu协议转换网关&#xff0c;为水泥厂实现高效生产与精准控制提供了有力支持。 水泥厂设备众多&#xff0c;其中不少设备采用Devicenet协议。Devicen…...

es6+和css3新增的特性有哪些

一&#xff1a;ECMAScript 新特性&#xff08;ES6&#xff09; ES6 (2015) - 革命性更新 1&#xff0c;记住的方法&#xff0c;从一个方法里面用到了哪些技术 1&#xff0c;let /const块级作用域声明2&#xff0c;**默认参数**&#xff1a;函数参数可以设置默认值。3&#x…...

一些实用的chrome扩展0x01

简介 浏览器扩展程序有助于自动化任务、查找隐藏的漏洞、隐藏自身痕迹。以下列出了一些必备扩展程序&#xff0c;无论是测试应用程序、搜寻漏洞还是收集情报&#xff0c;它们都能提升工作流程。 FoxyProxy 代理管理工具&#xff0c;此扩展简化了使用代理&#xff08;如 Burp…...

自定义线程池1.2

自定义线程池 1.2 1. 简介 上次我们实现了 1.1 版本&#xff0c;将线程池中的线程数量交给使用者决定&#xff0c;并且将线程的创建延迟到任务提交的时候&#xff0c;在本文中我们将对这个版本进行如下的优化&#xff1a; 在新建线程时交给线程一个任务。让线程在某种情况下…...

Python爬虫(52)Scrapy-Redis分布式爬虫架构实战:IP代理池深度集成与跨地域数据采集

目录 一、引言&#xff1a;当爬虫遭遇"地域封锁"二、背景解析&#xff1a;分布式爬虫的两大技术挑战1. 传统Scrapy架构的局限性2. 地域限制的三种典型表现 三、架构设计&#xff1a;Scrapy-Redis 代理池的协同机制1. 分布式架构拓扑图2. 核心组件协同流程 四、技术实…...