std : : vector

2023-10-27

一.简介

std::vector 的底层实现通常基于动态数组(dynamic array),它是一种连续分配的内存块,允许元素的快速随机访问。下面是 std::vector 的一些关键特点和底层实现细节:

  1. 连续内存块std::vector 内部使用一块连续的内存块来存储其元素,这使得元素的随机访问非常高效,因为可以通过指针算术运算来访问元素。

  2. 动态大小std::vector 允许动态地增加或减少其大小。当元素数量达到内部分配的容量时,std::vector 会重新分配更大的内存块,并将元素复制到新的内存块中。这种自动内存管理使得向量的大小可以根据需要进行调整,而不需要手动管理内存。

  3. 容量和大小std::vector 有两个重要的属性,即容量(capacity)和大小(size)。

    • 容量是 std::vector 当前内部分配的内存块的大小,通常大于或等于大小。当向量的大小超过容量时,会触发内存重新分配,容量会增加。
    • 大小是 std::vector 中实际存储的元素数量。
  4. 动态内存分配std::vector 使用 newdelete 运算符(或 mallocfree 函数,取决于具体实现)来动态分配和释放内存。当需要重新分配内存时,它会为新的内存块分配内存,然后将元素从旧的内存块复制到新的内存块,最后释放旧内存。

  5. 异常安全std::vector 的实现通常会提供异常安全性,这意味着如果在内存重新分配过程中发生异常,不会导致数据丢失或内存泄漏。这是通过使用临时副本和交换技术来实现的。

  6. 迭代器std::vector 提供了迭代器(iterator)来遍历元素,迭代器通常是指针的封装,可以用于访问 std::vector 中的元素。

  7. 内存效率:由于 std::vector 的元素存储在连续的内存块中,它在内存访问上具有很好的局部性,这有助于提高内存访问效率。

总之,std::vector 是一个非常灵活和高效的容器,它提供了动态数组的功能,使得元素的访问和管理变得非常方便。虽然 std::vector 的大小可以动态增长,但由于内存重新分配的开销,如果需要频繁插入或删除元素,可能需要考虑其他容器类型,如 std::liststd::deque,它们可以更高效地支持插入和删除操作。

扩展:

动态数组(Dynamic Array)是一种数据结构,它是一个连续分配的内存块,用于存储具有相同数据类型的元素。动态数组的大小可以动态增长或缩小,以适应元素的插入和删除操作。

以下是动态数组的主要特点和操作:

  1. 连续内存块:动态数组的元素存储在一块连续的内存块中,这意味着元素的地址在内存中是连续的,这有助于快速随机访问元素。通过索引访问元素的时间复杂度是 O(1)。

  2. 动态大小:动态数组允许在运行时动态增加或减少其大小。这意味着您可以向数组中添加元素或从数组中删除元素,而不需要预先知道数组的大小。这种动态大小的特性使得动态数组非常灵活。

  3. 内存分配:当向动态数组添加元素并且没有足够的内存容量时,动态数组会自动分配更大的内存块,将现有元素复制到新的内存块中,并释放旧的内存块。这个过程称为重新分配(re-allocation)。

  4. 时间复杂度:动态数组的插入和删除操作的时间复杂度取决于插入或删除的位置。在末尾进行插入和删除操作通常是最高效的,时间复杂度为 O(1),因为不需要移动元素。在数组中间进行插入或删除操作可能需要移动后续元素,时间复杂度为 O(n)。

  5. 容量和大小:动态数组具有容量(capacity)和大小(size)两个重要属性。

    • 容量是动态数组内部分配的内存块的大小,通常大于或等于大小。
    • 大小是动态数组中实际存储的元素数量。
  6. 迭代器:动态数组通常提供迭代器(iterator),可以用于遍历数组中的元素。

动态数组是一种非常常见和有用的数据结构,它具有灵活性和高效性的优点。

二.运用场景

