C++奇迹之旅:vector使用方法以及操作技巧

请添加图片描述

文章目录

  • 📝前言
  • 🌠 熟悉vector
    • 🌉使用vector
  • 🌠构造函数
    • 🌉vector遍历
  • 🌠operator[]
    • 🌉迭代器
  • 🌠Capacity容量操作
    • 🌉 size()
    • 🌉 capacity()
    • 🌉resize()
    • 🌉reserve()
  • 🌠 常用操作符
    • 🌉 push_back
    • 🌉pop_back
    • 🌉 find
    • 🌉 insert
    • 🌉 erase
  • 🚩总结


📝前言

本节我们将学习vector容器的使用和操作,让我们学习起来吧!
库函数网址查询:https://legacy.cplusplus.com/reference/vector/vector/?kw=vector

🌠 熟悉vector

在这里插入图片描述
C++ 标准库中的 std::vector 是一个动态数组容器,能够存储并管理元素的集合。它提供了动态调整大小的能力,并且在底层维护一个连续的存储区域,使得元素可以通过索引进行快速访问。

std::vector 是一个类模板,它的定义如下:

template <class T, class Allocator = std::allocator<T>>
class vector;

模板参数

  • T:向量中存储的元素的类型。
  • Allocator:用于分配内存的分配器类型,默认是 std::allocator<T>

在这里插入图片描述

就像数组一样,向量对其元素使用连续的存储位置,这意味着也可以使用指向其元素的常规指针上的偏移量来访问其元素,并且与数组中的元素一样高效。但与数组不同的是,它们的大小可以动态变化,它们的存储由容器自动处理

在内部,向量使用动态分配的数组来存储其元素。当插入新元素时,可能需要重新分配此数组才能增大大小,这意味着分配一个新数组并将所有元素移动到该数组。就处理时间而言,这是一项相对昂贵的任务,因此,每次将元素添加到容器时,向量都不会重新分配

在这里插入图片描述

相反,矢量容器可能会分配一些额外的存储来适应可能的增长,因此容器的实际容量可能大于包含其元素(即其大小)严格需要的存储。库可以实施不同的增长策略,以平衡内存使用和重新分配之间的平衡,但无论如何,重新分配应该只在大小的对数增长间隔下发生,以便在向量末尾插入单个元素时可以提供摊销的恒定时间复杂度(参见push_back)

因此,与数组相比,向量消耗更多的内存,以换取以有效的方式管理存储和动态增长的能力

在这里插入图片描述
与其他动态序列容器(dequeslistsforward_lists)相比,向量非常有效地访问其元素(就像数组一样),并且相对有效地从其末端添加或删除元素。对于涉及在末尾以外的位置插入或删除元素的操作,它们的性能比其他操作差,并且迭代器和引用的一致性低于列表和forward_lists

🌉使用vector

在这里插入图片描述

成员类型定义
value_type第一个模板参数
allocator_type第二个模板参数 (Alloc)
size_type一个无符号的整数类型,可以表示 difference_type 的任何非负值

🌠构造函数

在这里插入图片描述

std::vector 的四种不同构造函数分别是:

  1. 默认构造函数
explicit vector (const allocator_type& alloc = allocator_type());

这个构造函数创建一个空的 std::vectorallocator_type 是用来分配内存的分配器类型,默认使用 std::allocator<T>,构造函数是 explicit 的,这意味着它不能进行隐式转换或复制初始化。

示例

std::vector<int> v1; // 使用默认分配器创建一个空的 vector
std::vector<int> v2(std::allocator<int>()); // 使用指定的分配器创建一个空的 vector
  1. 填充构造函数
explicit vector (size_type n, const value_type& val = value_type(),
                 const allocator_type& alloc = allocator_type());

这个构造函数创建一个包含 nval 值的 std::vectorsize_type 是一个无符号整数类型,通常是 std::size_tvalue_type 是存储在 std::vector 中的元素的类型, allocator_type 是分配器类型,默认值为 std::allocator<T>

示例

std::vector<int> v1(10); // 创建一个包含 10 个默认值(0)的 vector
std::vector<int> v2(10, 5); // 创建一个包含 10 个值为 5 的 vector
  1. 范围构造函数
