【C++篇】深入剖析C++ Vector底层源码及实现机制

news2025/1/12 16:08:53

文章目录

须知

💬 欢迎讨论:如果你在学习过程中有任何问题或想法,欢迎在评论区留言,我们一起交流学习。你的支持是我继续创作的动力!

👍 点赞、收藏与分享:觉得这篇文章对你有帮助吗?别忘了点赞、收藏并分享给更多的小伙伴哦!你们的支持是我不断进步的动力!
🚀 分享给更多人:如果你觉得这篇文章对你有帮助,欢迎分享给更多对C++感兴趣的朋友,让我们一起进步!

 全面剖析vector底层及实现机制

接上篇:【C++篇】探索STL之美:vector容器讲解_c++vector容器-CSDN博客

前言

 Vector是C++标准模板库(STL)中提供的一种动态数组容器,能够高效管理元素的存储与操作。它具有自动扩容的特性,即在存储空间不足时会自动分配更大的内存,保证连续存储的同时提高了灵活性。Vector支持随机访问,拥有接近数组的访问速度,同时也提供了丰富的成员函数用于插入、删除、排序等操作,兼顾了灵活性与性能。

总之,Vector是C++开发中最常用的容器之一,因其高效、灵活、易用的特性,在处理动态数据时显得尤为重要。

1. 基本结构与初始化(具有不同种方式)

1.1 基本结构

Vector底层实现类似于动态数组,其内部通过一块连续的内存空间存储元素。主要成员包括:

  • 指针数据(_start, _end, _end_of_storage):分别指向当前元素的起始地址、末尾地址和存储空间的尾地址,用于跟踪已存储的元素和剩余空间。
  • 动态扩容:当插入新元素超出当前容量时,Vector会申请更大的连续内存空间,并将现有元素复制到新空间中。扩容一般是以一定倍数增长(通常为2倍)。

1.2 带大小和默认值初始化构造函数

  • 初始化一个给定大小的vector,并使用默认值填充。
  • 测试构造后大小、容量是否符合要求。
namespace W {
    template<class T>
    class vector {
    public:
        typedef T* iterator;

        vector(size_t n, const T& value = T()) {
            _start = new T[n];
            _finish = _start + n;
            _endOfStorage = _finish;
            for (size_t i = 0; i < n; ++i) {
                _start[i] = value;  // 填充默认值
            }
        }

        size_t size() const { return _finish - _start; }
        size_t capacity() const { return _endOfStorage - _start; }
        bool empty() const { return _start == _finish; }

        T& operator[](size_t pos) { return _start[pos]; }

        ~vector()
		{
			if (_start)
			{
				delete[] _start;
				_start = _finish = _endOfStorage = nullptr;
			}
		}

    private:
        iterator _start;
        iterator _finish;
        iterator _endOfStorage;
    };
}

测试用例:

void TestInitVector() {
    W::vector<int> v(5, 10);
    assert(v.size() == 5);  // 验证大小
    assert(v.capacity() == 5);  // 验证容量
    assert(!v.empty());  // 验证非空
    for (size_t i = 0; i < 5; ++i) {
        assert(v[i] == 10);  // 验证默认值
    }
    std::cout << "TestInitVector passed" << std::endl;
}

1.3 拷贝构造函数

  • 实现vector的拷贝构造函数。
  • 测试拷贝后的vector是否完全复制原来的内容和容量。

实现代码:

namespace W {
    template<class T>
    class vector {
    public:
        typedef T* iterator;

        vector(const vector<T>& v) {
            size_t n = v.size();
            _start = new T[n];
            _finish = _start + n;
            _endOfStorage = _finish;
            for (size_t i = 0; i < n; ++i) {
                _start[i] = v._start[i];  // 复制数据
            }
        }

        size_t size() const { return _finish - _start; }
        size_t capacity() const { return _endOfStorage - _start; }
        bool empty() const { return _start == _finish; }

        T& operator[](size_t pos) { return _start[pos]; }

        ~vector()
		{
			if (_start)
			{
				delete[] _start;
				_start = _finish = _endOfStorage = nullptr;
			}
		}

