C++入门篇8---vector

vecctor是动态顺序表

一、了解vector的相关接口及其功能

1.构造函数相关接口

函数声明功能介绍
vector()无参构造
vector(size_type n,const value_type& val=value_type())构造并初始化n个val
vector(const value& x)拷贝构造
vector(InputIterator first, InputIterator last)使用迭代器进行构造

上面不认识的类型如size_type、value_type等都是被typedef过的,可以根据英文意思直接理解,或者找相关的文档进行查询

void test1()
{
	vector<int> v;
	for (auto x : v)
	{
		cout << x << " ";
	}
	cout << endl;

	vector<int> v1(5, 2);
	for (auto x : v1)
	{
		cout << x << " ";
	}
	cout << endl;

	vector<int> v2(v1);
	//vector<int> v2(v1.begin(),v1.end());和上一行代码等价
	for (auto x : v2)
	{
		cout << x << " ";
	}
	cout << endl;

	string s = "hello world";
	vector<char> v3(s.begin(), s.end());//不同类型的迭代器也能初始化
	for (auto x : v3)
	{
		cout << x << " ";
	}
	cout << endl;
}

2.vector iterator的使用

iterator的使用接口说明
begin()+end()获取第一个数据位置的iterator/const_iterator,获取最后一个数据的下一个位置的iterator/const_iterator
rbegin()+rend()获取第一个数据位置的reverse_iterator/const_reverse_iterator,获取最后一个数据的下一个位置的reverse_iterator/const_reverse_iterator
void test2()
{
	vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(4);
	vector<int>::iterator it = v.begin();
    //注意如果写类型名,那么一定要写正确,如加不加reverse、const一定要写对
    //如果不想写这么长的类型,可以写auto自动类型推导
	while (it != v.end())
	{
		cout << *it << " ";
		it++;
	}
	cout << endl;

	vector<int>::reverse_iterator it1 = v.rbegin();
	while (it1 != v.rend())
	{
		cout << *it1 << " ";
		it1++;
	}
	cout << endl;
}

 3.vector空间增长问题

函数名称接口说明
size获取数据个数
capacity获取容量大小
empty判断是否为空
resize改变vector的size
reserve改变vector的capacity
void test3()
{
	vector<int> v;
	cout << v.size() << endl;
	cout << v.capacity() << endl;
	cout << v.empty() << endl;
	cout << "----------" << endl;
	vector<int> v1(5, 2);
	cout << v1.size() << endl;
	cout << v1.capacity() << endl;
	cout << v1.empty() << endl;
	cout << "----------" << endl;

	//vector<int> v2(v1);
	vector<int> v2(v1.begin(),v1.end());
	cout << v2.size() << endl;
	cout << v2.capacity() << endl;
	cout << v2.empty() << endl;
	cout << "----------" << endl;

	string s = "hello world";
	vector<char>v3(s.begin(), s.end());
	cout << v3.size() << endl;
	cout << v3.capacity() << endl;
	cout << v3.empty() << endl;
}

 结论:构造函数创建对象时,有多少个数据开多少空间

void test4()
{
	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
	int n = sizeof(arr) / sizeof(int);
	vector<int> v(arr, arr + n);//vector迭代器本质就是指针,所以这里传指针没问题
	cout << v.size() << ":" << v.capacity() << endl;

	v.reserve(100);
	v.resize(20);
	cout << v.size() << ":" << v.capacity() << endl;

	v.reserve(50);
	v.resize(5);
	cout << v.size() << ":" << v.capacity() << endl;
}

 结论:resize控制size()的大小,空间不够会扩容,reserve申请预留的空间如果小于已经开出的空间capacity(),则空间大小不变,如果大于,则会扩容(至于扩多大的容,主要看编辑器,但是至少保证空间够用)

4.vector的增删查改

函数名称接口说明
push_back()尾插
pop_back()尾删
find查找(vector没有find成员函数,这个find是算法库中的),如果找到find
insert在pos之前插入val,返回新插入元素位置的迭代器
erase删除pos位置的数据,返回被删除元素的下一个元素位置的迭代器
swap交换两个vector的数据空间
operator[]像数组一样用下标访问数据
void test6()
{
	vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(4);
	for (int i = 0; i < v.size(); i++)
	{
		cout << v[i] << " ";
	}
	cout << endl;

	v.pop_back();
	for (int i = 0; i < v.size(); i++)
	{
		cout << v[i] << " ";
	}
	cout << endl;

	v.insert(v.begin() + 1, 10);
	for (int i = 0; i < v.size(); i++)
	{
		cout << v[i] << " ";
	}
	cout << endl;

	v.erase(v.begin() + 2);
	for (int i = 0; i < v.size(); i++)
	{
		cout << v[i] << " ";
	}
	cout << endl;

	auto itx = find(v.begin(), v.end(), 10);//返回迭代器
	if (itx != v.end())//没找到返回end()
		cout << *itx;
}

 5.迭代器失效(重点)

