当前位置: 首页 > news >正文

【C++】深入理解vector(1):vector的使用和OJ题

目录

 一 vector的介绍

1  什么是vector

2 vector的介绍

二 vector的使用

1 vector的构造

2 没有输入输出流,无法cout,自己写

3 vector扩容问题

4 vector的增删查改

三 vector在OJ中的使用

1 只出现一次的数字

2 杨辉三角


 一 vector的介绍

1  什么是vector

vector这个单词的意思是向量,但是在STL中的使用可以理解为顺序表

string是字符串,vector则是一个改变数据的顺序容器

2 vector的介绍

vector的文本介绍

这段话的意思如下:

代表大小可以改变的数组。
和数组一样,向量的元素存储在连续的内存位置,这意味着可以通过指向元素的常规指针进行偏移来访问其元素,并且访问效率与数组相同。但与数组不同的是,向量的大小可以动态改变,其存储空间由容器自动管理。
在内部,向量使用动态分配的数组来存储元素。当插入新元素时,为了增大数组的大小,可能需要重新分配该数组,这意味着要分配一个新数组并将所有元素移动到新数组中。就处理时间而言,这是一项相对开销较大的任务,因此,向量不会在每次向容器中添加元素时都进行重新分配。
相反,向量容器可能会分配一些额外的存储空间以应对可能的增长,因此容器的实际容量可能会大于严格容纳其元素所需的存储空间(即其大小)。不同的库可以实现不同的增长策略,以平衡内存使用和重新分配的开销,但无论如何,重新分配应该只在大小呈对数增长的间隔发生,这样才能保证在向量末尾插入单个元素的时间复杂度为均摊常数时间(参见 push_back 操作)。


二 vector的使用

先包含头文件:

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<vector>
using namespace std;

1 vector的构造

(constructor)构造函数申明接口说明
vector()(重点)无参构造
vector(size_type n, const value_type& val =
value_type())
构造并初始化n个val
vector (const vector& x); (重点)拷贝构造
vector (InputIterator first, InputIterator last);使用迭代器进行初始化构
void test_vector1()
{vector<int> v1;vector<int> v2(10, 1);vector<int> v3(v2.begin(), v2.end());string s1("xxxxxxxxxxxxx");vector<int> v4(s1.begin(), s1.end());vector<int> v5(v3);//vector<int> v6({ 1,2,3,4,5 });vector<int> v6 = { 1,2,3,4,5 };vector<int> v7 = { 1,2,3,4,5,1,1,1,1,1,1 };
}

该函数展示了 vector<int> 的 6 种初始化方式,覆盖了常见场景:

