C++入门篇8---vector

news2024/11/24 4:34:53

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

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

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

相关文章

ad+硬件每日学习十个知识点(33)23.8.13 (导出gerber)

文章目录 1.第一次制造输出2.第二次制造输出3.第三次制造输出 1.第一次制造输出 答&#xff1a; 2.第二次制造输出 答&#xff1a; 3.第三次制造输出 答&#xff1a;

企业计算机服务器中了Devos勒索病毒怎么办,勒索病毒解密

社会在发展&#xff0c;科技在进步&#xff0c;企业的生产也得到了很大改善&#xff0c;但是随着网络技术的不断发展&#xff0c;越来越多的企业遭到的网络安全威胁开始增多&#xff0c;其中较为明显的就是勒索病毒攻击。预防勒索病毒攻击成为日常生活中不可或缺的一部分工作。…

Python—行命令搭建HTTP服务器并外网访问本地SQL Server数据库【无公网IP内网穿透】

在强者的眼中&#xff0c;没有最好&#xff0c;只有更好。我们是移动开发领域的优质创作者&#xff0c;同时也是阿里云专家博主。 ✨ 关注我们的主页&#xff0c;探索iOS开发的无限可能&#xff01; &#x1f525;我们与您分享最新的技术洞察和实战经验&#xff0c;助您在移动…

MySQL中事务特性以及隔离机制

目录 一、什么是事务 二、事务特性——即ACID特性 三、事务的隔离级别 1、脏读 2、不可重复读 3、幻读 Read uncommitted&#xff1a; Read committed: Repeatable read: Serializable&#xff1a; 一、什么是事务 事务&#xff08;Transaction&#xff09;——一个最…

小程序用户隐私新规,微信小程序开发者需满足新要求

微信公众平台运营中心最新公告指出&#xff0c;从2023年9月15日开始&#xff0c;涉及处理用户个人信息的小程序开发者需要满足新要求。开发者须主动同步用户同意并遵守小程序的隐私保护指引和其他信息处理规则&#xff0c;方可调用微信提供的隐私接口。 并且&#xff0c;在确认…

第四章,向量组,1-向量组与线性组合、线性表示

第四章&#xff0c;向量组&#xff0c;1-向量组与线性组合、线性表示 向量方程向量与向量组向量向量组 线性组合与线性表示线性组合 线性表示定理定义 多表多&#xff08;单向&#xff09;定理推论 定义 等价&#xff08;多表多&#xff1a;双向&#xff09; 知识回顾 玩转线性…

用免费Leangoo敏捷看板工具进行可视化的缺陷跟踪管理

用Leangoo敏捷看板进行可视化的缺陷跟踪管理 缺陷管理通常关注如下几个方面&#xff1a; 1. 缺陷的处理速度 2. 缺陷处理的状态 3. 缺陷的分布 4. 缺陷产生的原因 使用Leangoo敏捷看板我们可以对缺陷进行可视化的管理&#xff0c;方便我们对缺陷的处理进展、负责人、当前…

转行软件测试四个月学习,第一次面试经过分享

我是去年上半年从销售行业转行到测试的&#xff0c;从销售公司辞职之后选择去培训班培训软件测试&#xff0c;经历了四个月左右的培训&#xff0c;在培训班结课前两周就开始投简历了&#xff0c;在结课的时候顺利拿到了offer。在新的公司从事软件测试工作已经将近半年有余&…

云渲染效果不对?云渲染前的四个细节表明你的问题出在这里!

云渲染针对3D渲染行业&#xff0c;帮助本地电脑解决渲染慢的问题&#xff0c;大幅提高设计师的工作效率。但小编发现&#xff0c;有不少小伙伴在使用云渲染时&#xff0c;出现了渲染效果不对或丢失的问题&#xff0c;根据小伙伴们的问题和我们创意云云渲染平台给出的解决方案&a…

vue之动态表单(优化)