std::vector 是 C++ 标准库提供的一个动态数组容器,它在许多不同的场景中都非常有用。以下是一些常见的 std::vector 的运用场景:

  1. 动态数组std::vector 是一种动态数组,它可以根据需要自动增加或减少大小。这使得它成为存储不确定数量元素的首选选择,而不需要预先知道数组的大小

  2. 数据收集std::vector 适用于收集大量数据,例如从文件、网络或用户输入中读取的数据。您可以使用 push_back() 方法轻松添加新数据。

  3. 容器替代std::vector 可以替代 C 数组,因为它提供了更多的功能和安全性。与 C 数组不同,std::vector 知道自己的大小,而且可以动态调整大小。

  4. 迭代访问:如果需要通过索引或迭代器访问元素,并且需要快速随机访问能力std::vector 是一个很好的选择。它的时间复杂度为 O(1)。

  5. 栈和队列:虽然 std::vector 主要设计用于随机访问,但它也可以用作栈(先进后出)或队列(先进先出)。使用 push_back()pop_back() 方法可以将其用作栈,而使用 push_back()erase() 可以将其用作队列。

  6. 算法和数据处理std::vector 与标准库中的各种算法结合使用,可以用于各种数据处理任务,例如排序、查找、筛选、转换等。

  7. 高性能计算:在需要高性能的数值计算领域,std::vector 通常用于存储大量数值数据,例如图形处理、科学计算、模拟等。

  8. 游戏开发:在游戏开发中,std::vector 常用于存储游戏对象、粒子、动画帧等

  9. 数据传输std::vector 可以用于数据传输,例如从文件读取数据到向量,然后将向量传递给其他处理模块。

需要注意的是,虽然 std::vector 在许多情况下非常有用,但在某些特定情况下,其他容器类型(例如 std::liststd::dequestd::setstd::map 等)可能更适合特定的数据结构和操作。因此,在选择容器类型时,需要根据具体的需求和性能要求进行权衡和选择。

三.写个比较器

(一)简单组合

方法一:直接静态函数
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
static bool cmp(const pair<int, int>& a, const pair<int, int>& b) {
    if (a.first == b.first) return a.second < b.second;
    return a.first < b.first;
}
void display(vector<pair<int,int>>ans) { for (auto it : ans) cout << it.first << " " << it.second<<"\t"; }
int main() {
    vector<pair<int, int>>ans = { {1,2},{5,3},{2,5},{2,1},{7,2} };
    display(ans);
    cout << endl;
    sort(ans.begin(), ans .end(), cmp);
    display(ans);
    return 0;
}

方法二:写入结构体
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
struct cmp {
    bool operator()(const pair<int,int>&a,const pair<int,int>&b) {
        if (a.first == b.first) return a.second < b.second;
        return a.first < b.first;
    }
};
void display(vector<pair<int,int>>ans) { for (auto it : ans) cout << it.first << " " << it.second<<"\t"; }
int main() {
    vector<pair<int, int>>ans = { {1,2},{5,3},{2,5},{2,1},{7,2} };
    display(ans);
    sort(ans.begin(), ans .end(), cmp());
    cout << "----------" << endl;
    display(ans);
    return 0;
}

         在使用的时候,cmp() 表示实例化对象,要是不想实例化对象怎么办呢?这个时候我们可以把比较操作定义成静态成员函数,这样就可以通过这个结构体的名称来调用这个函数,而不需要实例化对象。

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
struct numcmp {
    static bool cmp(const pair<int, int>& a, const pair<int, int>& b) {
        if (a.first == b.first) return a.second < b.second;
        return a.first < b.first;
    }
};
void display(vector<pair<int,int>>ans) { for (auto it : ans) cout << it.first << " " << it.second<<"\t"; }
int main() {
    vector<pair<int, int>>ans = { {1,2},{5,3},{2,5},{2,1},{7,2} };
    display(ans);
    cout << endl;
    sort(ans.begin(), ans .end(), numcmp::cmp);
    display(ans);
    return 0;
}

区别:

这两种写法在功能上是等效的,它们都可以用于自定义比较操作,以对pair或其他数据结构进行排序。然而,它们之间有一些细微的区别和优劣势:

  1. 可读性:使用函数指针或函数对象(结构体中的operator())来定义比较操作,通常更易于理解和阅读。函数名可以明确指示比较的目的,而不需要查看结构体的成员。

  2. 灵活性:将比较操作封装在结构体中(函数对象方式)通常更灵活,因为你可以在结构体中存储额外的状态或配置,以影响比较的行为。这对于实现不同的排序方式很有用。

  3. 命名冲突:如果你有多个不同的比较操作,并且它们需要在不同的上下文中使用,将它们放入结构体中可以避免函数名冲突的问题,因为每个结构体都有自己的作用域。函数指针方式可能需要更多的命名空间管理。

  4. 语法:函数指针方式更紧凑,但在语法上可能略显繁琐。函数对象方式需要创建一个结构体并在排序函数中使用括号运算符来调用,这可能看起来有点冗长。

总的来说,选择哪种方式取决于你的需求和个人偏好。如果你只需要一个简单的比较操作,函数指针可能更合适。但如果你需要更复杂的比较逻辑,或者希望更好地组织和封装比较操作,那么使用函数对象(结构体中的operator())可能更好。