template <class InputIterator>
vector (InputIterator first, InputIterator last,
        const allocator_type& alloc = allocator_type());

这个构造函数使用范围 [first, last) 中的元素创建 std::vectorInputIterator 是输入迭代器类型,可以是指向数组的指针、其他容器的迭代器等。

示例

int arr[] = {1, 2, 3, 4, 5};
std::vector<int> v1(arr, arr + 5); // 使用数组中的元素创建 vector
std::list<int> lst = {1, 2, 3, 4, 5};
std::vector<int> v2(lst.begin(), lst.end()); // 使用 list 中的元素创建 vector
  1. 复制构造函数
vector (const vector& x);

这个构造函数使用另一个 std::vector x 的内容创建一个新的 std::vector,它会复制 x 中所有的元素,并且新创建的 std::vector 会有与 x 相同的大小和容量。

示例

std::vector<int> v1 = {1, 2, 3, 4, 5};
std::vector<int> v2(v1); // 使用 v1 中的元素创建 v2

综合测试代码

void test_vector07()
{
    // 默认构造函数
    vector<int>  v1;
    // 遍历 v1 并输出其中的元素,由于 v1 是空的,所以没有任何输出
    for (const auto& e : v1)
    {
        cout << e;
    }
    cout << endl;

    // 填充构造函数
    vector<int> v2(10);
    // 遍历 v2 并输出其中的元素,输出为 "0000000000"
    for (const auto& e : v2)
    {
        cout << e;
    }
    cout << endl;

    // 填充构造函数(带初始值)
    vector<int> v3(10, 3);
    // 遍历 v3 并输出其中的元素,输出为 "3333333333"
    for (const auto& e : v3)
    {
        cout << e;
    }
    cout << endl;

    // 复制构造函数
    vector<int> v5 = { 1, 2, 3, 4, 5 };
    vector<int> v6(v5);
    // 遍历 v5 并输出其中的元素,输出为 "12345"
    for (const auto& e : v5)
    {
        cout << e;
    }
    cout << endl;

    // 范围构造函数
    vector<int> v4(v5.begin() + 1, v5.end() - 2);
    // 遍历 v4 并输出其中的元素,输出为 "23"
    for (const auto& e : v4)
    {
        cout << e;
    }
    cout << endl;
}

在这里插入图片描述

🌉vector遍历

🌠operator[]

在这里插入图片描述

void test_vector08()
{
	std::vector<int> numbers = { 10, 20, 30, 40, 50 };

	// 非 const 访问
	numbers[1] = 25; // 修改第二个元素
	std::cout << "numbers[1]: " << numbers[1] << std::endl; // 输出:25

	// const 访问
	const std::vector<int> const_numbers = { 100, 200, 300, 400, 500 };
	std::cout << "const_numbers[2]: " << const_numbers[2] << std::endl; // 输出:300
	// const_numbers[2] = 350; // 错误:不能修改常量向量
}

在这里插入图片描述

🌉迭代器

在这里插入图片描述
迭代器基本使用方法大致相同,这里讲解基础的两个使用:

  1. begin 函数:
    在这里插入图片描述

    • 作用: 返回指向容器开头的迭代器。
    • 非 const 版本:
      iterator begin();
      
      • 返回类型: iterator,这是一个指向容器第一个元素的迭代器。
      • 用途: 可以用于遍历和修改容器中的元素。
    • const 版本:
      const_iterator begin() const;
      
      • 返回类型: const_iterator,这是一个指向容器第一个元素的常量迭代器。
      • 用途: 可以用于遍历但不能修改容器中的元素。
  2. end 函数:
    在这里插入图片描述

    • 作用: 返回指向容器末尾的迭代器。
    • 非 const 版本:
      iterator end();
      
      • 返回类型: iterator,这是一个指向容器末尾(即最后一个元素的下一个位置)的迭代器。
      • 用途: 通常用于标记迭代的结束。
    • const 版本:
      const_iterator end() const;
      
      • 返回类型: const_iterator,这是一个指向容器末尾的常量迭代器。
      • 用途: 通常用于标记迭代的结束,不能用于修改元素。

例子:

#include <vector>
#include <iostream>

int main() {
    std::vector<int> vec = {1, 2, 3, 4, 5};

    // 非 const 迭代器遍历
    std::cout << "使用非 const 迭代器遍历和修改向量元素:" << std::endl;
    for (std::vector<int>::iterator it = vec.begin(); it != vec.end(); ++it) {
        *it *= 2; // 将每个元素乘以 2
        std::cout << *it << " ";
    }
    std::cout << std::endl;

    // const 迭代器遍历
    std::cout << "使用 const 迭代器遍历向量元素:" << std::endl;
    const std::vector<int> const_vec = {10, 20, 30, 40, 50};
    for (std::vector<int>::const_iterator it = const_vec.begin(); it != const_vec.end(); ++it) {
        std::cout << *it << " "; // 只读访问
    }
    std::cout << std::endl;

    return 0;
}

在这里插入图片描述

🌠Capacity容量操作

在这里插入图片描述

🌉 size()

函数定义:

size_type size() const;

示例

#include <vector>
#include <iostream>

int main() {
    std::vector<int> vec = {1, 2, 3, 4, 5};

    // 获取向量的大小
    std::vector<int>::size_type vec_size = vec.size();
    std::cout << "向量的大小是:" << vec_size << std::endl;
    return 0;
}

输出:

5

🌉 capacity()

函数定义:

size_type capacity() const;

探索capaccity()的扩容机制

// 测试vector的默认扩容机制
void TestVectorExpand()
{
	size_t sz;
	vector<int> v;
	sz = v.capacity();
	cout << "making v grow:\n";
	for (int i = 0; i < 100; ++i)
	{
		v.push_back(i);
		if (sz != v.capacity())
		{
			sz = v.capacity();
			cout << "capacity changed: " << sz << '\n';
		}
	}
}	

vs:运行结果:vs下使用的STL基本是按照1.5倍方式扩容

making foo grow:
capacity changed: 1
capacity changed: 2
capacity changed: 3
capacity changed: 4
capacity changed: 6
capacity changed: 9
capacity changed: 13
capacity changed: 19
capacity changed: 28
capacity changed: 42
capacity changed: 63
capacity changed: 94
capacity changed: 141

g++运行结果:linux下使用的STL基本是按照2倍方式扩容

making foo grow:
capacity changed: 1
capacity changed: 2
capacity changed: 4
capacity changed: 8
capacity changed: 16
capacity changed: 32
capacity changed: 64
capacity changed: 128

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

void TestVectorExpandOP()
{
	vector<int> v;
	size_t sz = v.capacity();
	v.reserve(100); // 提前将容量设置好,可以避免一遍插入一遍扩容
	cout << "making bar grow:\n";
	for (int i = 0; i < 100; ++i)
	{
		v.push_back(i);
		if (sz != v.capacity())
		{
			sz = v.capacity();
			cout << "capacity changed: " << sz << '\n';
		}
	}
}

在这里插入图片描述

小结:capacity的代码在vsg++下分别运行会发现,vscapacity是按1.5倍增长的,g++是按2倍增长的。这个问题经常会考察,不要固化的认为,vector增容都是2倍,具体增长多少是根据具体的需求定义的。vs是PJ版本STL,g++是SGI版本STL。

🌉resize()

在这里插入图片描述

resize 成员函数用于调整向量的大小。根据新大小,可以增加或减少向量中的元素。如果新大小大于当前大小,新的元素将被添加到向量的末尾。如果新大小小于当前大小,向量将被截断。

void test_vector09()
{
	vector<int> vec = { 1, 2, 3, 4, 5 };

	// 调整大小到 8,不指定新元素的值
	vec.resize(8);
	cout << "调整大小到 8,不指定新元素的值:" << endl;
	for (size_t i = 0; i < vec.size(); ++i) 
	{
		cout << "vec[" << i << "] = " << vec[i] << endl;
	}

	// 调整大小到 3(截断向量)
	vec.resize(3);
	cout << "调整大小到 3(截断向量):" << endl;
	for (size_t i = 0; i < vec.size(); ++i) 
	{
		std::cout << "vec[" << i << "] = " << vec[i] << std::endl;
	}

	// 调整大小到 6,并指定新元素的值为 10
	vec.resize(6, 10);
	cout << "调整大小到 6,并指定新元素的值为 10:" << endl;
	for (size_t i = 0; i < vec.size(); ++i) 
	{
		cout << "vec[" << i << "] = " << vec[i] << endl;
	}


}

