string模拟实现插入+删除

个人主页:Jason_from_China-CSDN博客

所属栏目:C++系统性学习_Jason_from_China的博客-CSDN博客

所属栏目:C++知识点的补充_Jason_from_China的博客-CSDN博客

  string模拟实现reserve

这里实现的是扩容

扩容这里是可以实现缩容,可以实现扩容,这里主要实现的就是扩容的实现,这里实现缩容的实现

//扩容(reserve扩容是不更新_size的,因为你只是扩容,_size==_capacity)
void string::reserve(size_t n)
{assert(n >= 0);//扩容//扩容这里是需要拷贝空间的//不能直接new加空间,new存在的意义是开辟空间,不能像realloc一样扩容,但是realloc底层其实也是malloc,然后和这个逻辑一样if (n > _size){char* tmp = new char[n + 1];strcpy(tmp, _str);delete[] _str;_str = tmp;_capacity = n;}
}

代码解释

  1. 首先我们断言一下,因为size_t是无符号整数类型,所以肯定的大于等于0
  2. 这里我们判断是不是需要扩容,如果是需要扩容我们继续进行逻辑的实现
  3. 扩容的时候我们是需要创建一个新的空间的,然后析构旧空间,让_str指向新的空间
  4. 更新_capacity,注意这里是_size不做更新的,因为这里只是扩容,不是输入什么字符

string模拟实现尾插push_back

尾插的实现是很简单的:

	//尾插的实现void string::push_back(char ch){if (_capacity == _size){//这里是不能使用_size的,_size是空间里面包含的个数//_size == 0 ? 4 : _capacity * 2;//reserve(_size);reserve(_capacity == 0 ? 4 : _capacity * 2);}_str[_size] = ch;_size++;_str[_size] = '\0';}

代码解释:

  1. (_capacity == _size)首先判断是不是需要扩容
  2. reserve(_capacity == 0 ? 4 : _capacity * 2);如果空间是0的情况下,我们需要给初始空间
  3. 插入数值,更新_size

注意事项:

  1. 这里我们可以看到:_str[_size] = '\0';,我们在尾部插入字符0,这里是很关键的一步骤,因为如果你的优化开的比较大,那么有的编译器会直接自己给你加上字符\0,但是按照实际书写来说的话,其实这里是需要我们自己加上的
  2. 如果我们不加上字符\0,就会导致打印的时候把后面没有初始化的空间打印出来

  3. 我们加上之后,就不会产生这样的问题

  4. 1,原因解释,因为我们在尾插的时候,首先字符\0就是占据一个空间的,但是这个空间是不计入个数的。
    2,其次,这个空间就在字符计数的下一个,所以我们尾插,包括append的实现,都是会直接把这个\0的位置给直接替换,所以需要追加字符\0。
    3,除非我们再实现一个向后移动,但是没有必要。
    4,或者我们实现运算符重载+=,我们利用+=来实现,但是我还是觉得没有必要,因为的+=我们是复用append,而且是直接string这个类来接受,如果再实现一个字符串的+=会导致代码的冗余,所以此时是最优解
    5,这里我们可以看见,这里我们的+=是直接返回整个类的,如果只是改变字符串不改变整个类,那么是没有必要的

string模拟实现append

  1. append我们主要实现的是插入字符和字符串,这两个核心功能,并且也都是实现尾插
  2. 对于指定位置插入字符串,我们会在insert这个接口实现,
  3. 我们的目的是在实现的过程里面更加区分不同接口的作用
	//随机插入的实现,插入字符,插入字符串void string::append(char ch){if (_capacity == _size){reserve(_capacity == 0 ? 4 : _capacity * 2);}		_str[_size] = ch;_size++;_str[_size] = '\0';//这里relase会进行优化,但是debug不会进行优化,所以是需要加上字符\0的}void string::append(const char* str){size_t len = strlen(str);if (len + _size > _capacity){reserve(_capacity == 0 ? 4 : _capacity * 2);if (len + _size > _capacity)reserve(len + _size);}//参数//目的地//指向要复制内容的目标数组的指针。//来源//要复制的 C 字符串strcpy(_str + _size, str);_size += len;}

字符插入的代码解释:

  1. 这里字符的插入的实现逻辑和尾插的实现逻辑差不多,所以不做过多赘述

字符串插入的代码解释:

  1. 首先我们需要判断,插入的字符串的长度和现有_size的长度,会不会超过存储空间,超过空间了,我们一般是采取二倍扩容,如果二倍扩容还是不够的情况下,此时我们需要再次扩容
  2. strcpy
  3. 我们实现扩容之后,我们只需要了解strcmp的特性就可以,我们直接把需要插入的字符串拷贝到_str里面可以,这里有一点就是,我们是从\0开始拷贝的,我们把\0给覆盖了。因为拷贝过来的字符串是包含\0的