(二)对象

  • 一样的思路
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
class student {
public:
    int age;
    string name;
    int height;
    int weight;
    student(int _age, string _name, int _height,int _weight) :age(_age), name(_name), height(_height),weight(_weight) {};
};
struct numcmp {
    static bool cmp(student*a,student*b) {
        if (a->height == b->height) {
            if (a->weight == b->weight) return a->age < b->age;
            return a->weight < b->weight;
        }
        return a->height < b->height;
    }
};
void display(vector<student*>ans) {
    for (auto it : ans)  cout << it->age << " " << it->name << " " << it->height <<" "<<it->weight << "\t\t";
}
int main() {
    student *s1=new student(16, "张三", 175,160);
    student *s2=new student(19, "李四", 175,190);
    student *s3=new student(14, "王五", 160,150);
    vector<student*>ans ;
    ans.emplace_back(s1);
    ans.emplace_back(s2);
    ans.emplace_back(s3);
    display(ans);
    cout << endl;
    sort(ans.begin(), ans .end(), numcmp::cmp);
    display(ans);
    delete s1;//注意资源的释放
    delete s2;
    delete s3;
    return 0;
}

 注意:
  • 当使用new创建对象时,直接对象指针装入vector在堆上创建对象,需要delete释放

  • 当直接使用构造函数创建对象时,需要将对象的地址装入vector,vector中存储的是指向对象的指针。在栈上创建对象
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