    private:
        iterator _start;
        iterator _finish;
        iterator _endOfStorage;
    };
}

测试用例:

void TestCopyVector() {
    W::vector<int> v1(10, 20);
    W::vector<int> v2(v1);
    assert(v2.size() == 10);  // 验证大小
    assert(v2.capacity() == 10);  // 验证容量
    for (size_t i = 0; i < 10; ++i) {
        assert(v2[i] == 20);  // 验证数据拷贝
    }
    std::cout << "TestCopyVector passed" << std::endl;
}

1.4 赋值操作符重载

  • 实现赋值操作符重载。
  • 测试两个vector赋值后,是否正确拷贝了内容和容量。
namespace W {
    template<class T>
    class vector {
    public:
        typedef T* iterator;

        vector<T>& operator=(const vector<T>& v) {
            if (this != &v) {
                delete[] _start;  // 释放旧的空间
                size_t n = v.size();
                _start = new T[n];
                _finish = _start + n;
                _endOfStorage = _finish;
                for (size_t i = 0; i < n; ++i) {
                    _start[i] = v._start[i];  // 复制数据
                }
            }
            return *this;
        }

        size_t size() const { return _finish - _start; }
        size_t capacity() const { return _endOfStorage - _start; }
        bool empty() const { return _start == _finish; }

        T& operator[](size_t pos) { return _start[pos]; }

       ~vector()
		{
			if (_start)
			{
				delete[] _start;
				_start = _finish = _endOfStorage = nullptr;
			}
		}

    private:
        iterator _start;
        iterator _finish;
        iterator _endOfStorage;
    };
}

测试用例:

void TestAssignVector() {
    W::vector<int> v1(15, 30);
    W::vector<int> v2 = v1;  // 赋值操作
    assert(v2.size() == 15);  // 验证大小
    assert(v2.capacity() == 15);  // 验证容量
    for (size_t i = 0; i < 15; ++i) {
        assert(v2[i] == 30);  // 验证数据拷贝
    }
    std::cout << "TestAssignVector passed" << std::endl;
}

2. 容器管理内存的实现与测试

2.1 reserve函数:动态扩容

实现代码:

namespace W {
    template<class T>
    class vector {
    public:
        void reserve(size_t n) {
            if (n > capacity()) {
                size_t oldSize = size();
                T* tmp = new T[n];
                for (size_t i = 0; i < oldSize; ++i) {
                    tmp[i] = _start[i];
                }
                delete[] _start;
                _start = tmp;
                _finish = _start + oldSize;
                _endOfStorage = _start + n;
            }
        }
    };
}

测试用例:

void TestReserveVector() {
    W::vector<int> v(5, 10);
    v.reserve(10);  // 预留容量
    assert(v.capacity() == 10);  // 验证容量扩展
    for (size_t i = 0; i < 5; ++i) {
        assert(v[i] == 10);  // 验证数据保持不变
    }
    std::cout << "TestReserveVector passed" << std::endl;
}

输出

TestReserveVector passed

 2.2 resize函数:改变大小

用途

1. 增加容器大小

当新的大小大于当前大小时,resize会在容器末尾添加新元素,新添加的元素会被默认值初始化(对于内置类型,默认值通常为0或空值)。

std::vector<int> vec = {1, 2, 3};
vec.resize(5); // vec变为 {1, 2, 3, 0, 0}

2. 减少容器大小
当新的大小小于当前大小时,resize会移除多余的元素,只保留从起始位置算起的新大小的元素。

std::vector<int> vec = {1, 2, 3, 4, 5};
vec.resize(3); // vec变为 {1, 2, 3} 

 3.指定新元素的初始值
在扩容时,可以通过第二个参数指定新添加元素的初始值,而不是使用默认值。

std::vector<int> vec = {1, 2, 3};
vec.resize(5, 10); // vec变为 {1, 2, 3, 10, 10}