初始化方式代码示例说明
默认初始化vector<int> v1;创建空 vector,无元素(size() 为 0)。
填充初始化vector<int> v2(10, 1);创建包含 10 个元素的 vector,每个元素值为 1。
迭代器范围初始化vector<int> v3(v2.begin(), v2.end());用另一个容器(v2)的迭代器范围 [begin, end) 初始化,相当于复制 v2 的所有元素(v3 与 v2 内容相同)。
跨容器迭代器初始化vector<int> v4(s1.begin(), s1.end());用 string 的迭代器范围初始化(string 本质是字符序列),每个字符的 ASCII 码会被转换为 int 存储(例如 'x' 的 ASCII 码是 120,所以 v4 的元素全为 120)。
拷贝构造初始化vector<int> v5(v3);用另一个 vector(v3拷贝初始化v5 与 v3 元素完全相同。
初始化列表初始化vector<int> v6 = {1,2,3,4,5};C++11 新增,用初始化列表 {} 直接指定元素,最直观(等价于 vector<int> v6({1,2,3,4,5});)。

2 没有输入输出流,无法cout,自己写

我们需要自己写一个print函数,来完成流提取和流输出

void Print(const vector<int>& v)
{for (size_t i = 0; i < v.size(); i++){cout << v[i] << " ";}cout << endl;
}

在 vector<int> 中,<int> 表示模板参数,用于指定 std::vector 容器所存储的元素类型。这里的 <int> 说明这个 vector 只能存储 int(整数)类型的元素。

我们也可以用范围for来写

	//范围forfor (auto e : v){cout << e << " ";}cout << endl;

for (auto e : v) 表示 “对于容器 v 中的每个元素,依次赋值给变量 e,执行循环体”。

3 vector扩容问题

void test_vector2()
{vector<int> v1;const int n = 100;size_t old = v1.capacity();for (size_t i = 0; i < n; i++){v1.push_back(i);if (old != v1.capacity()){cout << v1.capacity() << endl;old = v1.capacity();}}
}

我们发现,在Vs下,扩容是以1.5倍增长,而在g++下,扩容是以2倍增长

如果已经确定vector中要存储元素大概个数,可以提前将空间设置足够,这样就可以避免边插入边扩容导致效率低下

void test_vector2()
{vector<int> v1;const int n = 100;v1.reserve(n);size_t old = v1.capacity();size_t begin = clock();for (size_t i = 0; i < n; i++){v1.push_back(i);if (old != v1.capacity()){cout << v1.capacity() << endl;old = v1.capacity();}}
}

4 vector的增删查改

接口使用示例功能效果注意要点
push_backvector<int> v; v.push_back(10);在 vector 末尾添加元素 10,若容量不足会扩容,导致 size 加 1。扩容时可能重新分配内存,使所有迭代器失效;元素是拷贝或移动(依元素类型和 C++ 版本)。
pop_backvector<int> v{1,2,3}; v.pop_back();删除 vector 末尾的元素 3,size 减 1。不能对空 vector 调用,否则行为未定义;只删除元素,不释放内存(容量不变)。
findvector<int> v{1,2,3}; auto it = find(v.begin(), v.end(), 2);在 v.begin() 到 v.end() 范围内查找值为 2 的元素,返回指向该元素的迭代器,若找不到返回 v.end()属于算法库函数,需包含 <algorithm>;只支持顺序查找,时间复杂度 O (n)。
insertvector<int> v{1,3}; v.insert(v.begin() + 1, 2);在 v 的第 2 个位置(下标为 1)插入元素 2,size 加 1。插入位置及之后的元素后移,若容量不足会扩容,导致插入点到末尾的迭代器失效;元素是拷贝或移动。
erasevector<int> v{1,2,3,4}; v.erase(v.begin() + 1);v.erase(v.begin(), v.begin() + 2);第一个示例:删除下标为 1 的元素 2;第二个示例:删除从下标 0 到 1 的元素 12被删元素之后的迭代器失效;返回指向下一个元素的迭代器;只删除元素,不释放内存。
swapvector<int> v1{1,2}, v2{3,4}; v1.swap(v2);交换 v1 和 v2 的数据空间,v1 变为 {3,4}v2 变为 {1,2}是高效操作,仅交换内部指针等,时间复杂度 O (1);swap 后迭代器仍有效,但指向另一容器的元素。
operator[]vector<int> v{1,2,3}; int num = v[1]; v[0] = 10;像数组一样,通过下标 1 获取元素 2;通过下标 0 将元素修改为 10

我们来模拟实现一下:

void test_vector3()
{vector<int> v1 = {1, 2, 3, 4, 5};v1.push_back(6);Print(v1);  // 输出:1 2 3 4 5 6 v1.insert(v1.begin(), 0);  // 在迭代器 v1.begin() 位置(头部)插入 0Print(v1);  // 输出:0 1 2 3 4 5 6 v1.insert(v1.begin() + 3, 0);  // 在下标为 3 的位置前插入 0Print(v1);  // 输出:0 1 2 0 3 4 5 6v1.erase(v1.begin());  // 删除迭代器 v1.begin() 指向的元素(头部的 0)Print(v1);  // 输出:1 2 0 3 4 5 6 v1.erase(v1.begin() + 3);  // 删除下标为 3 的元素(值为 3)Print(v1);  // 输出:1 2 0 4 5 6 
}

注意:

和string一样,vector也只有尾插和尾删,没有头插和头删,因为要挪动数据,效率太。

如果要头插、或者头删和string一样,用insert和erase(如上述代码所示)。


三 vector在OJ中的使用

1 只出现一次的数字

力扣链接:只出现一次的数字

解题思路:

利用异或运算的性质:

  • 任何数和 0 进行异或运算,结果还是这个数本身,即 a⊕0=a。
  • 任何数和它本身进行异或运算,结果是 0,即 a⊕a=0。
  • 异或运算满足交换律和结合律,即 a⊕b⊕a=b⊕(a⊕a)=b⊕0=b。

因为数组中除了一个元素只出现一次,其余每个元素都出现两次,所以将数组中所有元素依次进行异或运算,最后剩下的结果就是那个只出现一次的元素。

我们来演示一下:

举个具体的例子,比如数组是 [4,1,2,1,2]

  • 一开始 value = 0
  • 第一次异或:0 ^ 4 = 4value 变成 4
  • 第二次异或:4 ^ 1 = 5value 变成 5
  • 第三次异或:5 ^ 2 = 7value 变成 7
  • 第四次异或:7 ^ 1 = 6value 变成 6
  • 第五次异或:6 ^ 2 = 4value 变成 4

你看,最后 value 就是 4,也就是数组中只出现一次的那个数

但是有uu可能有疑问:为什么4和1异或之后变成了5:

初始时 value = 0(二进制是 0000)。

第一次异或:value ^ 4

  • 4 的二进制是 0100
  • 0000 ^ 0100 = 0100(也就是十进制的 4),所以此时 value = 4

第二次异或:value ^ 1(此时 value 是 4,即 0100

  • 1 的二进制是 0001
  • 逐位异或:
    • 第 1 位(从右数,最低位):0 ^ 1 = 1
    • 第 2、3 位:0 ^ 0 = 01 ^ 0 = 1
    • 第 4 位及以上:0 ^ 0 = 0
  • 结果二进制是 0101,也就是十进制的 5。所以此时 value 变成 5

代码实现如下:

class Solution {
public:int singleNumber(vector<int>& nums) {int value=0;for(auto i :nums){value ^=i;cout<<endl;}return value;}
};

2 杨辉三角

是一个不规则的二维数组,每一行的第一个和最后一个都是1

思路一:

用C语言实现。但是用C语言实现就需要开辟二维数组,而且还是指针数组,就会很麻烦

思路二:用vector解决

那用vector怎么表示二维数组呢?vector<vector<int>>

代码实现如下:

class Solution {
public:vector<vector<int>> generate(int numRows) {vector<vector<int>> vv;//定义行vv.resize(numRows,vector<int>());//定义列for(size_t i = 0;i < numRows;++i){vv[i].resize(i + 1,1);//1}for(size_t i = 2;i < vv.size();++i)//第0、1行的都不需要处理,1{for(size_t j = 1;j < vv[i].size() - 1;++j){vv[i][j] = vv[i-1][j] + vv[i-1][j-1];}}return vv;}
};

http://www.dtcms.com/a/496141.html

相关文章:

  • 前端最新Vue2+Vue3基础入门到实战项目9-10
  • UC3842/3845/2842/2845 软启动
  • 免费推广产品的网站年报申报入口官网
  • 做网站答辩三网合一营销型全网站
  • (定时任务)@Scheduled 到 XXL-Job:两种定时任务机制的核心区别
  • 【VSCode】Visual Studio Code 2024安装包及安装教程 (附所有版本下载)
  • java17中,使用原生url connection的方式去创建的http链接,使用的是http1.1还是2.0?
  • 无人机激光避障技术概述
  • 网站空间带宽t型布局网站的样子
  • 【测试】Web安全测试与自动化筛查
  • 上海黄浦 网站建设wordpress图床首页无缩略图
  • 免费手机建站平台杭州最大定制app开发公司
  • asp做的网站后台怎么进去wordpress文章推送公众号
  • Scrapy vs Requests:什么时候该用哪个爬虫框架?
  • 网站建设的步骤是什么赣州58同城网
  • 我的钢铁网网站架构jsp语言做网站
  • JavaSE基础——第十一章 常用类(一)
  • 建设网站托管费用wap手机网站描述正确的是
  • linux问题定位之寄存器篇
  • axios 的二次封装
  • linux系统编程(十②)RK3568 socket之 TCP 客户端的实现
  • 网站如何提交关键词asp网站只能打开首页
  • 门店管理网站建设wordpress 爬虫 插件
  • 提供一些准备Java八股文面试的建议
  • 详细聊一下G1垃圾回收器
  • 刷死粉网站推广c 微信小程序开发教程
  • 网站建设归工商局管还是工信局管龙游网站制作
  • MTK Router 改成抓包机器
  • 对新网站做seo大概需要多久wordpress 微网站模板
  • Vue Router 路由管理完全指南:从入门到精通前言