STL-vector的接口使用及模拟实现

news2025/3/1 20:13:41

文章目录

  • vector类的介绍
  • vector类的常用接口介绍
    • 构造相关
      • 无参构造
      • 迭代器区间构造
      • 拷贝构造
    • 容量相关的接口
      • size
      • reserve
      • resize
      • capacity
      • empty
    • 数据访问及遍历相关的接口
      • operator[]
      • begin + end
      • rbegin + rend
    • 修改数据相关的接口
      • push_back
      • pop_back
      • insert
      • erase
  • vector类的模拟实现(含各类接口)

vector类的介绍
vector是STL标准库提供的一个可变大小数组的序列容器的,底层使用的是连续的存储空间,是我们使用STL不可缺少的容器。

vector类的常用接口介绍

构造相关
无参构造:
在这里插入图片描述
作用:可以创建一个空的vector对象。

迭代器区间构造:
在这里插入图片描述
作用:使用容器的迭代器区间来生成一个vector对象,内容和传参的迭代器内容一样,注意传参是迭代器内的数据类型要相同。

拷贝构造:
在这里插入图片描述
作用:用一个已经存在的vector对象来创建一个新的vector对象,内容是相同的。

容量相关的接口
size:
在这里插入图片描述
作用:获取vector对象的数据大小。

reserve:
在这里插入图片描述
作用:为vector对象申请n个空间,如果n小于原本的大小,则不会进行任何操作,reserve只会扩容,不会缩容。

resize:
在这里插入图片描述
作用:将vector对象中是元素个数改为n个,如果n小于当前的元素个数,则会保留前n个元素,超出的部分会被删除,如果n大于当前的元素个数,则会用val填充超出的部分。

capacity:
在这里插入图片描述
作用:获取vector对象的容量大小。

empty:
在这里插入图片描述
作用:判断vector对象是否为空,如果是返回true,不为空返回false。

数据访问及遍历相关的接口
operator[]:
在这里插入图片描述
作用:通过重载了operator[],让我们可以像数组一样用下标的方式去访问数据,并且返回该位置元素的引用,下面是const对象使用的,返回的元素不可以被修改。
begin + end:
在这里插入图片描述
begin作用:获取vector对象中第一个元素的地址
end作用:获取vector对象中最后一个元素的下一个位置的地址
注意:
1、迭代器是STL中通用的遍历容器方式,迭代器是一种行为像指针一样的类型,但是迭代器的底层实现是不是指针不确定,具体看容器的底层实现方式,迭代器的使用方式也很像指针,迭代器++就是访问当前位置的下一个数据,- -(自减)就是前一个。
2、第二个const接口是提供给const对象调用的,普通的对象和const对象的迭代器是不一样的,不能混淆,因为const迭代器是不允许通过迭代器来修改数据的。

修改数据相关的接口
push_back:
在这里插入图片描述
作用:在vector对象的元素尾部插入一个元素。

pop_back:
在这里插入图片描述
作用:在vector对象的元素尾部删除一个元素。

insert:
在这里插入图片描述
作用:接口1是在某个位置之前插入一个val元素,接口2是在某个位置插入n个val元素,接口3是在某个位置,插入另外一段迭代器区间内的数据。

erase:
在这里插入图片描述
作用:接口1是删除某个位置的元素,接口2是删除某段迭代器区间内所有的数据。

vector类的模拟实现(含各类接口)

#include<iostream>
#include<assert.h>
using namespace std;

namespace Lh
{
    template <typename T>
    class vector
    {
    public:
        typedef T* iterator;                     //正向迭代器
        typedef const T* const_iterator;
        
        //普通迭代器
        iterator begin()
        {
            return _start;
        }
        iterator end()
        {
            return _finish;
        }
        //const 迭代器
        const_iterator begin() const
        {
            return _start;
        }
        const_iterator end() const
        {
            return _finish;
        }
        //无参的构造
        vector()
            :_start(nullptr)
            , _finish(nullptr)
            , _end_of_storage(nullptr)
        {}

        //迭代器区间构造
        template <class InputIterator>  //这里要用模板 否则数据的类型只能是自身的类型 被固定了
        vector(InputIterator first, InputIterator last)
        {
            while (first != last)
            {
                push_back(*first);
                ++first;
            }
        }
        //构造函数
        vector(size_t n, const T& val = T())
            :_start(nullptr)
            , _finish(nullptr)
            , _end_of_storage(nullptr)
        {
            reserve(n);
            for (size_t i = 0; i < n; ++i)
            {
                push_back(val);
            }
        }
        //构造函数 防止优先匹配模板
        vector(int n, const T& val = T())
            :_start(nullptr)
            , _finish(nullptr)
            , _end_of_storage(nullptr)
        {
            reserve(n);
            for (int i = 0; i < n; ++i)
            {
                push_back(val);
            }
        }