特点

  • 不会影响容量(capacity)resize只调整size(实际元素数量),不会改变容器的容量(底层分配的内存大小)。扩容时容量可能会增长,但缩小时容量不会减少。
  • 元素保留特性:缩小时多余的元素会被移除,但未移除的元素保持不变;扩容时已存在的元素同样不受影响。
  • 性能resize可能引起新元素的构造或旧元素的析构,因此需要注意其性能开销。
namespace W {
    template<class T>
    class vector {
    public:
        void resize(size_t n, const T& value = T()) {
            if (n < size()) {
                _finish = _start + n;  // 缩小大小
            } else {
                reserve(n);
                for (iterator it = _finish; it != _start + n; ++it)
			    {
                    *it = value;  // 填充新值
                }
                _finish = _start + n;
            }
        }
    };
}

测试用例:

void TestResizeVector() {
    W::vector<int> v(5, 10);
    v.resize(8, 20);  // 扩展大小并填充新值
    assert(v.size() == 8);  // 验证扩展后大小
    for (size_t i = 0; i < 5; ++i) {
        assert(v[i] == 10);  // 验证原值不变
    }
    for (size_t i = 5; i < 8; ++i) {
        assert(v[i] == 20);  // 验证新值
    }
    std::cout << "TestResizeVector passed" << std::endl;
}

3. 增加与删除元素

3.1 push_back函数:向vector末尾插入元素

3.1.1 实现思路

  1. 检查容量是否足够,若不足则扩容(通常容量加倍)。
  2. 将新元素插入到当前末尾。
  3. 更新_finish指针,指向新的末尾。

示例代码:

namespace W {
    template<class T>
    class vector {
    public:
        void push_back(const T& x) {
            // 如果空间不足,扩展容量为当前容量的两倍
            if (_finish == _endOfStorage) {
                size_t newCapacity = capacity() == 0 ? 1 : capacity() * 2;
                reserve(newCapacity);
            }

            // 在末尾插入新元素
            *_finish = x;
            ++_finish;
        }

    private:
        T* _start;
        T* _finish;
        T* _endOfStorage;
    };
}

 测试用例:

void TestPushBackVector() {
    W::vector<int> v;
    v.push_back(1);
    v.push_back(2);
    v.push_back(3);

    assert(v.size() == 3);  // 验证插入后的大小
    assert(v.capacity() >= 3);  // 验证容量是否自动扩容
    assert(v[0] == 1 && v[1] == 2 && v[2] == 3);  // 验证插入的元素是否正确

    std::cout << "TestPushBackVector passed" << std::endl;
}

输出:

TestPushBackVector passed

 3.2 pop_back函数:删除末尾元素

 将_finish指针向后移动移动一位,即该指针指向的就是最后一个元素

示例代码:

namespace W {
    template<class T>
    class vector {
    public:
        void pop_back() {
            assert(_finish != _start);  // 确保vector非空
            --_finish;  // 逻辑删除最后一个元素
        }

    private:
        T* _start;
        T* _finish;
        T* _endOfStorage;
    };
}

3.3 insert:在指定位置插入数据

实现思路

1 检查容量,不足扩容

2 将指定的数据从后往前挪动,空出该位置

3 将该位置插入指定数据

4 更新finish指针

实现代码:

namespace W {
    template<class T>
    class vector {
    public:
        T* insert(T* pos, const T& value) {
            assert(pos >= _start && pos <= _finish);  // 确保pos是有效指针

            // 检查空间是否足够
            if (_finish == _endOfStorage) {
                size_t newCapacity = capacity() == 0 ? 1 : capacity() * 2;
                size_t offset = pos - _start;  // 记录插入位置
                reserve(newCapacity);  // 扩容
                pos = _start + offset;  // 更新插入位置
            }

            // 将插入位置之后的元素整体向后移动
            for (T* it = _finish; it > pos; --it) {
                *it = *(it - 1);
            }

            // 插入新元素
            *pos = value;
            ++_finish;
            return pos;
        }

    private:
        T* _start;
        T* _finish;
        T* _endOfStorage;
    };
}

erase函数:删除指定位置的元素

实现思路

1 循环将指定位置数据的后面每一位向前挪动

