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

C++STL专题 vector底层实现


目录

一, vector的手搓

1.构造函数

2. 拷贝构造的实现

3.析构函数

4.begin() end() 的实现

5.reserve的实现

6.size和capacity的实现

7.push_back的实现

8.pop_back的实现

9.empty的实现

10.insert的实现

11.erase的实现

12.resize的实现

13.clear的实现

14.swap的实现

14. []重载

15.=重载

16. Vector类中的private

二,源码


一, vector的手搓

Vector类的定义

template <class T>
class Vector
{
public:typedef T* iterator;typedef const T* const_iterator;Vector(){}private:iterator _start = nullptr;//最开始iterator _finish = nullptr;//内容结尾(并不是容量的结尾)iterator _end_of_storage = nullptr;//容量结尾
};

1.构造函数

template<class InputIterator>
Vector(InputIterator first, InputIterator last)
{while (first != last){Push_back(*first);first++;}
}

(1).在模板类中再定义模板类,使得能够插入不同容器的值。

2. 拷贝构造的实现

Vector(const Vector<T>& v)//拷贝构造
{for (auto& e : v){Push_back(e);}
}

(1).直接使用范围for遍历一次即可。

3.析构函数

~Vector()
{if (_start){delete[] _start;_start = _finish = _end_of_storage = nullptr;}
}

(1).如果_start不空的话,就使用delete[] 释放空间。并且置空。

 

4.begin() end() 的实现

iterator begin()
{return _start;
}iterator end()
{return _finish;
}const_iterator begin() const
{return _start;
}const_iterator end() const
{return _finish;
}

(1).分为const修饰和不加const修饰,构成了函数重载,begin()返回起始_start即可,end()返回_finsih即可。

5.reserve的实现