在这里插入图片描述

🌉reserve()

std::vector::reserve 是一个成员函数,用于请求将向量的容量增加到至少指定的大小。这与 resize 不同,reserve 只改变容量(即预分配的存储空间),而不改变实际存储的元素数量。通过预先分配足够的存储空间,可以避免频繁的重新分配,从而提高性能,特别是在知道将要存储的大量元素时。

函数定义:

void reserve(size_type new_cap);
 new_cap:是请求的新容量值。

如果 new_cap 大于当前容量,向量的容量将增加到至少 new_cap。如果 new_cap 小于或等于当前容量,则容量保持不变。

  • 无返回值: 该函数没有返回值。

使用示例:

#include <vector>
#include <iostream>

int main()
{
    std::vector<int> vec;

    std::cout << "初始容量:" << vec.capacity() << std::endl;

    // 预分配容量
    vec.reserve(10);
    std::cout << "调用 reserve(10) 后的容量:" << vec.capacity() << std::endl;

    // 添加元素
    vec.push_back(1);
    vec.push_back(2);
    vec.push_back(3);
    std::cout << "添加三个元素后的容量:" << vec.capacity() << std::endl;

    // 再次预分配容量
    vec.reserve(20);
    std::cout << "调用 reserve(20) 后的容量:" << vec.capacity() << std::endl;

    return 0;
}

输出:

初始容量:0
调用 reserve(10) 后的容量:10
添加三个元素后的容量:10
调用 reserve(20) 后的容量:20

使用注意事项:

  • 效率: 使用 reserve 可以提高性能,避免在添加大量元素时频繁重新分配内存。
  • 内存增长策略: 如果没有调用 reserve,向量在需要更多容量时通常会自动增长,大多数实现使用倍增策略(即每次需要更多空间时,容量翻倍)。
  • 容量和大小的区别: 容量(capacity)是向量在重新分配前可以存储的元素数量,而大小(size)是向量当前实际存储的元素数量。

reserve只负责开辟空间,如果确定知道需要用多少空间,reserve可以缓解vector增容的代价缺陷问题。
resize在开空间的同时还会进行初始化,影响size

🌠 常用操作符

在这里插入图片描述

🌉 push_back

在这里插入图片描述

#include <iostream>
#include <vector>

int main() {
    std::vector<int> v;

    // 添加整数元素
    v.push_back(1);
    v.push_back(2);
    v.push_back(3);

    // 打印向量的内容
    std::cout << "Vector contents: ";
    for (int i : v) 
    {
        std::cout << i << " ";
    }
    std::cout << std::endl;

    return 0;
}

在这里插入图片描述

🌉pop_back

在这里插入图片描述

std::vector<int> v = { 1, 2, 3, 4, 5 };

// 在删除最后一个元素之前打印向量的内容
std::cout << "删除前向量的内容: ";
for (int i : v) 
{
	std::cout << i << " ";
}
std::cout << std::endl;

// 删除向量的最后一个元素
v.pop_back();

// 在删除最后一个元素之后打印向量的内容
std::cout << "删除后向量的内容: ";
for (int i : v) 
{
	std::cout << i << " ";
}
std::cout << std::endl;

在这里插入图片描述

🌉 find

在这里插入图片描述
注意std::find 是 C++ 标准库中 <algorithm> 头文件中的一个函数模板,而不是vectorfindvector中没有find,用于在给定范围内查找指定的值。

函数原型如下:

template <class InputIterator, class T>
InputIterator find (InputIterator first, InputIterator last, const T& val);
其中:
- `InputIterator first` 和 `InputIterator last` 表示查找范围的起始和结束迭代器。
- `const T& val` 表示要查找的值。

返回一个迭代器,指向范围内第一个等于 val 的元素。如果在给定范围内没有找到该值,则返回 last 迭代器。