2 更新finish指针

实现代码:

namespace W {
    template<class T>
    class vector {
    public:
        T* erase(T* pos) {
            assert(pos >= _start && pos < _finish);  // 确保pos是有效指针

            // 将pos之后的元素向前移动
            for (T* it = pos; it < _finish - 1; ++it) {
                *it = *(it + 1);
            }

            --_finish;  // 更新_finish指针
            return pos;
        }

    private:
        T* _start;
        T* _finish;
        T* _endOfStorage;
    };
}

4. 查找元素

4.1 front函数:返回vector的第一个元素

实现代码:

namespace W {
    template<class T>
    class vector {
    public:
        T& front() {
            assert(!empty());  // 确保vector非空
            return *_start;  // 返回第一个元素
        }

    private:
        T* _start;
        T* _finish;
        T* _endOfStorage;
    };
}

测试用例:

void TestFrontVector() {
    W::vector<int> v;
    v.push_back(10);
    assert(v.front() == 10);  // 验证front

    v.push_back(20);
    assert(v.front() == 10);  // 验证front不变

    std::cout << "TestFrontVector passed" << std::endl;


}

输出:

TestFrontVector passed

4.2 back函数:获取最后一个元素

实现代码:

namespace W {
    template<class T>
    class vector {
    public:
        T& back() {
            assert(!empty());  // 确保vector非空
            return *(_finish - 1);  // 返回最后一个元素
        }

    private:
        T* _start;
        T* _finish;
        T* _endOfStorage;
    };
}

测试用例:

void TestBackVector() {
    W::vector<int> v;
    v.push_back(10);
    assert(v.back() == 10);  // 验证back

    v.push_back(20);
    assert(v.back() == 20);  // 验证back变化

    std::cout << "TestBackVector passed" << std::endl;
}

 5. 迭代器的实现

  • begin 函数返回指向 vector 起始位置的迭代器(即指向第一个元素)。
  • end 函数返回指向 vector 末尾的迭代器(即指向最后一个元素的下一个位置)。
  • 两者结合可以用于遍历 vector 中的元素。

实现代码:
 

namespace W {
    template<class T>
    class vector {
    public:
        typedef T* iterator;  

        iterator begin() {
            return _start;
        }

        iterator end() {
            return _finish;
        }

    private:
        T* _start;
        T* _finish;
        T* _endOfStorage;
    };
}

测试用例:

void TestIteratorVector() {
    W::vector<int> v;
    v.push_back(10);
    v.push_back(20);
    v.push_back(30);

    // 使用迭代器遍历 vector
    for (W::vector<int>::iterator it = v.begin(); it != v.end(); ++it) {
        std::cout << *it << " ";
    }
    std::cout << std::endl;
}

输出:

10   20   30

 6. swap函数:交换两个vector

用途:

  • swap 函数用于交换两个 vector 的内容,包括它们的起始指针、结束指针和容量指针。
  • swap 函数是常用的优化操作,特别是在实现移动语义时能大大提高效率。

实现代码:

namespace W {
    template<class T>
    class vector {
    public:
        void swap(vector<T>& v) {
            std::swap(_start, v._start);
            std::swap(_finish, v._finish);
            std::swap(_endOfStorage, v._endOfStorage);
        }

    private:
        T* _start;
        T* _finish;
        T* _endOfStorage;
    };
}

 测试用例:

void TestSwapVector() {
    W::vector<int> v1;
    W::vector<int> v2;

    v1.push_back(1);
    v1.push_back(2);
    v2.push_back(3);
    v2.push_back(4);
    
    v1.swap(v2);

    // 验证 v1 和 v2 交换后内容是否正确
    for (auto e : v1) {
        std::cout << e << " ";
    }
    std::cout << std::endl;

    for (auto e : v2) {
        std::cout << e << " ";
    }
    std::cout << std::endl;
}

输出:

3 4 
1 2 

 7. 赋值运算符重载:深拷贝vector

 现代技术:拷贝并交换(Copy and Swap) 技术,这种技术可以减少重复代码并提高异常安全性。

