C++STL第二篇(vector的原理用法)

这篇具有很好参考价值的文章主要介绍了C++STL第二篇(vector的原理用法)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

vector

vector的数据安排以及操作方式,与array非常相似,两者的唯一差别在于空间的运用的灵活性。Array是静态空间,一旦配置了就不能改变,要换大一点或者小一点的空间,可以,一切琐碎得由自己来,首先配置一块新的空间,然后将旧空间的数据搬往新空间,再释放原来的空间。Vector是动态空间,随着元素的加入,它的内部机制会自动扩充空间以容纳新元素。因此vector的运用对于内存的合理利用与运用的灵活性有很大的帮助,我们再也不必害怕空间不足而一开始就要求一个大块头的array了。

Vector的实现技术,关键在于其对大小的控制以及重新配置时的数据移动效率,一旦vector旧空间满了,如果客户每新增一个元素,vector内部只是扩充一个元素的空间,实为不智,因为所谓的扩充空间(不论多大),一如刚所说,是”配置新空间-数据移动-释放旧空间”的大工程,时间成本很高,应该加入某种未雨绸缪的考虑,稍后我们便可以看到vector的空间配置策略。

C++STL第二篇(vector的原理用法)

Vector维护一个线性空间,所以不论元素的型别如何,普通指针都可以作为vector的迭代器,因为vector迭代器所需要的操作行为,如operaroe*, operator->, operator++, operator--, operator+, operator-, operator+=, operator-=, 普通指针天生具备。Vector支持随机存取,而普通指针正有着这样的能力。所以vector提供的是随机访问迭代器(Random Access Iterators).

#include <vector> // 包含 vector 头文件

// 创建一个存储 int 类型的 vector
std::vector<int> intVector;

// 向 vector 尾部添加元素
intVector.push_back(42);

// 获取 vector 的大小(元素个数)
int size = intVector.size();

// 获取 vector 的容量(当前分配的存储空间大小)
int capacity = intVector.capacity();

// 访问 vector 中的元素
int element = intVector[0]; // 使用下标访问

// 遍历 vector 中的所有元素
for (int i = 0; i < intVector.size(); ++i) {
    std::cout << intVector[i] << " ";
}

// 使用迭代器进行遍历
for (auto it = intVector.begin(); it != intVector.end(); ++it) {
    std::cout << *it << " ";
}

以上就是所有vector常用的语法,具体通过下述一个小例子来说。

	vector<int> regina;
	for (int i = 0; i < 10; i++) {
		regina.push_back(i);
		cout << regina.capacity() << endl;

	}
	int* start = &regina[0];
	int* end = &regina[regina.size() - 1];

	for (; start <= end; start++) {
		cout << *start << endl;
	}

C++STL第二篇(vector的原理用法)

Vector所采用的数据结构非常简单,线性连续空间,它以两个迭代器_Myfirst和_Mylast分别指向配置得来的连续空间中目前已被使用的范围,并以迭代器_Myend指向整块连续内存空间的尾端

。所谓动态增加大小,并不是在原空间之后续接新空间(因为无法保证原空间之后尚有可配置的空间),而是一块更大的内存空间,然后将原数据拷贝新空间,并释放原空间。因此,对vector的任何操作,一旦引起空间的重新配置,指向原vector的所有迭代器就都失效了。这是程序员容易犯的一个错误,务必小心。

常用操作

assign(beg, end);//将[beg, end)区间中的数据拷贝赋值给本身。
assign(n, elem);//将n个elem拷贝赋值给本身。
vector&operator=(const vector  &vec);//重载等号操作符
swap(vec);// 将vec与本身的元素互换。
--------
size();//返回容器中元素的个数
empty();//判断容器是否为空
resize(int num);//重新指定容器的长度为num,若容器变长,则以默认值填充新位置。如果容器变短,则末尾超出容器长度的元素被删除。
resize(int num, elem);//重新指定容器的长度为num,若容器变长,则以elem值填充新位置。如果容器变短,则末尾超出容器长>度的元素被删除。
capacity();//容器的容量
reserve(int len);//容器预留len个元素长度,预留位置不初始化,元素不可访问。
-------------
at(int idx); //返回索引idx所指的数据,如果idx越界,抛出out_of_range异常。
operator[];//返回索引idx所指的数据,越界时,运行直接报错
front();//返回容器中第一个数据元素
back();//返回容器中最后一个数据元素
-------------
insert(const_iterator pos, int count,ele);//迭代器指向位置pos插入count个元素ele.
push_back(ele); //尾部插入元素ele
pop_back();//删除最后一个元素
erase(const_iterator start, const_iterator end);//删除迭代器从start到end之间的元素
erase(const_iterator pos);//删除迭代器指向的元素
clear();//删除容器中所有元素