示例:

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> v = {1, 2, 3, 4, 5};

    // 查找值为 3 的元素
    auto it = std::find(v.begin(), v.end(), 3);
    if (it != v.end()) 
    {
        std::cout << "Found value: " << *it << std::endl;
    } else 
    {
        std::cout << "Value not found." << std::endl;
    }

    // 查找值为 10 的元素
    it = std::find(v.begin(), v.end(), 10);
    if (it != v.end()) 
    {
        std::cout << "Found value: " << *it << std::endl;
    } else 
    {
        std::cout << "Value not found." << std::endl;
    }

    return 0;
}

输出:

Found value: 3
Value not found.

std::find 函数的时间复杂度为 O(n),其中 n 是给定范围的大小。它会顺序遍历整个范围,直到找到目标元素或者到达范围末尾。因此,它适用于小型数据集,但对于大型数据集可能性能较差。在这种情况下,可以考虑使用更高效的算法,如 std::binary_search 或者基于哈希表的查找。

🌉 insert

std::vector::insert 是 C++ 标准库中 <vector> 头文件中的一个成员函数,用于在给定位置插入元素。

它有三种重载形式:

  1. 单元素插入:

    iterator insert (iterator position, const value_type& val);
    

    该形式在迭代器 position 指向的位置插入一个值为 val 的元素,并返回指向新插入元素的迭代器。

  2. 区间插入:

    void insert (iterator position, size_type n, const value_type& val);
    

    该形式在迭代器 position 指向的位置插入 n 个值为 val 的元素。

  3. 范围插入:

    template <class InputIterator>
    void insert (iterator position, InputIterator first, InputIterator last);
    

    该形式在迭代器 position 指向的位置插入 [first, last) 范围内的元素。

需要注意的是,在调用 insert 函数时,如果 vector 的大小需要扩张以容纳新的元素,则会自动分配新的内存空间。这可能会导致迭代器、指针和引用失效,因此在使用这些元素时需要格外小心。(这里我们在学习vector的模拟实现中可以看出)

下面是一个示例:

#include <iostream>
#include <vector>

int main() {
    std::vector<int> v = {1, 2, 3, 4, 5};

    // 插入单个元素
    auto it = v.insert(v.begin() + 2, 10);
    std::cout << "Inserted at position: " << it - v.begin() << ", value: " << *it << std::endl;

    // 插入多个元素
    v.insert(v.end(), 3, 20);
    for (int x : v) {
        std::cout << x << " ";
    }
    std::cout << std::endl;

    // 插入范围
    std::vector<int> other = {30, 40, 50};
    v.insert(v.begin(), other.begin(), other.end());
    for (int x : v)
     {
        std::cout << x << " ";
    }
    std::cout << std::endl;

    return 0;
}

输出:

Inserted at position: 2, value: 10
1 2 10 3 4 5 20 20 20 
30 40 50 1 2 10 3 4 5 20 20 20

🌉 erase

在这里插入图片描述
std::vector::erase 是 C++ 标准库中 <vector> 头文件中的一个成员函数,用于删除 vector 中的元素。它有两种重载形式:

  1. 单个元素删除:

    iterator erase (iterator position);
    

    该形式删除迭代器 position 指向的元素,并返回指向被删除元素之后的下一个元素的迭代器。

  2. 范围删除:

    iterator erase (iterator first, iterator last);
    

    该形式删除 [first, last) 范围内的所有元素,并返回指向被删除元素之后的下一个元素的迭代器。

需要注意的是,在调用 erase 函数时,如果 vector 的大小需要收缩以适应被删除的元素,则会自动缩小内存空间。这可能会导致迭代器、指针和引用失效,因此在使用这些元素时需要格外小心(这就是她为什么要有返回值,返回值是iterator)。

下面是一个示例:

#include <iostream>
#include <vector>

int main() {
    std::vector<int> v = {1, 2, 3, 4, 5};

    // 删除单个元素
    auto it = v.erase(v.begin() + 2);
    std::cout << "Erased element at position: " << it - v.begin() << ", value: " << *it << std::endl;

    // 删除范围
    it = v.erase(v.begin() + 1, v.begin() + 3);
    std::cout << "Erased elements from position " << it - v.begin() << " to " << v.end() - it << std::endl;

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

    return 0;
}

