【c++】vector的增删查改
1.先定义一个类对象vector
为了防止和库里面发生冲突,定义一个命名空间,将类对象放在命名空间 里面
#include<iostream>
using namespace std;
namespace zjw {class vector {public:private:};
}
2.定义变量,需要一个迭代器,为了便于修改,变成任意类型的迭代器,我们使用函数模版,三个迭代器变量 _start用于指向顺序表的头,_finish指向顺序表的结尾的下一位,_end_of_storage保存总容量,在初始化列表中先设置为空
#include<iostream>
using namespace std;
namespace zjw {template<class T>class vector {public:typedef T * iterator;//迭代器类型vector():_start(nullptr), _finish(nullptr), _end_of_storage(nullptr){}private:iterator _start;iterator _finish;iterator _end_of_storage};
}
3.定义函数
1.返回指向顺序表开始的迭代器函数
2.返回指向顺序表结尾的迭代器函数
3.返回容量大小的函数
4.返回顺序表元素多少
5.判断顺序表为空地的函数
5.一个运算符重载的函数(返回给定下标下的值)
#include<iostream>
using namespace std;
namespace zjw {template<class T>class vector {public:typedef T * iterator;//迭代器类型vector():_start(nullptr), _finish(nullptr), _end_of_storage(nullptr){}iterator begin()//1{return _start;}iterator end()//2{return _finish;}size_t capacity()//3{return _end_of_storage - _start;}size_t size()//4{return _finish - _start;}bool empty()//5{return _finish == _start;}T& operator[](size_t pos)//6{assert(pos < size());return _start[pos];}private:iterator _start;iterator _finish;iterator _end_of_storage;};
}
4.reserve函数开空间
void reserve(size_t n){if (n > capacity){T* tmp = new T[n];if (_start){memcpy(tmp, _start, sizeof(T) * size());delete[] _start;}_start = tmp;_finish = _start + size();_end_of_storage = _start + n;}}
5.push_back函数尾插,以及尾删函数
void push_back(const T& x){if (_finish == _end_of_storage){reserve(capacity() == 0 ? 4 : capacity() * 2);}*_finish = x;_finish++;}void pop_back(){assert(!empty());--_finish;}
6.测试尾插,尾删,下标遍历,迭代器遍历,范围for遍历,以及运算符重载返回对应下标的元素
void test1(){vector<int>v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);v1.push_back(5);for (int i = 0; i < v1.size(); i++){cout << v1[i] << " ";}cout << endl;v1.pop_back();v1.pop_back();vector<int>::iterator it = v1.begin();while (it != v1.end()){cout << *it << " ";++it;}cout << endl;v1.pop_back();for (auto e : v1){cout << e << " ";}cout << endl;}
这里开空间的函数会发生问题
7.修改扩容函数
void reserve(size_t n){if (n > capacity){ int sz=size();T* tmp = new T[n];if (_start){memcpy(tmp, _start, sizeof(T) * size());delete[] _start;}_start = tmp;_finish = _start + sz;_end_of_storage = _start + n;}}
8.resize函数
参数小于容量大小,相当于缩容,参数大于容量大小,相当于扩容,超过_finish的用值初始化
在讲resize之前看看模版会不会给匿名变量初始化,内置类型是否能初始化.
template <class T>void f(){T x = T();cout << x << endl;}void test3(){f<int>();f<int*>();f<double>();}
发现可以,所以我们在resize里面当n>capacity(),我们可以把顺序表外的用来初始化,自定义类型相当于调用自己的构造函数,内置函数我们在这假装理解为调用自己的构造函数.
void resize(size_t n, T val = T()){if (n < size()){_finish = _start + n;}else{if (n > capacity())reserve(n);while (_finish != _start + n){*_finish = val;++_finish;}}}
9.测试resize
void test2(){vector<int>v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);v1.push_back(5);cout << v1.size() << endl;cout << v1.capacity() << endl;v1.resize(10);cout << v1.size() << endl;cout << v1.capacity() << endl;for (auto e : v1){cout << e << " ";}cout << endl;v1.resize(3);for (auto e : v1){cout << e << " ";}}}
10.封装一个打印函数用于任何vector对象
void func(const vector<int>& v){for (int i = 0; i < v.size(); i++)//下标{cout << v[i] << " ";}cout << endl;vector<int>::iterator it = v.begin();//迭代器while (it != v.end()){cout << *it << " ";++it;}cout << endl;for (auto e : v)//范围for{cout << e << " ";}cout << endl;}
因为打印不同对象的元素,为了区分是有一个this指针的,但是参数是const 无法产生this指针
解决方法,在这些函数后面加 const ,如果是const对象调用的话,就是权限平移,如果是非const的话,是权限缩小,都可以调用了,如果要限制别人去修改这个*it,我们可以定义一个const的迭代器
void func(const vector<int>& v){for (int i = 0; i < v.size(); i++)//下标{cout << v[i] << " ";}cout << endl;vector<int>::iterator it = v.begin();//迭代器while (it != v.end()){cout << *it << " ";++it;}cout << endl;for (auto e : v)//范围for{cout << e << " ";}cout << endl;}
void test4(){vector<int>v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);v1.push_back(5);func(v1);}
11.insert函数实现
void insert(iterator pos, const T& val){assert(pos >= _start);assert(pos <= _finish);if (_finish == _end_of_storage){reserve(capacity() == 0 ? 4 : capacity() * 2);}iterator end = _finish - 1;while (end >= pos){*(end + 1) = *end;--end;}*pos = val;++_finish;}
测试insert
void test5(){vector<int>v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);v1.push_back(5);for (auto e : v1)//范围for{cout << e << " ";}cout << endl;auto pos = find(v1.begin(), v1.end(), 3);//找到3的位置if (pos != v1.end()){v1.insert(pos, 30);//3前插入30}for (auto e : v1)//范围for{cout << e << " ";}cout << endl;(*pos)++;//让3+1for (auto e : v1)//范围for{cout << e << " ";}cout << endl;}}
pos保存的之前是3的地址,如果在3前插入一个30,pos所指向的位置就变成了30,*pos++,就变成了31;
如果我们不使用push_back(5)的话
void test5(){vector<int>v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);//v1.push_back(5);for (auto e : v1)//范围for{cout << e << " ";}cout << endl;auto pos = find(v1.begin(), v1.end(), 3);//找到3的位置if (pos != v1.end()){v1.insert(pos, 30);//3前插入30}for (auto e : v1)//范围for{cout << e << " ";}cout << endl;(*pos)++;//让3+1for (auto e : v1)//范围for{cout << e << " ";}cout << endl;}}
会出现报错,到底是怎么一回事??
如何修改??
我们需要在未扩容前记录好pos距离_start的位置,拷到新空间,他与新_start也保持这个距离,更新pos
void insert(iterator pos, const T& val){assert(pos >= _start);assert(pos <= _finish);if (_finish == _end_of_storage){int len=pos - _start;reserve(capacity() == 0 ? 4 : capacity() * 2);pos = _start + len;}iterator end = _finish - 1;while (end >= pos){*(end + 1) = *end;--end;}*pos = val;++_finish;}
这里的*pos里面的数据被清理,如果不清理应该是3++,应该是4,我们可以注释掉reserve中的delete看看
这里的问题被叫做迭代器失效
12.earse函数
void eraase(iterator pos){assert(pos >= _start);assert(pos < _finish);iterator start = pos + 1;while (start != _finish){*(start - 1) = *start;++start;}--_finish;}
earse函数测试
void test6(){vector<int>v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);for (auto e : v1)//范围for{cout << e << " ";}cout << endl;auto pos = find(v1.begin(), v1.end(), 2);if (pos != v1.end()){v1.erase(pos);//删除2}(*pos)++;2位置上的元素++for (auto e : v1)//范围for{cout << e << " ";}}
这里2删除后2的地址上存的就是3,然后给3++;在std中这个也算迭代器失效,由于这里是自己写的,所以没报错.
void test6(){std::vector<int>v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);for (auto e : v1)//范围for{cout << e << " ";}cout << endl;auto pos = find(v1.begin(), v1.end(), 2);if (pos != v1.end()){v1.erase(pos);}(*pos)++;for (auto e : v1)//范围for{cout << e << " ";}}}
上面会调用vector里面的函数
在不同编译器下有不同的处理情况。在vs中std我们认为迭代器失效,如果删除的是4的话,以我们实现的earse后,–_finish ;4那里的值没有被清理,所以后面的(*pos)++也不会出错,但在vs中我们使用vector里面的实现认为迭代器失效.
我们可以将代码拷过去在linux下试一下g++是怎么回事??
在g++中使用库中的vector函数删除数据4没有报错,对于迭代器失效,不同编译器也有不同处理.
13.整体代码
#include<iostream>
#include<assert.h>
#include<vector>
using namespace std;
namespace zjw {template<class T>class vector {public:typedef T * iterator;//迭代器类型typedef T* const_iterator;//迭代器类型vector():_start(nullptr), _finish(nullptr), _end_of_storage(nullptr){}iterator begin()const {return _start;}iterator end() const{return _finish;}size_t capacity(){return _end_of_storage - _start;}size_t size() const{return _finish - _start;}bool empty(){return _finish == _start;}T& operator[](size_t pos) const{assert(pos < size());return _start[pos];}void reserve(size_t n){int sz = size();if (n > capacity()){T* tmp = new T[n];if (_start){memcpy(tmp, _start, sizeof(T) * size());delete[] _start;}_start = tmp;_finish = _start + sz;_end_of_storage = _start + n;}}void push_back(const T& x){if (_finish == _end_of_storage){reserve(capacity() == 0 ? 4 : capacity() * 2);}*_finish = x;_finish++;}void pop_back(){assert(!empty());--_finish;}void resize(size_t n, T val = T()){if (n < size()){_finish = _start + n;}else{if (n > capacity())reserve(n);while (_finish != _start + n){*_finish = val;++_finish;}}}void insert(iterator pos, const T& val){assert(pos >= _start);assert(pos <= _finish);if (_finish == _end_of_storage){int len=pos - _start;reserve(capacity() == 0 ? 4 : capacity() * 2);pos = _start + len;}iterator end = _finish - 1;while (end >= pos){*(end + 1) = *end;--end;}*pos = val;++_finish;}void erase(iterator pos){assert(pos >= _start);assert(pos < _finish);iterator start = pos + 1;while (start != _finish){*(start - 1) = *start;++start;}--_finish;}private:iterator _start;iterator _finish;iterator _end_of_storage;};void test1(){vector<int>v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);v1.push_back(5);for (int i = 0; i < v1.size(); i++){cout << v1[i] << " ";}cout << endl;v1.pop_back();v1.pop_back();vector<int>::const_iterator it = v1.begin();while (it != v1.end()){cout << *it << " ";++it;}cout << endl;v1.pop_back();for (auto e : v1){cout << e << " ";}cout << endl;}void test2(){vector<int>v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);v1.push_back(5);cout << v1.size() << endl;cout << v1.capacity() << endl;v1.resize(10);cout << v1.size() << endl;cout << v1.capacity() << endl;for (auto e : v1){cout << e << " ";}cout << endl;v1.resize(3);for (auto e : v1){cout << e << " ";}}void func(const vector<int>& v){for (int i = 0; i < v.size(); i++)//下标{cout << v[i] << " ";}cout << endl;vector<int>::iterator it = v.begin();//迭代器while (it != v.end()){cout << *it << " ";++it;}cout << endl;for (auto e : v)//范围for{cout << e << " ";}cout << endl;}void test4(){vector<int>v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);v1.push_back(5);func(v1);}void test5(){vector<int>v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);// v1.push_back(5);for (auto e : v1)//范围for{cout << e << " ";}cout << endl;auto pos = find(v1.begin(), v1.end(), 3);//找到3的位置if (pos != v1.end()){v1.insert(pos, 30);//3前插入30}for (auto e : v1)//范围for{cout << e << " ";}cout << endl;(*pos)++;//让3+1cout << *pos << endl;for (auto e : v1)//范围for{cout << e << " ";}cout << endl;}void test6(){std:: vector<int>v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);for (auto e : v1)//范围for{cout << e << " ";}cout << endl;auto pos = find(v1.begin(), v1.end(), 4);if (pos != v1.end()){v1.erase(pos);}(*pos)++;for (auto e : v1)//范围for{cout << e << " ";}}}int main()
{// zjw::test1();zjw::test6();// zjw::test3();
}
相关文章:

【c++】vector的增删查改
1.先定义一个类对象vector 为了防止和库里面发生冲突,定义一个命名空间,将类对象放在命名空间 里面 #include<iostream> using namespace std; namespace zjw {class vector {public:private:}; }2.定义变量,需要一个迭代器ÿ…...

【研究生复试】计算机软件工程人工智能研究生复试——资料整理(速记版)——JAVA
1、JAVA 2、计算机网络 3、计算机体系结构 4、数据库 5、计算机租场原理 6、软件工程 7、大数据 8、英文 自我介绍 1. Java 1. 和 equals的区别 比较基本数据类型是比较的值,引用数据类型是比较两个是不是同一个对象,也就是引用是否指向同 一个对象&…...

JVM-JVM中对象的生命周期
申明:文章内容是本人学习极客时间课程所写,文字和图片基本来源于课程资料,在某些地方会插入一点自己的理解,未用于商业用途,侵删。 原资料地址:课程资料 对象的创建 常量池检查:检查new指令是否能在常量池…...

RegExp正则表达式左限定右限定左右限定,预查询,预查寻,断言 : (?<= , (?= , (?<! , (?!
RegExp正则表达式左限定右限定左右限定,预查询,预查寻,断言 : (?< , (? , (?<! , (?! 有好多种称呼 (?< , (? , (?<! , (?! 有好多种称呼 , 我称为: 左限定, 右限定, 左否定, 右否定 (?<左限定) (?右限定)(?<!左否定) (?!右限定) 再…...

相机图像质量研究(30)常见问题总结:图像处理对成像的影响--重影
系列文章目录 相机图像质量研究(1)Camera成像流程介绍 相机图像质量研究(2)ISP专用平台调优介绍 相机图像质量研究(3)图像质量测试介绍 相机图像质量研究(4)常见问题总结:光学结构对成像的影响--焦距 相机图像质量研究(5)常见问题总结:光学结构对成…...

问题记录——c++ sort 函数 和 严格弱序比较
引出 看下面这段cmp函数的定义 //按照vector第一个元素升序排序 static bool cmp(const vector<int>& a, const vector<int>& b){return a[0] < b[0]; }int eraseOverlapIntervals(vector<vector<int>>& intervals) {//按区间左端排序…...

《Go 简易速速上手小册》第9章:数据库交互(2024 最新版)
文章目录 9.1 连接数据库 - Go 语言的海底宝藏之门9.1.1 基础知识讲解安装数据库驱动数据库连接 9.1.2 重点案例:用户信息管理系统准备数据库Go 代码实现连接数据库添加新用户查询用户信息用户登录验证主函数 9.1.3 拓展案例 1:批量添加用户准备数据库Go…...

redis的hash数据结构底层简记
hash:k和v都是string的hash表。 HSET(设置集合数据,4.0之前只能设置1个,之后可以设置多个),HSETNX(若k不存在则设置对应v),HDEL(删除指定kv,可以一次删除多个)…...

清除Django的管理员admin站点中“Recent Actions“最近活动面板上的所有信息
清除Django的管理员admin站点中"Recent Actions"最近活动面板上的所有信息 本文主要介绍了如何清除Django的管理员admin站点中"Recent Actions"最近活动面板上的所有信息 操作步骤如下 进入Django项目目录中运行代python manage.py shell进入Django shell…...

【JVM篇】ThreadLocal中为什么要使用弱引用
文章目录 🍔ThreadLocal中为什么要使用弱引用⭐总结 🍔ThreadLocal中为什么要使用弱引用 ThreadLocal可以在线程中存放线程的本地变量,保证数据的线程安全 ThreadLocal是这样子保存对象的: 在每个线程中,存放了一个…...

Stable Diffusion教程——stable diffusion基础原理详解与安装秋叶整合包进行出图测试
前言 在2022年,人工智能创作内容(AIGC)成为了AI领域的热门话题之一。在ChatGPT问世之前,AI绘画以其独特的创意和便捷的创作工具迅速走红,引起了广泛关注。随着一系列以Stable Diffusion、Midjourney、NovelAI等为代表…...

【JavaEE】_线程与多线程的创建
目录 1. 线程的概念 2. 创建与使用多线程 2.1 方式1:继承Thread类 2.2 方式2: 实现Runnable接口 2.3 以上两种创建线程方式的对比 3. 多线程的优势-增加运行速度 1. 线程的概念 进程的存在是由于系统的多任务执行需求,这也要求程序员进…...

【前端工程化面试题】如何优化提高 webpack 的构建速度
使用最新版本的 Webpack 和相关插件: 每个新版本的 Webpack 都会带来性能方面的改进和优化,因此始终确保你在使用最新版本。同时,更新你的相关插件也是同样重要的。 使用DllPlugin动态链接库: 使用DllPlugin和DllReferencePlugin来将第三方库的代码进行…...

免费chatgpt使用
基本功能如下: https://go.aigcplus.cc/auth/register?inviteCode3HCULH2UD...

OpenCV识别人脸案例实战
使用级联函数 基本流程 函数介绍 在OpenCV中,人脸检测使用的是cv2.CascadeClassifier.detectMultiScale()函数,它可以检测出图片中所有的人脸。该函数由分类器对象调用,其语法格式为: objects cv2.CascadeClassifier.detectMul…...

VOSK——离线语音库
文章目录 识别函数调用添加自定义热词表1. SetWords2. SetLatticeWords3. SetPartialWords使用示例注意1. SetMaxAlternatives2. SetNLSML3. SetSpkModel4. SetGrammar使用示例注意SetLogLevel示例用法注意事项 识别函数调用 在使用Vosk库进行语音识别时,PartialRe…...

ELAdmin 隐藏添加编辑按钮
使用场景 做了一个监控模块,数据都是定时生成的,所以不需要手动添加和编辑功能。 顶部不显示 可以使用 true 或者 false 控制现实隐藏 created() {this.crud.optShow {add: false,edit: false,del: true,download: true,reset: true}},如果没有 crea…...

浅谈Websocket
由于 http 存在⼀个明显的弊端(消息只能有客户端推送到服务器端,⽽服务器端不能主动推送到客户端),导致如果服务器如果有连续的变化,这时只能使⽤轮询,⽽轮询效率过低,并不适合。于是 WebSocket 被发明出来 WebSocket 是⼀种在 Web 应⽤程序中实现双向通信的协议。与传…...

JavaScript闭包详细介绍
文章目录 什么是闭包优点:变量持久化:封装私有变量:模块化:函数工厂: 缺点:内存占用:调试困难:过度使用导致性能下降: 什么是闭包 闭包是指有权访问另一个函数作用域中的…...

pytorch神经网络入门代码
import torch import torch.nn as nn import torch.optim as optim import torchvision import torchvision.transforms as transforms# 定义神经网络结构 class SimpleNN(nn.Module):def __init__(self, input_size, hidden_size, num_classes):super(SimpleNN, self).__init_…...

代码随想录算法训练营第三十四天|860.柠檬水找零 406.根据身高重建队列 452. 用最少数量的箭引爆气球
860.柠檬水找零 链接:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台 细节: 1. 首先根据题意就是只有5.的成本,然后就开始找钱,找钱也是10.和5. 2. 直接根据10 和 5 进行变量定义,然后去循环…...

Ditto:提升剪贴板体验的宝藏软件(复制粘贴效率翻倍、文本处理好助手)
名人说:莫道桑榆晚,为霞尚满天。——刘禹锡(刘梦得,诗豪) 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 目录 一、什么是Ditto?二、下载安装三、如…...

【自然语言处理-工具篇】spaCy<2>--模型的使用
前言 之前已经介绍了spaCy的安装,接下来我们要通过下载和加载模型去开始使用spaCy。 下载模型 经过训练的 spaCy 管道可以作为 Python 包安装。这意味着它们是应用程序的一个组件,就像任何其他模块一样。可以使用 spaCy download的命令安装模型,也可以通过将 pip 指向路径或…...

Java之通过Jsch库连接Linux实现文件传输
Java之通过JSch库连接Linux实现文件传输 文章目录 Java之通过JSch库连接Linux实现文件传输1. JSch2. Java通过Jsch连接Linux1. poxm.xml2. 工具类3. 调用案例 1. JSch 官网:JSch - Java Secure Channel (jcraft.com) JSch是SSH2的纯Java实现。 JSch 允许您连接到 ss…...

Nginx七层负载均衡之动静分离
思路: servera:负载均衡服务器 serverb:静态服务器 serverc:动态服务器 serverd:默认服务器 servera(192.168.233.132): # 安装 Nginx 服务器 yum install nginx -y#关闭防火墙和selinux systemctl stop firewalld setenforce 0# 切换到 Nginx 配置文…...

305_C++_定义了一个定时器池 TimerPool 类和相关的枚举类型和结构体
头文件:定义了一个定时器池 TimerPool 类和相关的枚举类型和结构体 #ifndef TIMERPOOL_H #define TIMERPOOL_H #include "rsglobal.h" #include "taskqueue.h" #incl...

大整数因数分解工具——yafu
一、安装 yafu--下载链接 二、配置环境变量,直接从cmd打开 1.找到yafu-x64.exe 所在的文件路径 2.点击设置——系统——系统信息——高级系统设置——环境变量——点击PATH(上下都可以)——新建 添加yafu-x64.exe 所在路径——点击确定 3…...

非关系型数据库(NOSQL)和关系型数据库(SQL)区别详解
前言: 在我们的日常开发中,关系型数据库和非关系型数据库的使用已经是一个成熟的软件产品开发过程中必不可却的存储数据的工具了。那么用了这么久的关系数据库和非关系型数据库你们都知道他们之间的区别了吗?下面我们来详细的介绍一下。 关系…...

7.Cloud-GateWay
0.概述 https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.1.RELEASE/reference/html/ 1.入门配置 1.1 POM <!--新增gateway--> <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-sta…...

【Linux】Framebuffer 应用
# 前置知识 LCD 操作原理 在 Linux 系统中通过 Framebuffer 驱动程序来控制 LCD。 Frame 是帧的意思, buffer 是缓冲的意思,这意味着 Framebuffer 就是一块内存,里面保存着一帧图像。 Framebuffer 中保存着一帧图像的每一个像素颜色值&…...