代码资源在这儿 ↑ vue之动态表单优化 vue2js动态表单优化vue3ts动态表单优化 vue2js动态表单优化 效果图 目录结构 五个文件的完整代码: 以下是App.vue <template><div><router-view></router-view><Formpage /></div> </templa…

【数据结构】栈与队列

1 栈 1.1 栈的概念及结构 栈&#xff1a;一种特殊的线性表&#xff0c;其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶&#xff0c;另一端称为栈底。栈中的数据元素遵守后进先出 LIFO (Last In First Out) 的原则。 压栈&#xff1a;栈…

java中右移>>和无符号右移>>>的区别

public static void main(String[] args) {byte[] dest new byte[2];dest[0] 0x15; //0001 0101dest[1] (byte) 0xfb;//1111 1011System.out.println((dest[0] >> 4) & 0xff);//右移 应该是0000 0001 十进制结果显示1 结果也是1&#xff0c;正确System.out.printl…

【小练习】交互式网格自定义增删改错误记录及解决(进行中)

经过之前的学习&#xff0c;已经能创建简单的交互式网格并设置自定义增删改按钮&#xff0c;但是实现上还是存在一些问题&#xff0c;来完善优化一下。 首先是修改&#xff0c;正常修改都会弹出修改框&#xff0c;里面是之前存储的信息&#xff0c;根据实际需要对其进行修改&a…

小程序多图片组合

目录 子组件 index.js 子组件 index.wxml 子组件 index.wxss 父组件引用&#xff1a; 子组件&#xff1a;preview-image 子组件 index.js Component({properties: {previewData: {type: Array,default: [],observer: function (newVal, oldVal) {console.log(newVal, ol…

AppStream下载元数据失败

错误&#xff1a;为仓库 AppStream 下载元数据失败 : Cannot prepare internal mirrorlist: No URLs in mirrorlist 目录 一、域名解析 二、CentOS-AppStream.repo 三、CentOS-Base.repo 四、CentOS-Extras.repo 五、rpm更新 一、域名解析 先验证 ping www.baidu.com 不…

【C语言】结构体解谜:拆解数据的力量!

&#x1f341;博客主页&#xff1a;江池俊的博客 &#x1f4ab;收录专栏&#xff1a;C语言—探索高效编程的基石 &#x1f4a1;代码仓库&#xff1a;江池俊的代码仓库 &#x1f3aa;我的社区&#xff1a;GeekHub &#x1f389;欢迎大家点赞&#x1f44d;评论&#x1f4dd;收藏⭐…

9:00面试,9:06就出来了,问的问题实在有点变态。。。

从小厂出来&#xff0c;没想到在另一家公司又寄了。 到这家公司开始上班&#xff0c;加班是每天必不可少的&#xff0c;看在钱给的比较多的份上&#xff0c;就不太计较了。没想到5月一纸通知&#xff0c;所有人不准加班&#xff0c;加班费不仅没有了&#xff0c;薪资还要降40%,…

Shell函数调用

定义一个函数&#xff0c;计算所有参数的和&#xff1a; #!/bin/bashfunction getsum(){local sum0for n in $do((sumn))donereturn $sum }getsum 10 20 55 15 #调用函数并传递参数 echo $?运行结果&#xff1a; 100

STM32 cubemx CAN

接收用到的结构体如下&#xff1a;CAN概念&#xff1a; 全称Controller Area Network&#xff0c;是一种半双工&#xff0c;异步通讯。 物理层&#xff1a; 闭环&#xff1a;允许总线最长40m&#xff0c;最高速1Mbps&#xff0c;规定总线两端各有一个120Ω电阻&#xff0c;闭环…

学习笔记整理-DOM-02-事件监听

一、什么是"事件监听" DOM允许书写JavaScript代码以让HTML元素对事件作出反应什么是"事件": 用户与网页的交互动作当用户点击元素时当鼠标移动到元素上时当文本框的内容被改变时当键盘在文本框中被按下时当网页已加载完毕时… “监听”&#xff0c;顾名思义…