        //拷贝构造  传统写法
        //vector(const vector<T>& v)
        //{
        //    _start = new T[v.size()];  //这里用size和capacity都可以
        //    //memcpy(_start, v._start, sizeof(T) * v.size());
        //    //这里自定义类型不能使用memcpy 内置类型可以 memcpy也是值拷贝
        //    //如果是自定义类型 又会引发浅拷贝以及析构两次的结果
        //    for (size_t i = 0; i < v.size(); ++i)
        //    {
        //        _start[i] = v._start[i];
        //    }
        //    _finish = _start + v.size();
        //    _end_of_storage = _start + v.size();
        //}

        //交换函数
        void swap(vector<T>& v)
        {
            std::swap(_start, v._start);
            std::swap(_finish, v._finish);
            std::swap(_end_of_storage, v._end_of_storage);

        }
        //拷贝构造 现代写法
        vector(const vector<T>& v)
            :_start(nullptr)
            , _finish(nullptr)
            , _end_of_storage(nullptr)
        {
            vector<T> tmp(v.begin(), v.end());
            swap(tmp);
        }
        //容量
        size_t capacity() const
        {
            return _end_of_storage - _start;
        }
        //Size
        size_t size() const
        {
            return _finish - _start;
        }
        //头部数据
        T& front()
        {
            assert(size() > 0);
            return *_start;
        }
        T& back()
        {
            assert(size() > 0);
            return *(_finish - 1);
        }
        //判断vector是否为空
        bool empty() const
        {
            return _finish == nullptr;
        }
        //operator[]
        T& operator[](size_t pos)
        {
            assert(pos < size());

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

            return _start[pos];
        }

        //尾插
        void push_back(const T& x)
        {
            //空间满了扩容
            if (_finish == _end_of_storage)
            {
                reserve(capacity() == 0 ? 4 : capacity() * 2);
            }
            *_finish = x;
            ++_finish;
        }
        //尾删
        void pop_back()
        {
            assert(_finish > _start);
            --_finish;
        }
        //任意位置插入数据
        iterator insert(iterator pos, const T& x)
        {
            assert(pos >= _start && pos <= _finish);

            if (_finish == _end_of_storage)  //检查容量
            {
                size_t len = pos - _start;   //防止迭代器失效 记录下pos到begin位置的距离
                reserve(capacity() == 0 ? 4 : capacity() * 2);   //扩容后会更换空间 导致pos失效
                pos = _start + len;          //更新下pos
            }
            iterator end = _finish - 1;
            while (end >= pos)               //挪动数据
            {
                *(end + 1) = *end;
                --end;
            }
            *pos = x;
            ++_finish;

            return pos;            //STL规定insert返回新插入位置的迭代器
        }
        //任意位置删除数据
        iterator erase(iterator pos) //stl 规定erase返回删除位置下一个位置迭代器
        {
            assert(pos >= _start && pos < _finish);

            iterator begin = pos + 1;
            while (begin < _finish)  //挪动数据
            {
                *(begin - 1) = *begin;
                ++begin;
            }
            --_finish;

            return pos;   //STL规定erase返回插入位置的迭代器
        }
        //扩容
        void reserve(size_t n)
        {
            if (n > capacity())  //超过了原有容量才扩容
            {
                iterator tmp = new T[n];
                size_t sz = size();
                if (_start)
                {
                    //memcpy(tmp, _start, sizeof(T) * sz);
                    //这里自定义类型不能使用memcpy 内置类型可以 memcpy也是值拷贝
                    //如果是自定义类型 又会引发浅拷贝以及析构两次的结果
                    for (size_t i = 0; i < sz; ++i)
                    {
                        tmp[i] = _start[i];
                    }
                    delete[] _start;
                }
                _start = tmp;
                _finish = _start + sz;
                _end_of_storage = _start + n;
            }
        }
        //
        void resize(size_t n, const T& val = T())
        {
            //n > 原来空间
            if (n > capacity())
            {
                reserve(n);
            }
            //n > 原来数据
            if (n > size())
            {
                //添加数据
                while (_finish < _start + n)
                {
                    *_finish = val;
                    ++_finish;
                }
            }
            else
            {
                _finish = _start + n;
            }
        }