由于vector的迭代器底层是指针,所以vector迭代器失效本质就是野指针问题

对于vector可能会导致其迭代器失效的操作有

1.在插入元素的过程中,导致扩容,而导致原本的空间被释放,那么在扩容之前获取的迭代器就会失效(这是一个例子,其实只要引发扩容,都可能导致迭代器失效)

2.删除操作,一般来说删除元素不会出现问题,但是如果删除的元素是最后一个元素,那么最后一个元素(即被删除元素位置)的迭代器就会失效

如果没看懂的,可以看看后面对插入删除功能的模拟实现)

以下代码的功能是删除vector中所有的偶数,请问while循环的代码是正确的

void test7()
{
	vector<int> v{ 1, 2, 3, 4 };
	auto it = v.begin();
    
	while (it != v.end())
	{
		if (*it % 2 == 0)
			v.erase(it);
		++it;
	}
	
    while (it != v.end())
	{
		if (*it % 2 == 0)
			v.erase(it);
		else
			++it;
	}

	while (it != v.end())
	{
		if (*it % 2 == 0)
			it = v.erase(it);
		else
			++it;
	}
}

很显然第一个while循环错误,因为删除是将后面的元素整体往前移动,所以删除完成之后,it就已经指向了后一个元素,不需要++,

而第二个while循环逻辑上没有问题,但是不同的编辑器会有不同的结果,在vs上,编辑器会严格检查在可能导致迭代器失效的操作之后使用之前的迭代器,直接报错,而在g++上就不会报错

第三个while循环才是标准的写法,而这也是对迭代器失效问题的解决---为erase函数设置了返回值,返回删除元素后面一个元素的迭代器,这样就确保不会发生迭代器失效的问题了

二、模拟实现vector的基本功能

namespace zxws
{
    template<class T>
    class vector
    {
    public:
        // Vector的迭代器是一个原生指针
        typedef T* iterator;
        typedef const T* const_iterator;

        iterator begin()
        {
            return _start;
        }

        iterator end()
        {
            return _finish;
        }

        const_iterator begin() const
        {
            return _start;
        }

        const_iterator end() const
        {
            return _finish;
        }

        // 构造和析构

        vector()
        {}

        vector(int n, const T& value = T())
        {
            reserve(n);
            while (n--) 
            {
                push_back(value);
            }
        }

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

        vector(const vector<T>& v)
        {
            reserve(v.capacity());
            for (auto& x : v)
            {
                push_back(x);
            }
        }

        vector<T>& operator= (vector<T> v)
        {
            swap(v);
            return *this;
        }

        ~vector()
        {
            if (_start)
            {
                delete[] _start;
                _start = _finish = _endOfStorage = nullptr;
            }
        }

        // capacity

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

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

        void reserve(size_t n)
        {
            if (n > capacity())
            {
                size_t sz = size();
                T* tmp = new T[n];
                if (_start)
                {
                    for (size_t i = 0; i < sz; i++)
                    {
                        tmp[i] = _start[i];
                    }
                    delete[] _start;
                }

                _start = tmp;
                _finish = _start + sz;
                _endOfStorage = _start + n;
            }
        }

        void resize(size_t n, const T& value = T())
        {
            if (n > size())
            {
                reserve(n);
                for (size_t i = size(); i < n; i++)
                {
                    _start[i] = value;
                }
            }
            _finish = n + _start;
        }


        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 push_back(const T& x)
        {
            if (_finish == _endOfStorage)
            {
                reserve(capacity() == 0 ? 4 : capacity() * 2);
            }
            *_finish = x;
            _finish++;
        }

        void pop_back()
        {
            assert(size() > 0);
            _finish--;
        }

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

        iterator insert(iterator pos, const T& x)
        {
            assert(pos >= _start);
            assert(pos <= _finish);
            if (_finish == _endOfStorage)
            {
                size_t l = pos - _start;
                reserve(capacity() == 0 ? 4 : capacity() * 2);
                pos = _start + l;
            }
            iterator it = _finish;
            while (it > pos)
            {
                *it = *(it - 1);
                --it;
            }
            *pos = x;
            _finish++;
            return pos;
        }

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

    private:
        iterator _start = nullptr;// 指向数据块的开始
        iterator _finish = nullptr; // 指向有效数据的尾
        iterator _endOfStorage = nullptr; // 指向存储容量的尾
    };