std : : vector 的相关文章

  • 在 C# 中使用“using”关键字避免多次处置的最佳实践

    当变量是 IDisposable 时 我们有using关键字来管理处置 但是如果我们在方法中返回值怎么办 using twice StringContent stringToStringContent string str using St
  • 元组在 VS2012 中如何工作?

    Visual Studio 2012 功能 tuples但不是可变参数模板 这是如何完成的 如何在不使用可变模板的情况下实现元组 简而言之 微软做了与之前在 NET 中实现类似元组的数据类型完全相同的事情 创建许多版本 每个版本都有固定数量
  • 是否可以从 C++ 应用程序调用 C# 应用程序?

    我是一名编程学生 现在我已经上了两门 C 课程 这个学期我将参加我的第一门 C 课程 出于好奇 是否可以从 C 应用程序调用 C 应用程序 如果是的话 是否还可以检查运行该程序的计算机是否具有 NET框架 我只是很好奇 我想如果可能的话 这
  • c# 从另一个类中的另一个静态事件引发事件

    需要帮助从另一个班级调用事件 我有已声明事件的课程 public class MxPBaseGridView GridView public event AddNewItemsToPopUpMenuEventHandler AddNewIt
  • MFC CList 支持复制分配吗?

    我在 MSVC 中查找了 CList 定义afxtempl h http www cppdoc com example mfc classdoc MFC AFXTEMPL H html并记录在MSDN http msdn microsoft
  • 在 ASP.NET MVC 中将模型从视图传递到控制器

    我正在 ASP NET MVC 中开发我的第一个应用程序 但遇到了一个我无法解决的问题 即使在阅读了整个互联网之后也是如此 因此 我有几个使用视图模型创建的视图 它们是报告 这些视图模型是根据用户选择标准填充的 我正在尝试构建一种接受模型并
  • 将下拉列表与字典绑定

    我将字典绑定到下拉列表 举例来说 我的字典中有以下项目 Test1 123 Test2 321 我希望下拉文本采用以下格式 Test1 Count 123 Test2 Count 321 我沿着以下路径走 但没有运气 MyDropDown
  • 静态类与类的实例

    我有一个静态类 用于访问我的公共属性 整个应用程序的全局属性 和我在应用程序运行期间使用的方法 例如 我在静态类中设置了一些属性 并且在应用程序运行时我可以从属性中获取值 但我可以使用单例模式创建非静态类并以相同的方式使用它 问题 对于我的
  • 使用 C# 中的 Google 地图 API 和 SSIS 包获取行驶距离

    更新 找到了谷歌距离矩阵并尝试相应地修改我的代码 我在这里收到无效参数错误 return new GeoLocation dstnc uri ToString catch return new GeoLocation 0 0 https 基
  • 子目录中的头文件(例如 gtk/gtk.h 与 gtk-2.0/gtk/gtk.h)

    我正在尝试使用 GTK 构建一个 hello world 其中包括以下行 include
  • 使用 OleDbCommandBuilder 时访问 SQL 语法错误

    我要在 C 中使用 OleDbDataAdapter 在 Access 数据库中插入数据 但收到错误消息INSERT INTO 命令中的语法错误 BackgroundWorker worker new BackgroundWorker Ol
  • 使用多线程进行矩阵乘法?

    我应该使用线程将两个矩阵相乘 有两件事 当我运行程序时 我不断得到 0 我还收到消息错误 对于每个错误 它在粗体行上显示 警告 从不兼容的指针类型传递 printMatrix 的参数1 我尝试打印输出 还要注意 第一个粗体块 这是我解决问题
  • ALTER TABLE ... ADD CONSTRAINT 失败时将事务回滚到保存点

    有没有办法在事务中添加检查约束and如果失败回滚到以前的保存点 而不是回滚整个事务 就我而言 当 ALTER TABLE ADD CONSTRAINT 命令失败时 事务无法回滚到保存点 尝试这样做会引发 InvalidOperationEx
  • 为什么 f(i = -1, i = -1) 是未定义的行为?

    我正在读关于违反评估顺序 http en cppreference com w cpp language eval order 他们举了一个令我困惑的例子 1 如果标量对象上的副作用相对于同一标量对象上的另一个副作用是无序的 则行为未定义
  • 无法在 C# 中为 EventArgs 分配使用派生类型的事件处理程序

    所以我有一个事件声明如下 public event EventHandler OnChangeDetected 然后我有以下处理程序被分配给该事件 myObject OnChangeDetected OnTableChanged 我的理解是
  • C 中使用 getrandom 实现随机浮点数

    我试图生成一个介于 0 和 1 之间的随机浮点数 无论是在 0 1 还是 0 1 对我来说都不重要 网上关于此的每个问题似乎都涉及rand 呼叫 播种time NULL 但我希望能够每秒多次调用我的程序 并每次都获得不同的随机数 这引导我找
  • 浮点字节序?

    我正在为实时海上模拟器编写客户端和服务器 并且由于我必须通过套接字发送大量数据 因此我使用二进制数据来最大化可以发送的数据量 我已经了解整数字节顺序以及如何使用htonl and ntohl为了规避字节顺序问题 但我的应用程序与几乎所有模拟
  • 如何将 int 作为“void *”传递给线程启动函数?

    我最初有一个用于斐波那契变量数组的全局变量 但发现这是不允许的 我需要进行基本的多线程处理并处理竞争条件 但我无法在 pthread 创建中将 int 作为 void 参数提供 我尝试过使用常量指针 但没有成功 由于某些奇怪的原因 void
  • 如果“嵌入式”SQL 2008 数据库文件不存在,如何创建它?

    我使用 C ADO Net 和在 Server Management Studio 中创建的嵌入式 MS SQL 2008 数据库文件 附加到 MS SQL 2008 Express 创建了一个数据库应用程序 有人可以向我指出一个资源 该资
  • C++ Boost ASIO 简单的周期性定时器?

    我想要一个非常简单的周期性计时器每 50 毫秒调用我的代码 我可以创建一个始终休眠 50 毫秒的线程 但这很痛苦 我可以开始研究用于制作计时器的 Linux API 但它不可移植 I d like使用升压 我只是不确定这是否可能 boost