        //赋值重载  现代写法 利用传值传参产生临时对象 来和this 进行交换 传值不会影响实参
        vector<T>& operator=(vector<T> v)
        {
            swap(v);
            return *this;
        }
        //析构
        ~vector()
        {
            delete[] _start;
            _start = nullptr;
            _finish = _end_of_storage = nullptr;
        }
    private:
        iterator _start;
        iterator _finish;
        iterator _end_of_storage;
    };

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

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

相关文章

excel统计函数:应用广泛的动态统计之王OFFSET 下篇

【前言】在上篇文章中&#xff0c;我们了解了OFFSET函数的运算原理和各个参数的作用&#xff0c;并且我们也通过一些OFFSET的案例&#xff0c;了解了它的用途。那么本篇我们继续来看看&#xff0c;OFFSET函数在实际工作中所能起到的强大效果吧。一、高阶应用的思路&#xff08;…

vector使用指南

目录 引言 空间配置器 vector 与 string的一些差异 vector容器与string容器的一些差异 接口介绍——reserve resize接口 shrink_to_fit 接口 operator[ ] 和 at 接口 assign接口 增删查改接口 swap接口 例题讲解 引言 vector实质上就是数据结构的顺序表&#xff0…

数据结构:栈和队列(详细讲解)

&#x1f387;&#x1f387;&#x1f387;作者&#xff1a; 小鱼不会骑车 &#x1f386;&#x1f386;&#x1f386;专栏&#xff1a; 《数据结构》 &#x1f393;&#x1f393;&#x1f393;个人简介&#xff1a; 一名专科大一在读的小比特&#xff0c;努力学习编程是我唯一…

(8)Qt中的自定义信号

目录 自定义信号需要遵循的规则 信号的发送 自定义信号的基本实现 使用一个父子窗口切换的小案例 Qt框架提供的信号在某些特定场景下是无法满足我们的项目需求的&#xff0c;因此我们还设计自己需要的的信号&#xff0c;同样还是使用connect()对自定义的信号槽进行连接。 自…

制造业ERP管理系统解决方案之销售管理

在企业的生存发展中&#xff0c;销售管理起到了重要的作用&#xff0c;它决定着企业发展的提速和效益的提升。做好销售管理工作&#xff0c;不仅可以推动企业资金有效运转&#xff0c;还可以使企业在稳定中高效发展&#xff0c;使企业价值最大化。而在制造企业销售管理中&#…

Leetcode.1658 将 x 减到 0 的最小操作数

题目链接 Leetcode.1658 将 x 减到 0 的最小操作数 题目描述 给你一个整数数组 nums 和一个整数 x 。每一次操作时&#xff0c;你应当移除数组 nums 最左边或最右边的元素&#xff0c;然后从 x 中减去该元素的值。请注意&#xff0c;需要 修改 数组以供接下来的操作使用。 如…

SHELL脚本学习 --- 第八次作业(安全脚本)

SHELL脚本学习 — 第八次作业 题目要求&#xff1a; 将密码输入错误超过4次的IP地址通过firewalld防火墙阻止访问 思路&#xff1a; 首先需要找到ssh密码输入错误超过四次的IP地址&#xff0c;需要到日志文件中找。 该日志文件为/var/log/secure。 找到之后通过正则匹配到密码输…

JavaEE高阶---SpringBoot 统⼀功能处理

一&#xff1a;什么是SpringBoot 统⼀功能处理 SpringBoot统一功能处理是AOP的实战环节。我们主要学习三方面内容&#xff1a; 统一用户登录权限验证&#xff1b;统一数据格式返回&#xff1b;统一异常处理。 二&#xff1a;统一用户登录权限验证 Spring 中提供了具体的实现…

通过后端代理实现Web搜索功能

大家好&#xff0c;才是真的好。 前面我们都在说使用Domino自带的视图搜索功能&#xff0c;这一篇也是&#xff0c;不过不是视图搜索&#xff0c;而是整个Notes数据库搜索&#xff0c;然后再将结果返回给浏览器网页呈现。 前提和前面两篇都是一样的&#xff0c;即Notes应用需…

Java 如何不使用 volatile 和锁实现共享变量的同步操作

前言 熟悉 Java 并发编程的都知道&#xff0c;JMM(Java 内存模型) 中的 happen-before(简称 hb)规则&#xff0c;该规则定义了 Java 多线程操作的有序性和可见性&#xff0c;防止了编译器重排序对程序结果的影响。 按照官方的说法&#xff1a; 当一个变量被多个线程读取并且至…

「数据密集型系统搭建」原理篇|数据类型不怕精挑细选

本篇围绕MySQL数据库的底层存储模型、列类型来聊聊数据库表设计及建模中要注意的事项&#xff0c;剖析最根源的底层物理存储文件&#xff0c;用最真实的数据剖析来证明和解答开发过程中的疑惑。 在一些技术谈资、面试沟通过程中&#xff0c;MySQL特别是我们常用的Innodb存储引擎…

JavaScript 作用域

文章目录JavaScript 作用域JavaScript 作用域JavaScript 局部作用域JavaScript 全局变量JavaScript 变量生命周期函数参数HTML 中的全局变量你知道吗?JavaScript 作用域 作用域可访问变量的集合。 JavaScript 作用域 在 JavaScript 中, 对象和函数同样也是变量。 在 JavaScr…

ONES X 海银财富|以敏捷流程管理,创新金融服务平台

近日&#xff0c;ONES 签约财富管理行业领跑者——海银财富&#xff0c;助力海银财富落地敏捷流程管理&#xff0c;打造从需求到交付的一体化平台&#xff0c;快速接受业务方的反馈&#xff0c;进行金融平台的迭代与优化。海银财富管理有限公司&#xff08;以下简称海银财富&am…

拆机详解:1968年军用集成电路计算机 高级货赢在做工

halo大家好&#xff0c;这里是一天更两篇的Eric。 今天我在网上偶然看到一个拆军用计算机的&#xff0c;正好给你们分享一下。这可是1970年左右为了F4战斗机敌我识别系统打造的&#xff0c;虽说比之前说的Macintosh更加的挤也更大&#xff0c;不过做工够扎实。 上图&#xff…

centos8安装RabbitMQ和erlang

RabbitMQ 消息队列MQ RabbitMQ简称MQ是一套实现了高级消息队列协议的开源消息代理软件&#xff0c;简单来说就是一个消息中间件。是一种程序对程序的通信方法&#xff0c;其服务器也是以高性能、健壮以及可伸缩性出名的Erlang语言编写而成为什么使用MQ 在项目中&#xff0c;…

QSyntaxHighlighter

一、描述 此类用于自定义语法高亮显示规则&#xff0c;是用于实现 QTextDocument 文本高亮显示的基类。 要自定义语法高亮显示&#xff0c;必须子类化 QSyntaxHighlighter 并重新实现 highlightBlock()。此函数将在合适的时机自动被调用。 highlightBlock() 函数将格式设置应…

SOFA Weekly|SOFANews、本周贡献 issue 精选

SOFA WEEKLY | 每周精选 筛选每周精华问答&#xff0c;同步开源进展欢迎留言互动&#xff5e;SOFAStack&#xff08;Scalable Open Financial Architecture Stack&#xff09;是蚂蚁集团自主研发的金融级云原生架构&#xff0c;包含了构建金融级云原生架构所需的各个组件&#…

Rasa 3.x 学习系列-Rasa [3.4.0] - 2022-12-14新版本发布

Rasa 3.x 学习系列-Rasa [3.4.0] - 2022-12-14新版本发布 任何人都可以学习Rasa之优秀Rasa学习资源推荐 欢迎同学们报名Gavin老师的Rasa系列课程,任何人都可以学习Rasa之优秀Rasa学习资源推荐: 1.NLP on Transformers高手之路137课 2 .Rasa 3.X 智能对话机器人案例开发硬核…

五、k8s pod详解

文章目录1 pod介绍1.1 pod 定义2 pod配置2.1 基本配置2.2 镜像拉取2.3 启动命令2.4 环境变量2.5 端口设置2.6 资源配额3 Pod生命周期3.1 创建和终止3.2 初始化容器3.3 钩子函数3.4 容器探测3.5 重启策略4 Pod调度4.1 定向调度4.2 亲和性调度5 污点和容忍5.1 污点&#xff08;Ta…

做短视频必须了解的6个问题,你知道几个答案呢?

做短视频必须了解的6个问题&#xff0c;你知道几个答案呢&#xff1f; 最近好多朋友问了视频运营和创作的问题&#xff0c;把其中六个有代表性的问题和答案汇总在一起&#xff0c;公开给大家&#xff0c;希望对大家有所帮助。 1、账号被限流了怎么办&#xff1f; 随手拍十条…