    void test()
    {
        //vector<int> v;
        vector<int> v(10);
        vector<int> v(10,2);
        //v.push_back(1);
        //v.push_back(2);
        //v.push_back(3);
        //v.push_back(4);
        //for (auto x : v)
        //{
        //    cout << x << " ";
        //}
        //cout << endl;
        //vector<int>v1(v);
        //for (auto x : v1)
        //{
        //    cout << x << " ";
        //}
        //cout << endl;

        string s = "hello world";
        vector<char> s1(s.begin(), s.end());
        for (auto x : s1)
        {
            cout << x << " ";
        }
        cout << endl;
        vector<char> s2;
        s2 = s1;
        for (auto x : s2)
        {
            cout << x << " ";
        }
        cout << endl;
    }

    void test1()
    {
        vector<string>v;
        v.push_back("11111111");
        v.push_back("11111111");
        v.push_back("11111111");
        v.push_back("11111111");
        v.push_back("11111111");
        v.push_back("11111111");
        v.push_back("11111111");
        v.push_back("11111111");
        v.push_back("11111111");

        for (auto x : v)
        {
            cout << x << " ";
        }
        cout << endl;
    }

    void test2()
    {
        vector<int> v;
        v.push_back(1);
        v.push_back(2);
        v.push_back(2);
        v.push_back(3);
        v.push_back(4);
        vector<int>::iterator it = v.begin();
        while(it!=v.end())
        {
            if (*it % 2 == 0)
                it = v.erase(it);
            else
                it++;
        }
        for (auto x : v)
        {
            cout << x << " ";
        }
        cout << endl;

        v.pop_back();
        for (auto x : v)
        {
            cout << x << " ";
        }
        cout << endl;
    }

