c++的学习之路:13、vector(2)

本章主要是模拟实现vector,文章末附上代码,和源码。

目录

一、STL源码

二、构造与析构

三、迭代器与【】、size、capacity、empty

四、reserve与resize

五、push_back与pop_back

六、insert与erase

七、测试 1

八、代码

九、思维导图


一、STL源码

今天看的是STL30这个源码,他的vector点开是下图这种可以看出他也是调用了几个头文件,上面注释的就是一些开源声明,大概就是说是可以使用、增删查改甚至售卖,做出有用的修改也需要声明。

如下图二可以看出vector的参数是只有三个原生指针,这个就是从图一这里就可以看出是一个typede进行的重定义的。

 他的size,capacity是如下图这样使用的,下面九不一一展示了,源码上传了可以自己看看。

二、构造与析构

如下方代码就是这个构造和析构,这里是放在了我的命名空间中以防和库里面的vector重复,这里是利用了缺省传值,在定义的时候直接赋值为nullptr然后进行一个空的初始化,然后如下方代码中vector(size_t n, const T& val = T())这一句就是利用一个匿名对象进行初始化,因为这样就可以直接使用模板进行构造,因为这样就可以使用不用的类型进行初始化对象,然后又利用了模板参数InputIterator进行初始化,这里就是如上篇文章中可以使用范围进行初始化,这里就是利用迭代器的原理,first就是迭代器的begin,last就是迭代器的end,也就是首和尾,然后进行构造,相当于缺省值的构造,这里面构造是需要开辟空间和插入数据,所以这里先写在这了,代码在后面文章, vector(int n, const T& val = T())有个这个是因为写入的值默认是整形,在构造时会进行隐形类型转换,size_t是无符号整形,需要转化,但是有类模板会优先使用这个就会造成野指针。

namespace ly
{
    template<class T>
    class vector
    {
    public:
        typedef T* iterator;
        typedef const T* const_iterator;

        vector()
        {}

        vector(size_t n, const T& val = T())
        {
            reserve(n);
            for (size_t i = 0; i < n; ++i)
            {
                push_back(val);
            }
        }

        vector(int n, const T& val = T())
        {
            reserve(n);
            for (int i = 0; i < n; ++i)
            {
                push_back(val);
            }
        }

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

        ~vector()
        {
            delete[] _start;
            _start = _finish = _end_of_storage = nullptr;
        }
    private:
        iterator _start = nullptr;
        iterator _finish = nullptr;
        iterator _end_of_storage = nullptr;
    };

}
 

三、迭代器与【】、size、capacity、empty

如下方代码所示,先看迭代器,在上文中就已经重定义了iterator是T*,所以这里begin就是直接返回start的指针,end就是finish,看过源码和之前模拟实现过string就会发现这里很好用,这里也是同样的有const,因为这里需要重载就是因为需要访问const类型的,size就是finish-start就能得出size,同理capacity就是end_of_storage - start,enpty就是判断是否满了,这里就是start等于finish的时候就是满了,【】就是直接访问就可以了,在pos位置进行访问,这里也是如下方代码所示。

        iterator begin()
        {
            return _start;
        }

        iterator end()
        {
            return _finish;
        }

        const_iterator begin() const
        {
            return _start;
        }

        const_iterator end() const
        {
            return _finish;
        }

        size_t size() const
        {
            return _finish - _start;
        }

        size_t capacity() const
        {
            return _end_of_storage - _start;
        }

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

        T& operator[](size_t pos)
        {
            assert(pos < size());
            return _start[pos];
        }

        const T& operator[](size_t pos) const
        {
            assert(pos < size());
            return _start[pos];
        }

四、reserve与resize

这里是和之前模拟实现string的时候差不多,判断容量是否够,不够减扩容,这里因为需要计算—finish地址,所以提前记录了size,然后创建一个空间,然后利用memcpy进行拷贝数据,在把旧的start释放了,在指向新的空间,在把finish和end_of_storage计算出来就好了,resize也是需要判断是否是缩容,缩容并不需要缩容,只需要删除数据就可以了,扩容也就是需要扩容后,再把数据初始化就可以了。

        void reserve(size_t n)
        {
            if (n > capacity())
            {
                size_t 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;
            }
        }

        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;
                }
            }
        }

五、push_back与pop_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;
        }

六、insert与erase