实现代码:

namespace W {
    template<class T>
    class vector {
    public:
        //这里可以服用reserve和push_back函数了
        vector(const vector<T>& v)
            : _start(nullptr), _finish(nullptr), _endOfStorage(nullptr)
        {
            reserve(v.size());  // 分配所需空间
            for (const T& elem : v) {
                push_back(elem);  // 拷贝每个元素
            }
        }

        // 赋值操作符,使用拷贝并交换技术
        vector<T>& operator=(vector<T> v) {
            swap(v);  // 调用 swap 函数交换内容
            return *this;
        }

        // swap 函数
        void swap(vector<T>& v) {
            std::swap(_start, v._start);
            std::swap(_finish, v._finish);
            std::swap(_endOfStorage, v._endOfStorage);
        }

        // 其他成员函数同之前实现...

    private:
        T* _start;
        T* _finish;
        T* _endOfStorage;
    };
}

测试用例:

void TestCopyAndAssignVector() {
    // 测试拷贝构造函数
    W::vector<int> v1;
    v1.push_back(1);
    v1.push_back(2);
    v1.push_back(3);

    W::vector<int> v2(v1);  // 使用拷贝构造函数
    for (size_t i = 0; i < v2.size(); ++i) {
        assert(v2[i] == v1[i]);  // 验证每个元素是否相同
    }

    // 测试赋值操作符
    W::vector<int> v3;
    v3 = v1;  // 使用赋值操作符
    for (size_t i = 0; i < v3.size(); ++i) {
        assert(v3[i] == v1[i]);  // 验证每个元素是否相同
    }

    std::cout << "TestCopyAndAssignVector passed" << std::endl;
}

现代写法解释 :

传值参数:通过传递 vector<T> 的值作为参数,创建一个临时对象 v。调用拷贝构造函数时自动执行拷贝,然后在赋值操作中与现有对象交换内容。传值是安全的,避免了手动内存管理问题。
swap:通过交换数据成员 _start_finish_endOfStorage,避免手动内存释放,简化代码逻辑。交换后的临时对象 v 离开作用域时自动销毁,保证资源释放。


 8. vector容器特性总结

1. 动态大小

  • 可以根据需要动态调整大小,而无需预定义固定容量,避免内存浪费。

  • 自动处理底层内存分配和扩展。

2. 随机访问性能优秀

  • 支持常数时间的随机访问,类似于数组,便于快速读取和修改元素。

3. 便捷的插入和删除操作

  • 支持尾部插入/删除操作,时间复杂度为O(1)。

  • 通过eraseinsert等方法,支持中间位置的元素操作,虽然复杂度为O(n),但提供了便利。

4. 内存管理

  • 自动管理底层内存,不需要开发者手动分配或释放内存,减少内存泄漏的风险。

5. 支持迭代器

  • 提供灵活的迭代器支持,可以轻松遍历、修改元素,并与其他STL算法结合使用。

6. 多功能性

  • 可以存储不同类型的对象,包括用户定义类型。

  • 提供了丰富的操作函数,例如排序、搜索等。

7. 与C++标准库兼容性高

  • 与标准库中的其他容器(如mapset)和算法无缝集成,形成强大的工具组合。

8. 性能优化

  • 在扩容时,底层内存分配采用指数增长策略(通常为两倍),减少了频繁的重新分配操作

这些特点使vector在需要灵活、动态数组的场景中非常实用,例如处理未知大小的输入数据或需要高效随机访问的场景。

 

相信通过这篇文章你对C++STL->vector的使用高级部分的有了初步的了解。如果此篇文章对你学习C++有帮助,期待你的三连,你的支持就是我创作的动力!!!

下一篇文章再会.

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

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

相关文章

【代码pycharm】动手学深度学习v2-04 数据操作 + 数据预处理

数据操作 数据预处理 1.数据操作运行结果 2.数据预处理实现运行结果 第四课链接 1.数据操作 import torch # 张量的创建 x1 torch.arange(12) print(1.有12个元素的张量&#xff1a;\n,x1) print(2.张量的形状&#xff1a;\n,x1.shape) print(3.张量中元素的总数&#xff1…