    void test3()
    {
        vector<int> v;
        v.push_back(1);
        v.push_back(2);
        v.push_back(3);
        v.push_back(4);
        v.push_back(5);
        v.insert(v.begin()+2, 0);
        v.insert(v.end(),0);
        for (auto x : v)
        {
            cout << x << " ";
        }
        cout << endl;
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Git】本地搭建Gitee、Github环境

本地 &#xff08;Local&#xff09; 1、使用命令生成公钥&#xff08;pub文件&#xff09; 1. $ ssh-keygen -t rsa -C "xxxxxxxemail.com" -f "github_id_rsa" 2. $ ssh-keygen -t rsa -C "xxxxxxxemail.com" -f "gitee_id_rsa" …

解读spring中@Value 如何将配置转自定义的bean

实现方式 着急寻求解决方式的猿友先看这块 定义配置转化类 public class UserConverter implements Converter<String, List<User>> {Overridepublic List<User> convert(String config) {if (StringUtils.isEmpty(config)) {return Collections.emptyLis…

数组的详述(1)

1、一维数组的创建和初始化&#xff1a; 数组是一组相同类型元素的集合。 &#xff08;1)创建方式&#xff1a; type_t 是指数组的元素类型 arr_name 数组名 [const_n] 一个常量表达式&#xff0c;用来指定数组的大小 //在c99标准之前&#xff0c;数组的大小必须是常…

普通上班族学Python有用吗?

普通上班族学Python有用吗&#xff1f;对于广大上班族而言&#xff0c;时间和精力主要问题&#xff0c;学习Python编程语言为了能提高工作效率。学Python不是单纯的为了增加知识储备&#xff0c;Python本质上是一个工具和手段&#xff0c;最终目的是要通过它来帮我们解决实际工…

Falco操作系统安全威胁监测利器

原理简介 Falco是一个开源的云原生安全工具&#xff0c;用于检测和防御容器和云原生环境中的安全威胁。它基于Linux内核的eBPF技术&#xff0c;通过监控系统调用和内核事件来实现安全检测和响应。 具体来说&#xff0c;Falco的实现原理如下&#xff1a; 1. 内核模块&#xf…

并发编程系列-Semaphore

Semaphore&#xff0c;如今通常被翻译为"信号量"&#xff0c;过去也曾被翻译为"信号灯"&#xff0c;因为类似于现实生活中的红绿灯&#xff0c;车辆是否能通行取决于是否是绿灯。同样&#xff0c;在编程世界中&#xff0c;线程是否能执行取决于信号量是否允…

添加vue devtools扩展工具+添加后F12不显示Vue图标

前言&#xff1a;在开启Vue学习之旅时&#xff0c;遇到问题两个问题&#xff0c;第一添加不上vue devtools扩展工具&#xff0c;第二添加完成后&#xff0c;F12不显示Vue图标。查阅了很多博客&#xff0c;自己解决了问题&#xff0c;故写此博客记录。如果你遇到和我一样的问题&…

item_get_sales-获取商品销量详情

一、接口参数说明&#xff1a; item_get_sales-获取商品销量详情&#xff0c;点击更多API调试&#xff0c;请移步注册API账号点击获取测试key和secret 公共参数 请求地址: https://api-gw.onebound.cn/taobao/item_get_sales 名称类型必须描述keyString是调用key&#xff08…

算法通过村第三关-数组青铜笔记|单调数组

文章目录 前言单调数组问题搜索插入位置&#xff1a;数组合并问题&#xff1a;总结 前言 提示&#xff1a;本份真诚面对自己、坦然无碍面对他人&#xff0c;就是优雅。 数组中的比较经典性问题: 单调数组问题数组合并问题 单调数组问题 参考例子&#xff1a;896. 单调数列…

vue3+element-plus表格默认排序default-sort失效问题

场景 在使用动态数据渲染的场景&#xff0c;el-table设置默认属性default-sort失效。 原因 el-table的default-sort属性是针对静态数据的&#xff0c;如果是动态数据&#xff0c;default-sort则无法监听到。 案例&#xff1a;静态数据 <template><el-table:data&…

全面拥抱AI时刻来临?基于AI技术助力养猪产仔是否可行?

这两天看到一篇论文&#xff0c;蛮有意思的&#xff0c;技术层面倒没有什么新颖的点&#xff0c;主要是落地应用场景比较贴近现实&#xff0c;文章主要就是应用yolov5来开发构建了一套母猪产仔智能化检测预警模型&#xff0c;从而来降低大型养殖场中人工成本。一起来简单看下吧…

比例电磁铁控制放大器

GP63系列比例电磁铁应用于电液比例控制系统中&#xff0c;与比例控制放大器配套使用共同控制力士(REXROTH)型十通径螺纹比例阀。在额定行程及额定电流范围内&#xff0c;其输出力与输入电流成比例&#xff0c;通过内置反力弹簧&#xff0c;改变了输出力的特性&#xff0c;使系统…

leetcode358周赛

2815. 数组中的最大数对和 核心思想&#xff1a;维护每一个最大的数字的最大值&#xff0c;然后一边更新最大值&#xff0c;一边统计结果。其中求nums中的每一个数的数位最大值可以用map的方法&#xff0c;我自己做的时候是用的%10&#xff0c;感觉map这种方法很巧妙。 2816. …

【Linux】可重入函数 volatile关键字 以及SIGCHLD信号

可重入函数 volatile关键字 以及SIGCHLD信号 一、可重入函数1、引入2、可重入函数的判断 二、volatile关键字1、引入2、关于编译器的优化的简单讨论 三、SIGCHLD信号 一、可重入函数 1、引入 我们来先看一个例子来帮助我们理解什么是可重入函数&#xff1a; 假设我们现在要对…

微软电脑surface键盘无法使用问题解决

昨天下班后&#xff0c;正常关掉电脑&#xff0c;今天来上班发现键盘无法使用了 打人工找到了解决方法 开机->到锁屏页面->使用屏幕键盘输入密码进入电脑 然后右键左下角的win图标 找到设备管理器->键盘 全部右键卸载 再找到设备管理->系统设备 把这个DTX也卸…

母婴即时零售行业数据可视化分析

对新晋父母来说&#xff0c;很多母婴用品如同一位贴心的助手&#xff0c;为他们的宝宝提供温暖和呵护。从婴儿床垫到可爱的拼图玩具&#xff0c;每一件用品都是为宝宝的成长和发展量身定制。对于繁忙的父母们而言&#xff0c;这些用品不仅帮助照顾孩子&#xff0c;更是为他们减…

ISIS技术(第三十七课)

1 分享一下华为官网上的一张地图 官网地址:https://support.huawei.com/hedex/hdx.do?docid=EDOC1000105967&id=ZH-CN_CONCEPT_0000001501534705 2 路由的分类 -直连路由 直接连接的路由,且配置了IP地址之后(在同一网段内),就是直连路由。 -非直连路由 -静态路由…

奥威BI数据可视化工具:报表就是平台,随时自助分析

别的数据可视化工具&#xff0c;报表就只是报表&#xff0c;而奥威BI数据可视化工具&#xff0c;一张报表就约等于一个平台&#xff0c;可随时展开多维动态自助分析&#xff0c;按需分析&#xff0c;立得数据信息。 奥威BI是一款多维立体分析数据的数据可视化工具。它可以帮助…

Hadoop Hbase Hive 版本对照一览

这里写目录标题 一、Hadoop 与 Hbase 版本对照二、Hadoop 与 Hive 版本对照 官网内容记录&#xff0c;仅供参考 一、Hadoop 与 Hbase 版本对照 二、Hadoop 与 Hive 版本对照

10-1_Qt 5.9 C++开发指南_Data Visualization实现数据三维显示

Data Visualization 是 Qt 提供的用于数据三维显示的模块。在 Qt 5.7 以前只有商业版才有此模块&#xff0c;而从Qt5.7 开始此模块在社区版本里也可以免费使用了。Data Visualization 用于数据的三维显示&#xff0c;包括三维柱状图、三维空间散点、三维曲面等。Data Visualiza…