如下方代码,这里实现的思路是先断言,pos位置是在start和finish之间,不是就报错,如果刚好数据满了就进行扩容,这里需要注意的是扩容的时候需要进行计算pos的绝对位置,也就是距离start的长度,在扩容后在进行计算pos位置,然后就是挪动数据与把数据存入,erase就不需要判断相等finish的时候,因为满了也可以删,然后在进行挪动覆盖,这个就是erase的实现。

        iterator insert(iterator pos, const T& val)
        {
            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)
            {
                *(end + 1) = *end;
                --end;
            }
            *pos = val;
            ++_finish;
            return pos;
        }

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

七、测试 1

这里就进行测试一下上面写的代码是否有错,如下图的代码就是测试push_back与pop_back的写发,然后这里也是测试了下迭代器的使用,for的实现就是迭代器。

void Print(const vector<int>& v)
    {
        for (auto vi : v)
        {
            cout << vi << ' ';
        }
        cout << endl;
    }

    void Test1()
    {
        vector<int> v1;
        v1.push_back(1);
        v1.push_back(2);
        v1.push_back(3);
        v1.push_back(4);
        Print(v1);
        v1.pop_back();
        v1.pop_back();
        Print(v1);
    }

 

 这里就是测试了下【】与利用模板进行范围的初始化

void Test2()
    {
        vector<int> v1;
        v1.push_back(1);
        v1.push_back(2);
        v1.push_back(3);
        v1.push_back(4);
        Print(v1);
        vector<int> v2(v1.begin(), v1.end());
        Print(v2);
        for (size_t i = 0; i < v2.size(); i++)
        {
            cout << v2[i] << ' ';
        }
        cout << endl;
    } 

 这里是测试插入和删除,这里利用了find找到1和3进行头插和在3的位置插入,如下方所示。

void Test3()
    {
        vector<int> v1;
        v1.push_back(1);
        v1.push_back(2);
        v1.push_back(3);
        v1.push_back(4);
        Print(v1);
        auto pos = find(v1.begin(), v1.end(), 1);
        v1.insert(pos, 0);
        pos = find(v1.begin(), v1.end(), 3);
        v1.insert(pos, 30);
        Print(v1);
        pos = find(v1.begin(), v1.end(), 0);
        v1.erase(pos);
        pos = find(v1.begin(), v1.end(), 30);
        v1.erase(pos);
        Print(v1);
    } 

八、代码

vector.h

#pragma once
#include <iostream>
#include <vector>
#include <assert.h>
using namespace std;namespace ly
{template<class T>class vector{public:typedef T* iterator;typedef const T* const_iterator;vector(){}vector(size_t n, const T& val = T()){reserve(n);for (size_t i = 0; i < n; ++i){push_back(val);}}vector(int n, const T& val = T()){reserve(n);for (int i = 0; i < n; ++i){push_back(val);}}template <class InputIterator>vector(InputIterator first, InputIterator last){while (first != last){push_back(*first);++first;}}~vector(){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;}size_t size() const{return _finish - _start;}size_t capacity() const{return _end_of_storage - _start;}bool empty(){return _start == _finish;}T& operator[](size_t pos){assert(pos < size());return _start[pos];}const T& operator[](size_t pos) const{assert(pos < size());return _start[pos];}void reserve(size_t n){if (n > capacity()){size_t 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;}}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 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;}iterator insert(iterator pos, const T& val){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){*(end + 1) = *end;--end;}*pos = val;++_finish;return pos;}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 = nullptr;iterator _finish = nullptr;iterator _end_of_storage = nullptr;};void Print(const vector<int>& v){for (auto vi : v){cout << vi << ' ';}cout << endl;}void Test1(){vector<int> v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);Print(v1);v1.pop_back();v1.pop_back();Print(v1);}void Test2(){vector<int> v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);Print(v1);vector<int> v2(v1.begin(), v1.end());Print(v2);for (size_t i = 0; i < v2.size(); i++){cout << v2[i] << ' ';}cout << endl;}void Test3(){vector<int> v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);Print(v1);auto pos = find(v1.begin(), v1.end(), 1);v1.insert(pos, 0);pos = find(v1.begin(), v1.end(), 3);v1.insert(pos, 30);Print(v1);pos = find(v1.begin(), v1.end(), 0);v1.erase(pos);pos = find(v1.begin(), v1.end(), 30);v1.erase(pos);Print(v1);}
}