随机推荐

  • HashMap底层原理分析(结合面试问题分析)

    1 为什么HashMap底层数组的容量总是2的幂次方 答 因为hashmap的底层在计算一个entry存放在数组中的索引值的时候 采用哈希值运算 如果经过哈希算法得到的一个哈希值h的后面的二进制表示为 0101 0101 此时的数组的长度l
  • 软件构造总结笔记

    软件构造总结笔记 本笔记依据考试大纲 调整课堂讲义的分点 以知识点分化作为条理 精简原本人课堂笔记 进行总结 GitHub仓库资源 gzn00417 2020Spring Software Construction 文章目录 软件构造总结笔
  • 记一次某src得子域名接管漏洞挖掘

    如下案例是fofa找的 在火线资产里直接搜索关键词html noSuchbucket 可以看到显示如下信息
  • 无损剪切音视频文件的跨平台工具: LosslessCut

    mifi lossless cut Stars 17 3k License GPL 2 0 LosslessCut是一款跨平台的FFmpeg GUI工具 它可以对视频 音频和字幕等相关媒体文件进行快速无损操作 该软件最主要的功能是无损剪切和
  • 初识网络原理

    确定不来看看新出炉的知识 目录 1 网络互连 1 1局域网 1 2广域网 2 网络通信基础 2 1IP地址 2 2端口号 3 认识协议 3 1五元组 3 2协议分层 3 3OSI 7层模型 3 4TCP IP5层 或5层 模型 3 5网络设
  • 请求参数默认值多种实现方式

    文章目录 1 直接赋值 2 使用切面实现默认值 自定义注解 切面类 控制层使用 效果展示 3 使用过滤器Filter实现 自定义请求体 自定义过滤器 1 直接赋值 当前页码 private int pageNum 1 每页条数 privat
  • idea快速清理无效类文件

    1 右击选中的项目 如下图所示 2 在弹出框中输入 unused declaration点击选择 如下图所示 3 弹出如下图所示 点击ok 此时需要一段时间 4 结果如下图所示 5 此时 一个个选中 然后双击 有4种处理模式 如下图所示 S
  • 基于Distflow的最优潮流模型(OPF)--模型推导篇

    开篇 前言 自打上期内容火电机组经济调度建模及求解 基础篇推出以后 有小伙伴留言 不考虑潮流问题的经济调度都是耍流氓 作为一个有文化的流氓 我们尝试着为大家科普潮流计算 对于电力系统而言 潮流计算是一个非常复杂且重要内容 如果我们推文中有什
  • 俞敏洪:与其有钱,不如值钱

    很多人一辈子有两个追求 一个是有钱 一个是值钱 有的人运气好 出生在富贵之家 一出生就像贾宝玉一样嘴里含着玉 有钱就不是问题 但有钱解决不了第二个问题 也就是你本人值不值钱的问题 值钱是个人价值的体现 比如你去找一份工作 人家给你开出百万年
  • 链表 List.h

    链表 List h include list h include
  • Android指纹门锁ESP32项目

    本教程中我向您展示如何使用指纹扫描仪Android手机通过ESP32或ESP8266 Wifi或Arduino wifi模块进行门解锁 要创建此项目 您需要ESP32 中继模块 电磁门锁和Android手机 所需零件 源代码 详情参阅 亚图
  • layUI 使用select选择框无法显示出样式,看不到、等解决方案

    我们在写layui代码时候可能遇到这样的问题 明明代码都是从layui官网上复制下来的 却还是会看不到相应的元素 就比如我昨天遇到的一个BUG 代码如上 但是页面上却没有显示出选择框 选择框这里却依然没有结果出现 这个问题困扰了我几个小时
  • js下载base64格式的图片

    步骤 1 创建一个a标签 2 给a标签创建点击事件 3 将base64数据转为Blob类型 4 将a标签的href指向Blob类型数据 5 触发a标签 代码 template vue qr 组件可以自动将 text绑定的url地址转换为二维
  • 【Python零基础入门篇 · 9】:字典的相关操作

    文章目录 字典 键 值 字典的基本格式 字典的定义 键值对 键的唯一性 字典的常见操作一 增删改查 查看元素 根据键名返回值 删除元素 del clear 修改元素 添加元素 字典中的常见操作二 len 求长度 dict keys dict
  • SQL语句:查询数据表的前n行信息

    每种数据库使用的关键字都不一样 每种数据库使用的关键字都不一样 每种数据库使用的关键字都不一样 SQL Server MS Access 语法 TOP SELECT TOP number percent column name s FROM
  • Java 模拟百度翻译

    相信百度翻译对于大家来说并不陌生 本案例要求编写一个程序模拟百度翻译 用户输入英文之后搜索程序中对应的中文 如果搜索到对应的中文就输出搜索结果 反之给出提示 package demo52 import java util HashMap i
  • sv面向对象:类

    写在前面 开始修炼 类是通过代码怎么体现 实例1 定义一个类 systemverilog绿皮书 例5 1简单的 Transaction类 class Transaction bit 31 0 addr crc data 8 class pr
  • Tomcat配置SSL证书

    本地配置ssl证书 为了更好的再服务器上配置ssl证书 先在本上上熟悉流程 本地不需要类似阿里云的证书 借助java的keytool帮助生成离线的证书 keytool genkey alias ceshi storetype PKCS12
  • MVC和MVVM【区别和详解】

    本篇文章的主要内容是给大家讲解一下MVC与MVVM思想之间的区别 希望能对你有所帮助 他们的区别主要在于MVC中Controller 控制层 变成了MVVM中的viewModel 双向数据绑定 MVVM解决了MVC中需要大量操作DOM所带来
  • std : : vector

    一 简介 std vector 的底层实现通常基于动态数组 dynamic array 它是一种连续分配的内存块 允许元素的快速随机访问 下面是 std vector 的一些关键特点和底层实现细节 连续内存块 std vector 内部使用