void Reserve(size_t n)
{if (n > Capacity()){size_t oldsize = Size();T* tmp = new T[n];for (int i = 0; i < oldsize; i++) {tmp[i] = _start[i];}//memcpy(tmp, _start, Size() * sizeof(T));delete[] _start;_start = tmp;_finish = tmp + oldsize;_end_of_storage = tmp + n;}
}

(1).扩容函数,如果要求的空间大于当前的容量,就要扩容,首先存储当先数据个数Size()到oldsize,然后再开辟一个新空间,然后把_start中的全部数据拷贝到tmp中,然后再把_start释放空间,再将tmp赋值给_start,将_finish指向tmp+oldsize的位置。_end_of_storage指向tmp+n的位置。

6.size和capacity的实现

size_t Size()
{return _finish - _start;
}size_t Capacity()
{return _end_of_storage - _start;
}

(1).Size为vector中数据个数,所以直接返回_finish(最后一个数据的地址)减start(第一个数据的地址)即可。

(2).Capacity为vector中容量大小,所以直接返回_end_of_storage(容量的最后一个地址)减start(第一个数据的地址)即可。

7.push_back的实现

void Push_back(const T& x)
{if (_finish == _end_of_storage) // 扩容{Reserve(Capacity() == 0 ? 4 : Capacity() * 2);}*_finish = x;++_finish;
}

(1).push_back前要检查是否需要扩容,这里选择二倍扩容。

(2).直接将*_finish(元素的最后一个位置的下一个位置)赋值为x。再将_finish自加,使其移动到空位置,方便下次赋值。

8.pop_back的实现

void Pop_back()
{assert(!empty());--_finish;
}

(1).首先判断是否为空,如果为空就断言。

(2).直接将_finish自减即可。

9.empty的实现

bool empty()
{return _start == _finish;
}

(1).判断_start 和 _finish是否相等即可,如果相等就为空,否则为不空。

10.insert的实现

iterator insert(iterator pos, const T& x)
{assert(pos >= _start);assert(pos <= _finish);if (_finish == _end_of_storage) // 扩容{size_t len = pos - _start; // 解决迭代器失效Reserve(Capacity() == 0 ? 4 : Capacity() * 2);pos = _start + len; // 解决迭代器失效}iterator end = _finish - 1;while (end >= pos) // 迭代器失效问题已经扩容了,但是pos还是指向原来的旧空间 野指针{*(end + 1) = *end;end--;}*pos = x;++_finish;return pos;
}

(1).大致思路为把要插入位置(pos)之后的全部向后移动一位,然后再将pos位置赋值为要插入的元素。

(2).要想插入,首先判断是否需要扩容。

(3).定义一个迭代器end,存储vector中最后一个元素的位置,然后循环判断(end >= pos),每次成立时,就把end+1处赋值为end的元素,然后将end自减。退出循环后,直接将*pos赋值为x并把_finish自加即可。

11.erase的实现

void erase(iterator pos)
{assert(pos >= _start);assert(pos <= _finish);iterator it = pos + 1;while (it != end()){*(it - 1) = *it;++it;}--_finish;
}

(1).大致思路为将pos位置之后的全部元素都向前移动一个位置,最后将_finish自减即可。

12.resize的实现

void resize(size_t n, T val = T())
{// n<size// size<n<capacity// n>capaciityif (n < Size()){_finish = _start + n;}else{Reserve(n);while (_finish < _start + n){*_finish = val;++_finish;}}
}

(1).resize为对字符串大小做改变,当n<size时,就会对当前字符串缩减,其余情况为reserve。

13.clear的实现

void clear()
{_finish = _start;
}

(1).直接将_finish=_start即可。

14.swap的实现

void swap(Vector<T>& v)
{std::swap(_start, v._start);std::swap(_finish, v._finish);std::swap(_end_of_storage, v._end_of_storage);
}

(1).直接交换即可。

14. []重载

T& operator[](size_t i)
{return _start[i];
}const T& operator[](size_t i) const
{return _start[i];
}

(1).由于_start为顺序表,所以直接返回顺序表的值即可。

15.=重载

//方法一:Vector<T>& operator=(const Vector<T>& v)
{if (this != &v){clear();Reverse(v.Size());for (auto& e : v){Push_back(e);}}return *this;
}//方法二:Vector<T>& operator=( vector<T> v){swap(v);return *this;}

(1).有两种方法,第一种方法为先清空_start,然后再对_start重新扩容,扩容置与v相等,然后遍历v,把v中的元素按个插入_start。

(2).方法二:要进行传值传参,不能用传址传参,然后直接交换即可,这样_start就成了v了,由于v为传值传参,并不受影响。

16. Vector类中的private

private:iterator _start = nullptr;//缺省iterator _finish = nullptr;//缺省iterator _end_of_storage = nullptr;//缺省

二,源码

#pragma once
#include <iostream>
#include <vector>
#include <assert.h>
#include<algorithm>namespace hhc
{template <class T>class Vector{public:typedef T* iterator;typedef const T* const_iterator;Vector(){}Vector(const Vector<T>& v)//拷贝构造{for (auto& e : v){Push_back(e);}}~Vector(){if (_start){delete[] _start;_start = _finish = _end_of_storage = nullptr;}}iterator begin(){return _start;}iterator end(){return _finish;}const_iterator begin() const{return _start;}const_iterator end() const{return _finish;}void Reserve(size_t n){if (n > Capacity()){size_t oldsize = Size();T* tmp = new T[n];for (int i = 0; i < oldsize; i++) {tmp[i] = _start[i];}//memcpy(tmp, _start, Size() * sizeof(T));delete[] _start;_start = tmp;_finish = tmp + oldsize;_end_of_storage = tmp + n;}}size_t Size(){return _finish - _start;}size_t Capacity(){return _end_of_storage - _start;}void Push_back(const T& x){if (_finish == _end_of_storage) // 扩容{Reserve(Capacity() == 0 ? 4 : Capacity() * 2);}*_finish = x;++_finish;}bool empty(){return _start == _finish;}void Pop_back(){assert(!empty());--_finish;}void insert(iterator pos, const T& x){assert(pos >= _start);assert(pos <= _finish);if (_finish == _end_of_storage) // 扩容{size_t len = pos - _start; // 解决迭代器失效Reserve(Capacity() == 0 ? 4 : Capacity() * 2);pos = _start + len; // 解决迭代器失效}iterator end = _finish - 1;while (end >= pos) // 迭代器失效问题已经扩容了,但是pos还是指向原来的旧空间 野指针{*(end + 1) = *end;end--;}*pos = x;++_finish;}void erase(iterator pos){assert(pos >= _start);assert(pos <= _finish);iterator it = pos + 1;while (it != end()){*(it - 1) = *it;++it;}--_finish;}void resize(size_t n, T val = T()){// n<size// size<n<capacity// n>capaciityif (n < Size()){_finish = _start + n;}else{Reserve(n);while (_finish < _start + n){*_finish = val;++_finish;}}}void clear(){_finish = _start;}void swap(Vector<T>& v){std::swap(_start, v._start);std::swap(_finish, v._finish);std::swap(_end_of_storage, v._end_of_storage);}template<class InputIterator>Vector(InputIterator first, InputIterator last){while (first != last){Push_back(*first);first++;}}T& operator[](size_t i){return _start[i];}const T& operator[](size_t i) const{return _start[i];}//方法一:Vector<T>& operator=(const Vector<T>& v){if (this != &v){clear();Reverse(v.Size());for (auto& e : v){Push_back(e);}}return *this;}//方法二:Vector<T>& operator=( vector<T> v){swap(v);return *this;}private:iterator _start = nullptr;iterator _finish = nullptr;iterator _end_of_storage = nullptr;};template <class Container>void print_Container(const Container& v){// 没用实例化的类模板里面取东西,编译器不能区分const_iterator是类型还是静态成员变量// 编译器规定不能去没用实例化的模板里面取东西typename Container::const_iterator it = v.begin();auto itt = v.begin(); // 这样也行while (it != v.end()){std::cout << *it << ' ';*it++;}std::cout << std::endl;for (auto num : v){std::cout << num << ' ';}}}

本篇完

相关文章:

C++STL专题 vector底层实现

目录 一&#xff0c; vector的手搓 1.构造函数 2. 拷贝构造的实现 3.析构函数 4.begin() end() 的实现 5.reserve的实现 6.size和capacity的实现 7.push_back的实现 8.pop_back的实现 9.empty的实现 10.insert的实现 11.erase的实现 12.resize的实现 13.clear的实…...

【Linux】装机常用配置

文章目录 1. 下载常用软件包2. 更新yum源3. vim编辑器配置4. 安装C语言和C的静态库&#xff08;换root&#xff09;5. git6. sudo给普通用户提权7. 更新git版本&#xff08;centos默认安装1.8.x&#xff0c;我们更新到2.x&#xff09;8. getch9. json10. 升级gcc版本11. 跨系统…...

oracle库PASSWORD_VERSIONS 对应的加密方式

oracle库PASSWORD_VERSIONS 对应的加密方式 10G DES 11G SHA-1 12C SHA-2-based SHA-512官方文档&#xff1a; https://docs.oracle.com/database/121/DBSEG/authentication.htm#DBSEG487...

分享一个基于微信小程序的乡村医疗上门服务预约平台(源码、调试、LW、开题、PPT)

&#x1f495;&#x1f495;作者&#xff1a;计算机源码社 &#x1f495;&#x1f495;个人简介&#xff1a;本人 八年开发经验&#xff0c;擅长Java、Python、PHP、.NET、Node.js、Android、微信小程序、爬虫、大数据、机器学习等&#xff0c;大家有这一块的问题可以一起交流&…...

切香肠(Sausage)

题目描述 有 n 条香肠&#xff0c;每条香肠的长度相等。我们打算将这些香肠切开后分给 k 名客人&#xff0c;且要求每名客人获得一样多的香肠&#xff0c;且要将所有的香肠分配完&#xff0c;不做保留。 请问最少需要切几刀才能完成&#xff1f;一刀只能切断一条香肠&#xf…...

Session与Cookie以及Cache区别,及应用场景

Session、Cookie和Cache是Web开发中常用的数据存储方式&#xff0c;它们在功能、存储位置和应用场景上有所不同。 一、Session、Cookie和Cache的区别 Session 存储位置&#xff1a;服务器端。功能&#xff1a;通过在服务器上存储唯一的标识符&#xff08;Session ID&#xff…...

Debian | 更换 Gnome 至 Xfce4

Debian | 更换 Gnome 至 Xfce4 更新源 sudo apt update && sudo apt upgrade安装 xfce4 sudo apt install xfce4我选择 lightdm&#xff0c;回车 切换桌面 sudo update-alternatives --config x-session-manager输入 xfce 所在序号&#xff0c;我这里是 3 卸载 …...

在使用JSON过程中遇到的一个空间释放问题

在对完成的模块进行空间访问检查中发现了这个问题&#xff0c;这刚开始接触JSON的使用&#xff0c;也不知道他的内部实现&#xff0c;因此该问题找了好久&#xff0c;终于发现是每个节点创建都会自动开辟空间&#xff0c;因此造成空间未成功释放的错误。 JSON未成功替换节点空间…...

基于ThinkPHP开发的校园跑腿社区小程序系统源码,包含前后端代码

基于ThinkPHP开发的校园跑腿社区小程序系统源码&#xff0c;包含前后端代码 最新独立版校园跑腿校园社区小程序系统源码 | 附教程 测试环境&#xff1a;NginxPHP7.2MySQL5.6 多校版本&#xff0c;多模块&#xff0c;适合跑腿&#xff0c;外卖&#xff0c;表白&#xff0c;二…...

不同专业方向如何在ChatGPT的帮助下完成选题

学境思源&#xff0c;一键生成论文初稿&#xff1a; AcademicIdeas - 学境思源AI论文写作 选择一个合适的论文题目是每个论文写作同学必须面对的重要任务。无论是历史专业、计算机科学专业&#xff0c;还是其他各个领域&#xff0c;找到一个既有研究价值又符合个人兴趣的选题往…...

MathType7.4中文版本功能详解!你的数学公式编辑神器

嘿&#xff0c;亲爱的小伙伴们&#xff0c;今天我要跟大家分享一个超实用的工具——MathType7中文版。作为一个自媒体人&#xff0c;我常常需要编辑各种复杂的数学公式&#xff0c;而这款软件简直就是我的救星&#xff01;接下来&#xff0c;就让我带你们领略一下它的神奇之处吧…...

在 PhpStorm 中为 .java 文件启用语法高亮,需要正确配置文件类型和关联语言。

点击访问我的技术博客https://ai.weoknow.comhttps://ai.weoknow.com 因为我同时使用java和php混编所以在一个项目中如果同时打开IntelliJ IDEA和PhpStorm不符合我完美主义的本性。 捣鼓了一下搞定了 1. 添加文件类型关联 将 .java 文件与 Java 语言支持关联&#xff1a; …...

2024年8月1日(前端服务器的配置以及tomcat环境的配置)

[rootstatic ~]# cd eleme_web/ [rootstatic eleme_web]# cd src/ [rootstatic src]# ls views/ AboutView.vue HomeView.vue [rootstatic src]# vim views/HomeView.vue [rootstatic src]# nohup npm run serve nohup: 忽略输入并把输出追加到"nohup.out" 构建项目…...

基于tcp,html,数据库的在线信息查询系统项目总结

1.项目背景 在线信息查询系统是一种可用于检索和展示各种信息的计算机程序或平台。主要特点包括&#xff1a; 用户接口&#xff1a;通常提供友好的界面&#xff0c;用户可以方便地输入查询条件。 数据存储&#xff1a;系统往往连接到数据库&#xff0c;存储大量信息&#xf…...

P1032 [NOIP2002 提高组] 字串变换

[NOIP2002 提高组] 字串变换 题目背景 本题不保证存在靠谱的多项式复杂度的做法。测试数据非常的水&#xff0c;各种做法都可以通过&#xff0c;不代表算法正确。因此本题题目和数据仅供参考。 本题为搜索题&#xff0c;本题不接受 hack 数据。关于此类题目的详细内容 题目…...

Android 12系统源码_多屏幕(一)多屏幕设备显示Activity

前言 分屏&#xff1a;是指一个屏幕分出多个窗口&#xff0c;分别显示不同应用的界面&#xff0c;这在当前的手机设备中很常见。多屏&#xff1a;是指一个设备存在多个屏幕&#xff0c;这些可能是虚拟屏幕或者实体硬件屏幕&#xff0c;不同的应用同时显示在不同的屏幕中&#…...

如何判断IP地址属于住宅IP还是机房IP

在数字化时代,IP地址作为互联网通信的基础标识&#xff0c;扮演着重要的角色。无论是网络管理、数据分析还是安全监控&#xff0c;正确识别IP地址的类型——尤其是区分是住宅IP还是机房IP&#xff0c;对于确保网络安全、优化网络性能以及合法合规运营具有重要意义。IPIDEA代理I…...

C#TreeView控件应用

1、代码 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms;namespace TestApp…...

计算机网络-数据链路层

基本概念 数据链路和链路 链路&#xff1a;指的是从一个节点到相邻节点的一段物理线路&#xff0c;且中间没有任何其他的交换节点 数据链路&#xff1a;传输数据时&#xff0c;除了一条物理线路&#xff0c;还需要一些必要通信协议来控制这些传输。 数据链路层的三个基本问…...

农场游戏中的时间管理实例

一、准备工作 在Unity中创建承载日期和时间的文本 二、设置游戏的时间戳 using System.Collections; using System.Collections.Generic; using UnityEngine; //标识这个类可以被序列化 [System.Serializable] public class GameTimestamp {// 游戏时间戳的成员变量public in…...

Appium+python自动化(十六)- ADB命令

简介 Android 调试桥(adb)是多种用途的工具&#xff0c;该工具可以帮助你你管理设备或模拟器 的状态。 adb ( Android Debug Bridge)是一个通用命令行工具&#xff0c;其允许您与模拟器实例或连接的 Android 设备进行通信。它可为各种设备操作提供便利&#xff0c;如安装和调试…...

Oracle查询表空间大小

1 查询数据库中所有的表空间以及表空间所占空间的大小 SELECTtablespace_name,sum( bytes ) / 1024 / 1024 FROMdba_data_files GROUP BYtablespace_name; 2 Oracle查询表空间大小及每个表所占空间的大小 SELECTtablespace_name,file_id,file_name,round( bytes / ( 1024 …...

linux arm系统烧录

1、打开瑞芯微程序 2、按住linux arm 的 recover按键 插入电源 3、当瑞芯微检测到有设备 4、松开recover按键 5、选择升级固件 6、点击固件选择本地刷机的linux arm 镜像 7、点击升级 &#xff08;忘了有没有这步了 估计有&#xff09; 刷机程序 和 镜像 就不提供了。要刷的时…...

如何在网页里填写 PDF 表格?

有时候&#xff0c;你可能希望用户能在你的网站上填写 PDF 表单。然而&#xff0c;这件事并不简单&#xff0c;因为 PDF 并不是一种原生的网页格式。虽然浏览器可以显示 PDF 文件&#xff0c;但原生并不支持编辑或填写它们。更糟的是&#xff0c;如果你想收集表单数据&#xff…...

Mysql中select查询语句的执行过程

目录 1、介绍 1.1、组件介绍 1.2、Sql执行顺序 2、执行流程 2.1. 连接与认证 2.2. 查询缓存 2.3. 语法解析&#xff08;Parser&#xff09; 2.4、执行sql 1. 预处理&#xff08;Preprocessor&#xff09; 2. 查询优化器&#xff08;Optimizer&#xff09; 3. 执行器…...

纯 Java 项目(非 SpringBoot)集成 Mybatis-Plus 和 Mybatis-Plus-Join

纯 Java 项目&#xff08;非 SpringBoot&#xff09;集成 Mybatis-Plus 和 Mybatis-Plus-Join 1、依赖1.1、依赖版本1.2、pom.xml 2、代码2.1、SqlSession 构造器2.2、MybatisPlus代码生成器2.3、获取 config.yml 配置2.3.1、config.yml2.3.2、项目配置类 2.4、ftl 模板2.4.1、…...

五子棋测试用例

一.项目背景 1.1 项目简介 传统棋类文化的推广 五子棋是一种古老的棋类游戏&#xff0c;有着深厚的文化底蕴。通过将五子棋制作成网页游戏&#xff0c;可以让更多的人了解和接触到这一传统棋类文化。无论是国内还是国外的玩家&#xff0c;都可以通过网页五子棋感受到东方棋类…...

ui框架-文件列表展示

ui框架-文件列表展示 介绍 UI框架的文件列表展示组件&#xff0c;可以展示文件夹&#xff0c;支持列表展示和图标展示模式。组件提供了丰富的功能和可配置选项&#xff0c;适用于文件管理、文件上传等场景。 功能特性 支持列表模式和网格模式的切换展示支持文件和文件夹的层…...

归并排序:分治思想的高效排序

目录 基本原理 流程图解 实现方法 递归实现 非递归实现 演示过程 时间复杂度 基本原理 归并排序(Merge Sort)是一种基于分治思想的排序算法&#xff0c;由约翰冯诺伊曼在1945年提出。其核心思想包括&#xff1a; 分割(Divide)&#xff1a;将待排序数组递归地分成两个子…...

shell脚本质数判断

shell脚本质数判断 shell输入一个正整数,判断是否为质数(素数&#xff09;shell求1-100内的质数shell求给定数组输出其中的质数 shell输入一个正整数,判断是否为质数(素数&#xff09; 思路&#xff1a; 1:1 2:1 2 3:1 2 3 4:1 2 3 4 5:1 2 3 4 5-------> 3:2 4:2 3 5:2 3…...