鸿蒙HarmonyOS开发:一次开发,多端部署(工程级)三层工程架构

文章目录 一、工程创建1、先创建出最基本的项目工程。2、新建common、features、 products 目录 二、工程结构三、依赖关系1、oh-package.json52、配置ohpm包依赖 四、引用ohpm包中的代码1、定义共享资源2、在common模块index文件中导出3、在phone模块oh-package.json5文件中引…

NLP论文速读(EMNLP 2023)|工具增强的思维链推理

论文速读|ChatCoT: Tool-Augmented Chain-of-Thought Reasoning on Chat-based Large Language Models 论文信息&#xff1a; 简介&#xff1a; 本文背景是关于大型语言模型&#xff08;LLMs&#xff09;在复杂推理任务中的表现。尽管LLMs在多种评估基准测试中取得了优异的成绩…

uniapp vue3小程序报错Cannot read property ‘__route__‘ of undefined

在App.vue里有监听应用的生命周期 <script>// 只能在App.vue里监听应用的生命周期export default {onError: function(err) {console.log(AppOnError:, err); // 当 uni-app 报错时触发}} </script>在控制台打印里无意发现 Cannot read property ‘__route__‘ of …

第17章 子查询

一、介绍子查询 1.1 介绍 子查询指一个查询语句嵌套在另一个查询语句内部的查询&#xff0c;这个特性从MySQL 4.1开始引入。 SQL 中子查询的使用大大增强了 SELECT 查询的能力&#xff0c;因为很多时候查询需要从结果集中获取数据&#xff0c;或者需要从同一个表中先计算得出一…

蓝队技能-应急响应篇日志自动采集日志自动查看日志自动化分析Web安全内网攻防工具项目

知识点&#xff1a; 1、应急响应-系统日志收集-项目工具 2、应急响应-系统日志查看-项目工具 3、应急响应-日志自动分析-项目工具 演示案例-蓝队技能-工具项目-自动日志采集&自动日志查看&自动日志分析 系统日志自动采集-观星应急工具(Windows系统日志) SglabIr_Co…

【西瓜书】线性判别分析-LDA

线性判别分析&#xff08;Linear Discriminant Analysis&#xff0c;简称LDA&#xff09;是一种经典的线性学习方法。在二分类问题上&#xff0c;因为最早由Fisher提出&#xff0c;也称“Fisher判别分析”。 严格说来&#xff0c;LDA 与 Fisher判别分析稍有不同&#xff0c;LDA…

Photino:通过.NET Core构建跨平台桌面应用程序,.net国产系统

一、Photino.NET简介&#xff1a; 最近发现了一个不错的框架 Photino.Net 一份代码运行&#xff0c;三个平台 windows max linux &#xff0c;其中windows10,windows11,ubuntu 18.04,ubuntu 20.04 已测试均可以。mac 因为没有相关电脑没有测试。 github:https://github.com/t…

湘潭大学软件工程算法设计与分析考试复习笔记(四)

回顾 湘潭大学软件工程算法设计与分析考试复习笔记&#xff08;一&#xff09;湘潭大学软件工程算法设计与分析考试复习笔记&#xff08;二&#xff09;湘潭大学软件工程算法设计与分析考试复习笔记&#xff08;三&#xff09; 前言 现在是晚上十一点&#xff0c;我平时是十…

Python毕业设计选题:基于python的豆瓣电影数据分析可视化系统-flask+spider

开发语言&#xff1a;Python框架&#xff1a;flaskPython版本&#xff1a;python3.7.7数据库&#xff1a;mysql 5.7数据库工具&#xff1a;Navicat11开发软件&#xff1a;PyCharm 系统展示 系统首页 个人中心 管理员登录界面 管理员功能界面 电影管理 用户管理 系统管理 摘要…

小程序租赁系统开发为企业提供高效便捷的租赁服务解决方案