在C++的STL中,capacity()size()vector类的两个成员函数,用于获取vector对象的容量和大小。

  • capacity()函数返回vector对象在不重新分配内存的情况下能够容纳的元素数量。换句话说,capacity()表示vector当前分配的内存空间大小,而不是vector实际包含的元素数量。当vector中的元素数量达到当前容量时,如果需要继续添加元素,vector会分配更大的内存空间,并将原有元素复制到新的内存空间中。
  • size()函数返回vector对象当前包含的元素数量。换句话说,size()表示vector中实际存储的元素数量,而不考虑vector实际分配的内存空间大小。

举个例子,假设你有一个vector对象regina,初始时capacity()可能为10,而size()为0。这意味着regina的内存空间能够容纳10个元素,但实际上它目前并没有存储任何元素。当你向regina中添加元素时,size()会逐渐增加,直到等于capacity(),此时vector可能会重新分配更大的内存空间。

总结一下:

  • capacity():表示vector当前分配的内存空间大小,不考虑实际存储的元素数量。
  • size():表示vector实际存储的元素数量,不考虑分配的内存空间大小。
vector<int> regina;
for (int i = 0; i < 100000; i++) {
	regina.push_back(i);
}

cout << "capacity:" << regina.capacity() << endl;
cout << "size:" << regina.size() << endl;

//此时 通过resize改变容器大小
regina.resize(10);

cout << "capacity:" << regina.capacity() << endl;
cout << "size:" << regina.size() << endl;

//容量没有改变
vector<int>(regina).swap(regina);
/*在创建临时vector对象时,它会使用刚好
足够的内存来存储regina的元素,并且不会有
额外的内存占用。然后通过swap函数,regina
会将自己的内存与临时vector进行交换,
从而达到释放多余内存的目的。*/

cout << "capacity:" << regina.capacity() << endl;
cout << "size:" << regina.size() << endl;

C++STL第二篇(vector的原理用法)

在这段代码中,我们首先向regina中添加了10万个元素,然后调用resize(10)regina的大小改变为10。接着通过创建临时vector对象并与regina交换来释放多余的内存。让我解释一下容量是如何变小的。

  1. 初始状态:
    • 在向regina中添加10万个元素后,capacity()可能会大于或等于10万,因为vector在需要时会分配比实际所需更多的内存,以减少频繁的重新分配和复制。
  2. 调用resize(10)
    • 当调用resize(10)时,regina的大小被改变为10,但它的容量仍然可能保持不变。这是因为resize函数通常只改变vector的大小,而不会改变其容量,除非指定了新的容量值。
  3. 通过临时vector对象和swap释放多余内存:
    • 接着使用了一个巧妙的技巧,创建了临时的vector对象,并通过swap函数释放了regina中多余的内存。这样做会使regina的容量变得刚好足够存储当前的元素数量,没有额外的内存占用。

vector VS valarray VS array

  1. std::vector
    • std::vector 是标准库中最常用的动态数组容器。
    • 它可以动态增长和缩小,即在运行时可以添加或删除元素。
    • vector 内部使用动态内存分配来存储元素,因此可以根据需要动态调整其大小。
    • 支持随机访问,插入和删除操作效率较高。
  2. std::valarray
    • std::valarray 代表值数组,是用于执行数学运算的数组。
    • valarray 提供了一些数学运算函数,如对每个元素进行操作、求平方根、求平均值等。
    • valarray 的设计旨在提供高性能的数学运算,但在某些情况下可能不够灵活。
    • 在实际开发中,valarray 往往被认为是一个在数值计算方面更专业的工具,而不是通用的容器。
  3. std::array
    • std::array 是固定大小的数组容器,其大小在编译时确定。
    • array 在内存中是连续存储的,类似于原生数组,但提供了更多的功能和安全性。
    • array 提供了数组的基本功能,如随机访问、迭代器等,但大小固定,不能动态增长或缩小。
#include <iostream>
#include <vector>
#include <valarray>
#include <array>

int main() {
    // 1. std::vector 例子
    std::vector<int> vec = {1, 2, 3, 4, 5};
    vec.push_back(6); // 添加元素
    for (int i : vec) {
        std::cout << i << " ";
    }
    std::cout << "\n";

    // 2. std::valarray 例子
    std::valarray<int> valarr = {1, 2, 3, 4, 5};
    valarr += 5; // 对每个元素加5
    for (int i : valarr) {
        std::cout << i << " ";
    }
    std::cout << "\n";

    // 3. std::array 例子
    std::array<int, 5> arr = {1, 2, 3, 4, 5};
    for (int i : arr) {
        std::cout << i << " ";
    }
    std::cout << "\n";

    return 0;
}

C++STL第二篇(vector的原理用法)文章来源地址https://www.toymoban.com/news/detail-838297.html