string模拟实现+=

这里其实就是复用append,比较简单,直接上代码

	//尾插的实现string& string::operator+=(char ch){append(ch);return *this;}string& string::operator+=(const char* str){append(str);return *this;}

注意事项:

  1. 我们只需要返回的时候返回这个对象,也就是*this,因为+=是对象本身是需要发生改变的

string模拟实现insert

这里是有一点难度的,难度不大,主要是边界问题的处理,这里的图解会涉及的多一点

插入字符:

	//插入+添加字符串void string::insert(size_t pos, char ch){//这里需要断言一下,无符号整形如果传递是负值,就会导致传递一个非常大的数值//但是我们不需要断言插入的数值是否小于_size,因为当大于_size的时候,会把空格当做字符,进行移动,当然前提是\0在空间结束之前,调试的时候可以看出来assert(pos >= 0);//判断需不需要扩容if (_capacity == _size){reserve(_capacity == 0 ? 4 : _capacity * 2);}//移动的两种方式//1,end=_size,往后移动,进行插入->弊端,会产生越界的行为,我们需要进行修正//2,end=_size+1,往后移动,进行插入int end = _size + 1;while (end > pos){_str[end] = _str[end - 1];end--;}_str[pos] = ch;_size++;}

代码解释

  1. 首先我们进行断言,这里断言直接大于0就可以,如果按照下图\0是会往后移动的
  2. 我们判断插入此时空间是不是满了,满了是需要扩容的

核心代码讲解(不推荐的方式):

  1. 第一种方式:
    1,如果我希望在pos==0这个位置插入一个字符2,那么此时我就需要把所有的数值往后移动,那么我们就涉及到一点,我们可以指向已知的最后一个字符,设置为end
    2,但是这样是存在弊端的,我们看代码是可以发现的,我们的循环条件是end>=pos
    我们的条件不能是end>pos,当pos==0的时候,这样就会导致end在pos==1的位置停下来
    3,当我们end>=pos,当end==0的时候,依旧会继续循环,然后end---,最后越界,最后我们才能在pos的位置进行插入
    4,但是需要清楚一点的是,pos是size_t类型的,是无符号整形,所以我们需要转换为int类型,从而进行对比
    5,所以这一种方式是不推荐的
  2. 第二种方式(比较推荐的方式):
    这里实现的关键是要把插入的字符计入到总的空间里面,此时不会产生越界的情况
    此时我们的循环条件只是end>pos
    当等于pos的时候,就会停止循环


 

插入字符串:

这里我们直接上代码,并且实现方式我们依旧是采取第二种实现方式进行实现

	void string::insert(size_t pos, const char* str){assert(pos >= 0);//判断是不是需要扩容int len = strlen(str);if (_size + len > _capacity){reserve(_capacity == 0 ? 4 : _capacity * 2);if (_size + len > _capacity)reserve(_size + len);}//留出来插入字符的空间int end = _size + len;//end>while (end > pos + len - 1)//这里是需要等于的,因为需要把数值赋值给_str[end] = _str[end - len];{_str[end] = _str[end - len];end--;}//进行插入for (size_t i = 0; i <len; i++){_str[pos + i] = str[i];}//更新长度_size += len;}

代码解释:

  1. 我们依旧是需要判断是不是需要扩容

核心代码讲解:

  1. 留出充足的移动的空间
  2. 进行移动
    移动的时候我们是不能直接移动到pos这个位置的,这样会导致越界的行为
  3. 进行插入

string模拟实现earse

earse的实现,我们主要是实现指定位置删除指定长度

不传递参数会有缺省参数

//头文件	//删除字符+删除字符串void earse(size_t pos, size_t len = npos);private://这里本质上就是字符串的增删查改,所以和数据结构是有点像的char* _str;size_t _size;size_t _capacity;//C++静态成员变量,规定静态成员变量必须是类里面声明,类外面定义,但是C++还规定,int类型是可以类里面声明,类里面定义的static const int npos = -1;
//实现文件//删除字符+删除字符串
//这里是pos指的是下标
void string::earse(size_t pos, size_t len)
{assert(pos >= 0);//这种情况下,就是从pos位置开始往后全部删除// || len == npos,这里不需要再这样,因为这里是无符号整形,也就是我们传递是npos==-1,但是我们接受的是一个很大的数值,所以已经确定了是直接全部删除的if (len >= _size - pos){_str[pos] = '\0';_size = pos;}else{size_t end = pos + len;while (end <= _size){_str[end - len] = _str[end];end++;}_size -= len;}
}

注意事项:

  1. 首先我们看npos,因为npos是一个默认的缺省参数,因为npos在很多地方都会用到,所以我们给到一个静态成员变量
  2. 我们给npos是一个-1的数值,因为npos是一个无符号整形,-1就会直接给到一个最大值。
  3. 关于静态成员变量,类里面定义,类外面初始化的问题。这里刚好有一个点就是,C++给整形,也就是int类型开了一个后门,就是只有int类型可以类里面定义,类里面初始化

代码解释:

  1. 首先我们得知道我们删除的字符的长度是多少,如果pos所在位置到尾部最后一个位置的字符只有三个,你需要删除的有四个,其实就没有必要了,直接在pos这里插入字符\0就可以,并且更新_size
  2. 如果不是这样的情况,也就是从中间删除一段字符,此时我们只需要把后面的字符移动到中间那一段字符就可以,进行覆盖最后在后面插入字符串
    移动的时候我们是需要移动到_str[_size]这个位置的,这个位置是\0,所以最后我们是不需要插入字符\0的
  3. 最后更新_szie

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

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

相关文章

《JVM第8课》垃圾回收算法

文章目录 1.标记算法1.1 引用计数法1.2 可达性分析法 2.回收算法2.1 标记-清除算法&#xff08;Mark-Sweep&#xff09;2.2 复制算法&#xff08;Coping&#xff09;2.3 标记-整理算法&#xff08;Mark-Compact&#xff09; 3.三种垃圾回收算法的对比 为什么要进行垃圾回收&…

编程之路:蓝桥杯备赛指南

文章目录 一、蓝桥杯的起源与发展二、比赛的目的与意义三、比赛内容与形式四、比赛前的准备五、获奖与激励六、蓝桥杯的影响力七、蓝桥杯比赛注意事项详解使用Dev-C的注意事项 一、蓝桥杯的起源与发展 蓝桥杯全国软件和信息技术专业人才大赛&#xff0c;简称蓝桥杯&#xff0c…

全网最适合入门的面向对象编程教程:58 Python字符串与序列化-序列化Web对象的定义与实现

全网最适合入门的面向对象编程教程&#xff1a;58 Python 字符串与序列化-序列化 Web 对象的定义与实现 摘要&#xff1a; 如果我们要在不同的编程语言之间传递对象&#xff0c;就必须把对象序列化为标准格式&#xff0c;比如XML\YAML\JSON格式这种序列化Web对象。这种序列化W…

使用YOLO 模型进行线程安全推理

使用YOLO 模型进行线程安全推理 一、了解Python 线程二、共享模型实例的危险2.1 非线程安全示例&#xff1a;单个模型实例2.2 非线程安全示例&#xff1a;多个模型实例 三、线程安全推理3.1 线程安全示例 四、总结4.1 在Python 中运行多线程YOLO 模型推理的最佳实践是什么&…

每日一题|3255. 长度为 K 的子数组的能量值 II|递增序列、计数器

同昨天的解法一样&#xff0c;遍历一遍的同时&#xff0c;统计当前最长的子串长度&#xff0c;如果>k&#xff0c;则将子串开始位置处赋值子串当前位置元素的值。 class Solution:def resultsArray(self, nums: List[int], k: int) -> List[int]:res [-1] * (len(nums)…

金华迪加现场大屏互动系统 mobile.do.php 任意文件上传漏洞复现

0x01 产品描述&#xff1a; ‌ 金华迪加现场大屏互动系统‌是由金华迪加网络科技有限公司开发的一款专注于增强活动现场互动性的系统。该系统设计用于提供高质量的现场互动体验&#xff0c;支持各种大型活动&#xff0c;如企业年会、产品发布会、展览展示等。其主要功能包…

【网络面试篇】HTTP(1)(笔记)——状态码、字段、GET、POST、缓存

目录 一、相关问题 1. HTTP请求常见的状态码和字段&#xff1f; &#xff08;1&#xff09;状态码 &#xff08;2&#xff09;字段 ① Host 字段 ② Content-length 字段 ③ Connection 字段 ④ Content-Type 字段 ⑤ Content-Encoding 字段 2. GET 和 POST 的区别&a…

Java学习Day60:微服务总结!(有经处无火,无火处无经)

1、技术版本 jdk&#xff1a;17及以上 -如果JDK8 springboot&#xff1a;3.1及其以上 -版本2.x springFramWork&#xff1a;6.0及其以上 -版本5.x springCloud&#xff1a;2022.0.5 -版本格林威治或者休斯顿 2、模拟springcloud 父模块指定父pom <parent><…

ThreadX在STM32上的移植:F1,F4通用启动文件tx_initialize_low_level.s

在嵌入式系统开发中&#xff0c;实时操作系统&#xff08;RTOS&#xff09;的选择对于系统性能和稳定性至关重要。ThreadX是一种广泛使用的RTOS&#xff0c;它以其小巧、快速和可靠而闻名。在本文中&#xff0c;我们将探讨如何将ThreadX移植到STM32微控制器上&#xff0c;特别是…

UE5.4 PCG基础节点

Projection&#xff1a;投影。可以让撒点重新恢复到表面采样器的初始高度和旋转值。缩放保持不变 DensityFilter&#xff1a;密度过滤器 AttributeNoise&#xff1a;Attribute噪声 模式&#xff1a;设置。重新定义噪点分布为0-1 模式&#xff1a;加0或乘1的时候&#xff0…

STM32-PWR低功耗

一、概述 PWR&#xff08;Power Control&#xff09;电源控制&#xff0c;PWR负责管理STM32内部的电源供电部分&#xff0c;可以实现可编程电压监测器和低功耗模式的功能可编程电压监测&#xff08;PVD&#xff09;可以监控VDD电源电压&#xff0c;当VDD下降到PVD阀值以下或上…

AI 证件照工具 HivisionIDPhotos

如何在 Linux 系统使用 Docker 在本地部署 HivisionIDPhotos&#xff0c;并结合路由侠内网穿透外网访问本地部署的 HivisionIDPhotos 。 第一步&#xff0c;本地部署安装 HivisionIDPhotos 1&#xff0c;检查 Docker 服务状态&#xff0c;确保 Docker 正常运行。 systemctl …

springboot - 定时任务

定时任务是企业级应用中的常见操作 定时任务是企业级开发中必不可少的组成部分&#xff0c;诸如长周期业务数据的计算&#xff0c;例如年度报表&#xff0c;诸如系统脏数据的处理&#xff0c;再比如系统性能监控报告&#xff0c;还有抢购类活动的商品上架&#xff0c;这些都离不…

pandas——对齐运算+函数应用

引言&#xff1a;对齐运算是数据清洗的重要过程&#xff0c;可以按索引对齐进行运算&#xff0c;如果没对齐的位置则补NaN&#xff0c;最后也可以填充NaN 一、Series的对齐运算 1.Series 按行、索引对齐 import pandas as pds1 pd.Series(range(10, 20), indexrange(10)) s2…

画动态爱心(Python-matplotlib)

介绍 氵而已 由于用的是 AI&#xff0c;注释得非常清楚&#xff0c;自己改改也可以用 代码 # -*- coding: utf-8 -*- # Environment PyCharm # File_name 尝试1 |User Pfolg # 2024/11/05 22:45 import numpy as np import matplotlib.pyplot as plt import matplot…

学习threejs,将多个网格合并成一个网格

&#x1f468;‍⚕️ 主页&#xff1a; gis分享者 &#x1f468;‍⚕️ 感谢各位大佬 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍⚕️ 收录于专栏&#xff1a;threejs gis工程师 文章目录 一、&#x1f340;前言1.1 ☘️THREE.Geometry 几何体1.2 …

对于一个需要渲染300帧的动画项目,云渲染要多久

探讨云渲染动画300帧需要多久的问题时&#xff0c;我们今天来从多个角度进行分析&#xff0c;对于一个需要渲染300帧的动画项目&#xff0c;传统的本地渲染方式可能会因为硬件限制而变得耗时且效率低下。幸运的是&#xff0c;【渲染101】云渲染技术的出现为这一问题提供了解决方…

系统上云-流量分析和链路分析

优质博文&#xff1a;IT-BLOG-CN 一、流量分析 【1】流量组成&#xff1a; 按协议划分&#xff0c;流量链路可分为HTTP、SOTP、QUIC三类。 HTTPSOTPQUIC场景所有HTTP请求&#xff0c;无固定场景国内外APP等海外APP端链路选择DNS/CDN(当前特指Akamai)APP端保底IP列表/动态IP下…

「Mac畅玩鸿蒙与硬件22」鸿蒙UI组件篇12 - Canvas 组件的动态进阶应用

在鸿蒙应用中&#xff0c;Canvas 组件可以实现丰富的动态效果&#xff0c;适合用于动画和实时更新的场景。本篇将介绍如何在 Canvas 中实现动画循环、动态进度条、旋转和缩放动画&#xff0c;以及性能优化策略。 关键词 Canvas 组件动态绘制动画效果动态进度条旋转和缩放性能优…

C 学习(4)

return 0; 前提&#xff1a;C 语言规定&#xff0c;main()是程序的入口函数&#xff0c;即所有的程序一定要包含一个main()函数。程序总是从这个函数开始执行&#xff0c;如果没有该函数&#xff0c;程序就无法启动。其他函数都是通过它引入程序的。 main()的写法&#xff0c…