输出:

Erased element at position: 2, value: 4
Erased elements from position 1 to 3
1 5

🚩总结

请添加图片描述

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

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

相关文章

【Android开发】Android请求出现网络请求失败,HTTP请求,安全网络通信与权限管理

额外权限 要有这个权限&#xff1a; <uses-permission android:name"android.permission.INTERNET" />HTTP安全考虑 从 Android 9&#xff08;API 级别 28&#xff09;开始&#xff0c;默认情况下不支持通过 HTTP 访问网络&#xff0c;而要求使用 HTTPS。这…

html 字体设置 (web端字体设置)

windows自带的字体是有版权的&#xff0c;包括微软雅黑&#xff08;方正&#xff09;、宋体&#xff08;中易&#xff09;、黑体&#xff08;中易&#xff09;等 版权算是个大坑&#xff0c;所谓为了避免版权问题&#xff0c;全部使用开源字体即可 我这里选择的是思源宋体&…

软考-下午题-试题二、三

主要是最后一问的不同解答 1、父图子图平衡 1、员工关系是否存在传递依赖&#xff1f;用100字以内的文字说明理由。2019 2、在职员关系模式中&#xff0c;假设每个职员有多名家属成员&#xff0c;那么职员关系模式存在什么问题&#xff1f; 应如何解决&#xff1f;2020 职员关系…

world machine学习笔记(3)

打开 可以打开场景设置&#xff0c;项目设置平铺构建设置 场景设置&#xff1a; 输出范围 设置中心点和范围 设置分辨率 项目设置&#xff1a; 设置地图颜色&#xff0c;单位&#xff0c;最高地形高度 点击这个图形进行预览设置 该按钮还有其他的功能 world machine基础流程…

【成都站线下会议|EI稳定检索|SPIE出版】第三届信号处理与通信安全国际学术会议(ICSPCS 2024)

【SPIE独立出版|确定ISSN、ISBN号&#xff01;&#xff01;】【成都站&#xff01;&#xff01;欢迎投稿参会】 第三届信号处理与通信安全国际学术会议&#xff08;ICSPCS 2024&#xff09; 2024 3rd International Conference on Signal Processing and Communication Secur…

AJAX初级

AJAX的概念&#xff1a; 使用浏览器的 XMLHttpRequest 对象 与服务器通信 浏览器网页中&#xff0c;使用 AJAX技术&#xff08;XHR对象&#xff09;发起获取省份列表数据的请求&#xff0c;服务器代码响应准备好的省份列表数据给前端&#xff0c;前端拿到数据数组以后&#xf…

设计新境界:大数据赋能UI的创新美学

设计新境界&#xff1a;大数据赋能UI的创新美学 引言 随着大数据技术的蓬勃发展&#xff0c;它已成为推动UI设计创新的重要力量。大数据不仅为界面设计提供了丰富的数据资源&#xff0c;还赋予了设计师以全新的视角和工具来探索美学的新境界。本文将探讨大数据如何赋能UI设计…

云部署最简单python web

最近在玩云主机&#xff0c;考虑将简单的web应用装上去&#xff0c;通过广域网访问一下&#xff0c;代码很简单&#xff0c;所以新手几乎不会碰到什么问题。 from flask import Flaskapp Flask(__name__)app.route(/) def hello_world():return Hello, World!app.route(/gree…

力扣 滑动窗口题目总结

Leetcode3.无重复字符的最长子串 思路&#xff1a; 这道题主要用到思路是&#xff1a;滑动窗口 什么是滑动窗口&#xff1f; 其实就是一个队列,比如例题中的 abcabcbb&#xff0c;进入这个队列&#xff08;窗口&#xff09;为 abc 满足题目要求&#xff0c;当再进入 a&#x…

2024年上半年软件系统架构师论文【回忆版】

文章目录 考试时间考试地点案例分析1、微服务架构的优点和缺点2、质量属性的6个元素3、分布式锁 Redis的缺点4、MongoDB 存储矢量图的优势 论文回忆版论文一、论单元测试的设计与应用论文二、论大数据模型的设计与应用论文三、论模型驱动的架构设计及应用论文四、论云原生运维的…