test.cpp

#define _CRT_SECURE_NO_WARNINGS 1
#include "vector.h"int main()
{ly::Test3();
}

 

九、思维导图

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

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

相关文章

FJSP:蜣螂优化算法( Dung beetle optimizer, DBO)求解柔性作业车间调度问题(FJSP),提供MATLAB代码

一、柔性作业车间调度问题 柔性作业车间调度问题&#xff08;Flexible Job Shop Scheduling Problem&#xff0c;FJSP&#xff09;&#xff0c;是一种经典的组合优化问题。在FJSP问题中&#xff0c;有多个作业需要在多个机器上进行加工&#xff0c;每个作业由一系列工序组成&a…

2024.4.3-day08-CSS 盒子模型(溢出显示、伪元素)

个人主页&#xff1a;学习前端的小z 个人专栏&#xff1a;HTML5和CSS3悦读 本专栏旨在分享记录每日学习的前端知识和学习笔记的归纳总结&#xff0c;欢迎大家在评论区交流讨论&#xff01; 文章目录 作业 2024.4.3-学习笔记css溢出显示单行文本溢出显示省略号多行文本溢出显示省…

多态.Java

&#xff08;1&#xff09;什么是多态&#xff1f; 同类型的对象&#xff0c;表现出不同的形态。前者指父类&#xff0c;后者指不同的子类 说简单点&#xff0c;就是父类的同一种方法&#xff0c;可以在不同子类中表现出不同的状态&#xff0c;或者说在不同子类中可以实现不同…

UVA247 Calling Circles 解题报告

UVA247 Calling Circles 解题报告 题目链接 https://vjudge.net/problem/UVA-247 题目大意 如果两个人相互打电话&#xff08;直接或间接&#xff09;&#xff0c;则说他们在同一个电话圈里。例如&#xff0c;a打给b&#xff0c;b打给c&#xff0c;c打给d&#xff0c;d打给a…

10.java openCV4.x 入门-特殊的Mat类汇总(二)

专栏简介 &#x1f492;个人主页 &#x1f4f0;专栏目录 点击上方查看更多内容 &#x1f4d6;心灵鸡汤&#x1f4d6;我们唯一拥有的就是今天&#xff0c;唯一能把握的也是今天建议把本文当作笔记来看&#xff0c;据说专栏目录里面有相应视频&#x1f92b; &#x1f9ed;文…

原型设计模式的学习

哪位大佬帮我看看关于“原型设计模式”的问题 写作原因&#xff1a; 我需要了解原型模式&#xff0c;但网上的说法是&#xff1a;通过一个clone方法来创建对象。然而&#xff0c;这并没有解答关于“效率”的问题&#xff1a; 以下是以怪物游戏和深拷贝为例来说明的&#xff1a;…

Linux 常用指令及其理论知识

个人主页&#xff1a;仍有未知等待探索-CSDN博客 专题分栏&#xff1a;http://t.csdnimg.cn/Tvyou 欢迎各位指教&#xff01;&#xff01;&#xff01; 目录 一、理论知识 二、基础指令 1、ls指令&#xff08;列出该目录下的所有子目录和文件&#xff09; 语法&#xff1a; …

论文阅读——Sat2Vid

Sat2Vid: Street-view Panoramic Video Synthesis from a Single Satellite Image 提出了一种新颖的方法&#xff0c;用于从单个卫星图像和摄像机轨迹合成时间和几何一致的街景全景视频。 即根据单个卫星图像和给定的观看位置尽可能真实地、尽可能一致地合成街景全景视频序列。…

Docker中Mysql报 mbind: Operation not permitted

问题 我们在docker中安装的mysql运行时报 mbind: Operation not permitted mbind: Operation not permitted mbind: Operation not permitted mbind: Operation not permitted mbind: Operation not permitted mbind: Operation not permitted原因 这是Docker的Seccomp安全限…

[leetcode] 25. K 个一组翻转链表

给你链表的头节点 head &#xff0c;每 k 个节点一组进行翻转&#xff0c;请你返回修改后的链表。 k 是一个正整数&#xff0c;它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍&#xff0c;那么请将最后剩余的节点保持原有顺序。 你不能只是单纯的改变节点内部的值…

MySQL(目录)