内容概要 在这个数字化飞速发展的时代&#xff0c;小程序租赁系统应运而生&#xff0c;成为企业管理租赁业务的一种新选择。随着移动互联网的普及&#xff0c;越来越多的企业开始关注如何利用小程序来提高租赁服务的效率和便捷性。小程序不仅可以为用户提供一个快速、易用的平…

《深入理解 Spring MVC 工作流程》

一、Spring MVC 架构概述 Spring MVC 是一个基于 Java 的轻量级 Web 应用框架&#xff0c;它遵循了经典的 MVC&#xff08;Model-View-Controller&#xff09;设计模式&#xff0c;将请求、响应和业务逻辑分离&#xff0c;从而构建出灵活可维护的 Web 应用程序。 在 Spring MV…

RHCE的学习(21)

第三章 Shell条件测试 用途 为了能够正确处理Shell程序运行过程中遇到的各种情况&#xff0c;Linux Shell提供了一组测试运算符。 通过这些运算符&#xff0c;Shell程序能够判断某种或者几个条件是否成立。 条件测试在各种流程控制语句&#xff0c;例如判断语句和循环语句中…

SpringBoot中的restTemplate请求存在乱码问题的解决

SpringBoot中的restTemplate请求存在乱码问题的解决 搜索网上各种解法&#xff0c;最后在不断的一点点对比中&#xff0c;排查到了问题&#xff0c;是restTemplate不支持gzip&#xff0c;对返回的数据不能对gzip自动解压&#xff0c;因此需要去掉header中的accept-encoding 网…

【蓝桥杯C/C++】翻转游戏:多种实现与解法解析

博客主页&#xff1a; [小ᶻZ࿆] 本文专栏: 蓝桥杯C/C 文章目录 &#x1f4af;题目&#x1f4af;问题分析解法一&#xff1a;减法法解法二&#xff1a;位运算解法解法三&#xff1a;逻辑非解法解法四&#xff1a;条件运算符解法解法五&#xff1a;数组映射法不同解法的比较…

同三维T80003JEHS 4K/60帧HDMI/SDI超高清H.265解码器

1路HDMI和1路SDI输出&#xff0c;1路3.5音频输入和1路3.5音频输出&#xff0c;1个USB2.0口1个USB3.0口&#xff0c;带1个RS232串口&#xff0c;2个网口&#xff0c;支持1路4K60或4路4K30或16路1080P或32路720P解码输出。4种画面分割显示模式。 产品简介&#xff1a; 同三维T80…

Windows Server 2022 Web1

载入靶机&#xff0c;看到相关描述&#xff1a; 进入虚拟机发现桌面有phpstudy和解题两个软件&#xff1a; 打开解题.exe&#xff0c;发现里面是一些问题&#xff0c;接下来就需要获取相关信息&#xff1a; 1、shell密码 2、IP地址 3、隐藏账户名称 4、挖矿程序的矿池域名 打…

Leetcode打卡:新增道路查询后的最短距离II

执行结果&#xff1a;通过 题目&#xff1a;3244 新增道路查询后的最短距离II 给你一个整数 n 和一个二维整数数组 queries。 有 n 个城市&#xff0c;编号从 0 到 n - 1。初始时&#xff0c;每个城市 i 都有一条单向道路通往城市 i 1&#xff08; 0 < i < n - 1&…

在 CentOS 系统上直接安装 MongoDB 4.0.25

文章目录 步骤 1&#xff1a;配置 MongoDB 官方源步骤 2&#xff1a;安装 MongoDB步骤 3&#xff1a;启动 MongoDB 服务步骤 4&#xff1a;验证安装步骤 5&#xff1a;可选配置注意事项 以下是在 CentOS 系统上直接安装 MongoDB 4.0.25 的详细步骤&#xff1a; 步骤 1&#x…

商城小程序的流程渠道拓展

传统印象里&#xff0c;小程序的开发制作似乎很难&#xff0c;尤其是商城类型且功能体系完善的&#xff0c;事实也确实如此&#xff0c;没有较高的技术和成本投入或团队各个流程的专业人员合作&#xff0c;很难开发出来成品&#xff0c;或者质量较低。 当然对于大公司来说&…