LeetCode 279 —— 完全平方数

阅读目录 1. 题目2. 解题思路3. 代码实现 1. 题目 2. 解题思路 此图利用动态规划进行求解&#xff0c;首先&#xff0c;我们求出小于 n n n 的所有完全平方数&#xff0c;存放在数组 squareNums 中。 定义 dp[n] 为和为 n n n 的完全平方数的最小数量&#xff0c;那么有状态…

esp32-idf 开发踩坑记录

现象 直接使用原始命令编译idf.py build 但是提示idf 版本错误 卸载旧版本 编译出错build 问题 然后删除编译文件后&#xff0c;重新编译&#xff0c;还是出错 解决方法1 最后发现是因为项目所在文件夹有中文目录&#xff0c;把项目迁移到英文目录后&#xff0c;重新编译&a…

【Python 对接QQ的接口(二)】简单用接口查询【等级/昵称/头像/Q龄/当天在线时长/下一个等级升级需多少天】

文章日期&#xff1a;2024.05.25 使用工具&#xff1a;Python 类型&#xff1a;QQ接口 文章全程已做去敏处理&#xff01;&#xff01;&#xff01; 【需要做的可联系我】 AES解密处理&#xff08;直接解密即可&#xff09;&#xff08;crypto-js.js 标准算法&#xff09;&…

同名在线查询系统微信小程序源码下载支持多种流量主,附带系统教程

同名在线查询系统微信小程序源码下载支持多种流量主这是一款支持查询同名的一款微信小程序 该款小程序支持多种查询模式 重名查询&#xff0c;热度查询&#xff0c;概率香查询 源码免费下载地址抄笔记(chaobiji.cn)

arcgisPro将一个图层的要素复制到另一个图层

1、打开两个图层&#xff0c;如下&#xff0c;其中一个图层中有两个要素&#xff0c;需要将其中一个要素复制到另一个图层中&#xff0c;展示如下&#xff1a; 2、选中待复制要素&#xff0c;点击复制按钮&#xff0c;如下&#xff1a; 3、下拉粘贴按钮列表&#xff0c;选择【选…

普通函数的参数中的auto

2.1 普通函数的参数中的auto 从c14起&#xff0c;lambda可以使用auto占位符声明或者定义参数: auto printColl [] (const auto& coll) // generic lambda{ for (const auto& elem : coll) {std::cout << elem << \n;}} 只要支持Lambda 内部的操作&…

java图书电子商务网站的设计与实现源码(springboot+vue+mysql)

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于springboot的图书电子商务网站的设计与实现。项目源码以及部署相关请联系风歌&#xff0c;文末附上联系信息 。 项目简介&#xff1a; 图书电子商…

推荐一款自助分析的财务分析软件:奥威BI软件

奥威BI软件是一款支持多维度动态自助分析的软件&#xff0c;预设了智能财务分析方案&#xff0c;提供内存行列计算模型解决财务指标计算难题&#xff0c;界面简洁&#xff0c;以点击、拖曳操作为主&#xff0c;十分适合没有IT背景的财务人做财务分析。因此也经常有人说奥威BI软…

tcp协议介绍,协议段格式(端口号,首部长度,窗口大小,序号,确认序号,6个标志位),流量控制,确认应答机制,捎带应答,三次握手的双方认知不一致问题

目录 tcp协议 介绍 传输控制协议 图解 全双工 缓冲区 控制 tcp协议段格式 数据在不同层的名称 图解 ​编辑 端口号 首部长度 窗口大小 -- 引入 前提 流量控制 确认应答机制 窗口大小 -- 介绍 序号 -- 引入 确认应答机制的进一步探讨 如果应答丢失 捎带应…

基于Android studio 使用SQLite数据库完成登录注册功能——保姆级教程

&#x1f345;文章末尾有获取完整项目源码方式&#x1f345; 点击快捷传送地址&#xff1a; 保姆级教学——制作登陆注册功能页面 目录 一、准备工作 二、创建相关文件 三、页面布局 四、DabaHelper帮助类的编写 五、RegisterActivity注册页面 六、LoginActivity登录页面…