作者&#xff1a;码农出击 链接&#xff1a;https://www.zhihu.com/question/632989513/answer/3312494291 来源&#xff1a;知乎 著作权归作者所有。 MySQL数据库&#xff08;7天~15天&#xff09; 1、数据存储引擎&#xff1a;InnoDB、myISAM、Memory 2、数据库索引类型及原…

最好用的安卓按钮(3)

属性解释 按钮文字 app:text“床前明月光” 按钮文字颜色 app:textColor“color/color_white” 按钮文字大小 app:textSize“22sp” 按钮背景颜色 app:color_normal“color/color_accent” 0x2 单独设置每个圆角 效果 代码 <top.androidman.SuperButton android:layo…

替换空格(替换特定字符)

&#x1f600;前言 在字符串处理中&#xff0c;经常会遇到需要替换特定字符的情况。本文将介绍一道经典的字符串替换问题&#xff1a;将字符串中的空格替换成 “%20”。我们将探讨一种高效的解决方法&#xff0c;通过倒序遍历字符串来实现原地替换&#xff0c;避免额外空间的开…

也说说Sybase ASE中的空间膨胀及应对方案

前言 直观来讲,数据库是典型的以空间换时间的思路去提高数据检索的效率。我们先把数据“入”进去,组织好,建好索引,都为了什么?相当大一部分只不过是为了最终能快速得到查询的结果。当然这又引发了好多子项,比如,怎么“入”得快而又不发生冲突,怎么在相对少的资源的情…

OpenCV中的模块:三维重建-SFM(2)

接上一篇文章,本篇将介绍SFM模块在windows平台上的编译。与Ubuntu下的过程类似,主要过程也是依赖库的下载、编译及安装,不同点是:与Ubuntu直接安装不同,windows下我们将对库的依赖关系更加清晰。 1. 依赖库的编译 打开相应库的最外层CMakeLists.txt所在的目录,库的编译过…

机器学习_PySpark-3.0.3文本特征提取(TF-IDF)流程

机器学习_PySpark-3.0.3文本特征提取(TF-IDF)流程 本例中 Tokenizer 是用于分词的模块。 本例中 HashingTF().tranform() 函数把词哈希成特征向量, 返回结果是 Vectors.sparse() 类型的。 本例中 IDF 类用于计算给定文档集合的反文档频率, 是一个词普遍重要性的度量 (即: 一…

【RISC-V 指令集】RISC-V 向量V扩展指令集介绍(八)- 向量整数算术指令

1. 引言 以下是《riscv-v-spec-1.0.pdf》文档的关键内容&#xff1a; 这是一份关于向量扩展的详细技术文档&#xff0c;内容覆盖了向量指令集的多个关键方面&#xff0c;如向量寄存器状态映射、向量指令格式、向量加载和存储操作、向量内存对齐约束、向量内存一致性模型、向量…

Linux 内核的构建块:深入探索 C 结构体的应用

Linux 内核的构建块&#xff1a;深入探索 C 结构体的应用 Linux 内核&#xff0c;作为操作系统的中心和基础&#xff0c;承担着调度处理器、管理内存、处理输入/输出&#xff08;I/O&#xff09;等各种底层任务。要实现这些复杂的功能&#xff0c;内核的编写借助了 C 语言强大…

SAP FICO接口-OA-调取SAP供应商明细接口(应付预付明细)开发说明书(包括测试样例、程序代码仅作参考,不保证一定可以运行)

需求说明: 根据OA查询条件查询ZVACDOCAZVACDOCA-BUKRS=查询公司代码; ZVACDOCA- LIFNR=查询供应商代码; ZVACDOCA-BELNR=查询凭证编号; ZVACDOCA-GJAHR=查询会计年度; ZVACDOCA-AWKEY=查询采购发票号*; ZVACDOCA-BLART≠W* ZVACDOCA-AUGBL=空 ZVACDOCA- XREVERSED…

ShrewSoft VPN无法连接.报错failed to attach to key daemon的解决方案

今天突然发现使用的ShrewSoft VPN 软件来连接公司网络。但是连接过程中&#xff0c;报错 “Fail to attach to key daemon” 解决步骤&#xff1a; 1. 重启电脑&#xff0c;可以解决90%问题。 2. 可能和ShrewSoft 相关的服务没有启动有关。 于是检查服务状态。 2.1 按Wind…