到了这里,关于C++STL第二篇(vector的原理用法)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 第二篇|研究数据哪里来——建筑业

    数据是研究和产业发展的重要基石,然而无论是学者、企业还是研究机构往往都面临着“找数据难”的局面。本期将分享一些查找建筑相关的数据及资料的渠道。希望可以帮大家解决这一难题,有用求收藏求收藏求收藏~ 1.政府机构 可以查找国家、地方政府的建筑行业统计数

    2024年02月14日
    浏览(38)
  • [ 数据结构 -- 手撕排序算法第二篇 ] 冒泡排序

    手撕排序算法系列之:冒泡排序。 从本篇文章开始,我会介绍并分析常见的几种排序,大致包括 插入排序 , 冒泡排序 ,希尔排序,选择排序,堆排序,快速排序,归并排序等。 大家可以点击此链接阅读其他排序算法:排序算法_大合集(data-structure_Sort) 本篇主要来手撕冒

    2024年02月11日
    浏览(38)
  • 数据结构修炼第二篇:顺序表和链表

    第一章 时间复杂度和空间复杂度 第二章 顺序表,列表 第三章 栈和队列 第四章 二叉树 第五章 排序 作者:🎈乐言🎈 简介:🎈大一学生,目前在致力于c/c++/python,高数的学习,有问题尽管问我,关注后私聊! 持续更新专栏:《c进阶》,《数据结构修炼》 🚀 (优质好文持

    2024年02月02日
    浏览(36)
  • 【MySQL进阶之路丨第二篇】数据库的安装与配置

    下载地址:MySQL下载地址 进入网址后,点击 MySQL Community Server : 选择版本: 我们选择历史版本中的5.7.24版本 安装到D盘的MySQL文件夹中 解压后复制bin目录路径 在系统变量的Path中添加bin目录路径 接着在D:SoftwareMySQLmysql-5.7.24-winx64目录下新增加一个配置文件mysql.ini和一个data文

    2024年02月10日
    浏览(33)
  • MySQL篇—通过Clone插件进行本地克隆数据(第二篇,总共三篇)

        在上一篇文章中,我们深入探讨了Clone技术的多种用途,以及使用它所需满足的前提条件。我们也详细分析了Clone存在的限制,并深入了解了其背后的备份原理。今天,我们将继续探索MySQL Clone Plugin的强大功能,Clone其实最重要的就是克隆数据了,包括本地克隆数据和远程

    2024年02月02日
    浏览(29)
  • MySQL数据库进阶第二篇(索引,SQL性能分析,使用规则)

    本篇博客深入详细地介绍了数据库索引的概念和重要性。内容包含:索引的概念和目标、索引的优点与缺点。此外,博客还深入解析了三种主要的索引结构:B-Tree、B+Tree和Hash,提供了详细的结构解析和优化方法,并通过插图进一步增强了理解。 博客的部分内容专注于对B-Tr

    2024年02月21日
    浏览(42)
  • 【夜深人静学数据结构与算法 | 第二篇】后缀(逆波兰)表达式

    目录 前言:  中缀表达式:  后缀表达式: 中缀表达式转后缀表达式: 后缀表达式计算结果: 总结:  计算机在计算四则运算的时候,由于括号以及运算优先级的存在,并不能够很好的处理所有的运算,为了处理这种情况,我们引入了后缀表达式来优化算法。         

    2024年02月13日
    浏览(40)
  • [数据结构 -- 手撕排序第二篇] 一篇带你详细了解希尔排序

    目录 1、常见排序算法 1.1 插入排序基本思想 2、希尔排序 2.1 希尔排序( 缩小增量排序 ) 2.1.1 预排序阶段 2.1.2 插入排序阶段 2.2 单趟希尔排序 2.2.1 思路分析 2.2.2 代码实现 3、希尔排序代码实现 4、希尔排序时间复杂度 5、希尔排序与插入排序效率对比 6、希尔排序特性总结 直接

    2024年02月13日
    浏览(44)
  • 【C++入门】STL容器--vector底层数据结构剖析

    目录  前言  1. vector的使用       vector的构造  vector迭代器  vector空间相关的接口  vector 功能型接口  find  swap  insert  erase 2. vector内部数据结构剖析 reserve  push_back和pop_back size、capacity、empty、operator[ ];  insert和erase resize swap  拷贝构造和赋值重载 构造函数补充  迭代器

    2024年01月25日
    浏览(38)
  • 【C++ STL容器】:vector存放数据以及存放自定义的数据类型

    时不可以苟遇,道不可以虚行。 STL 中最常用的容器为: vector ,暂且把它理解为我们之前学过的数组 Array 。 添加头文件: #include vector 利用内置函数: push_back() 先声明两个迭代器, 一个指向容器中的第一元素 , 一个指向容器中的最后一个元素的下一个位置 然后利用一层

    2024年02月15日
    浏览(44)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包