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

深入理解C++ STL中的 vector

文章目录

  • 1. vector 的概述
    • 1.1 vector 是什么?
    • 1.2 vector 的优点
    • 1.3 vector 的缺点
  • 2. vector 的基本使用
    • 2.1 vector 的定义
    • 2.2 基本操作
    • 2.3 示例
    • 2.4 迭代器的使用
  • 3. vector 的内部实现原理
    • 3.1 动态数组的实现
    • 3.2 内存管理
    • 3.3 内存扩展策略
    • 3.4 元素的插入与删除
      • 3.4.1 尾部插入与删除
      • 3.4.2 中间或头部插入与删除
  • 4. vector 高级功能
    • 4.1 复制与赋值
    • 4.2 移动语义与 std::move
    • 4.3 vector 的初始化列表(C++11)
    • 4.4 emplace_back() 与 push_back() 的区别
    • 4.5 shrink_to_fit() 减少容量浪费
  • 5. vector 的常见应用场景
    • 5.1 动态数组
    • 5.2 堆栈
    • 5.3 动态队列
    • 5.4 2D 矩阵的实现
  • 6. vector 的复杂度分析
    • 6.1 时间复杂度
    • 6.2 空间复杂度
  • 7. vector 的常见问题和陷阱
  • 7.1 容量浪费问题
  • 7.2 迭代器失效(最需要注意的地方)
  • 7.3 元素的析构

前言: C++ Standard Template Library (STL) 是一个强大且灵活的库,提供了许多有用的数据结构和算法,其中vector 是最常用的容器之一。
vector是动态数组的封装,可以在运行时自动调整大小,提供了数组的效率以及更多的功能和灵活性。
在本文中,我们将深入讨论 vector的特性、使用方法、底层实现及其复杂性分析。

1. vector 的概述

vector文档的链接:http://www.cplusplus.com/reference/vector/vector/

1.1 vector 是什么?

vector 是 C++ STL 中一种顺序容器(sequence container),其底层实现基于动态数组。与普通数组不同的是,vector 可以根据需要动态扩展其大小,即它能够存储任意数量的元素,而不需要在创建时指定一个固定的大小。此外,vector 提供了丰富的成员函数,可以方便地对元素进行插入、删除、遍历、查找等操作。

1.2 vector 的优点

动态扩展:vector 能够自动调整大小,避免了固定大小数组带来的内存不足问题。
高效的随机访问:由于 vector 底层是连续的内存块,因此它可以像数组一样通过索引进行快速的随机访问。
灵活的插入和删除:vector 支持高效的尾部插入和删除操作,且提供了多种插入、删除方式。
STL 兼容性:vector 是 STL 容器,支持 STL 的算法和迭代器,可以与其他 STL 容器和算法无缝结合。

1.3 vector 的缺点

头部和中间的插入、删除效率低:由于 vector 使用连续的内存块,因此在中间或头部插入或删除元素时,需要移动大量元素,时间复杂度为 O(n)。 内存浪费:为了提高扩展效率,vector 通常会预留比实际需要更多的内存,这可能导致内存浪费。

2. vector 的基本使用

在使用 vector 时,我们需要包含头文件 。下面是一些 vector 的基本使用方法和常见操作:

2.1 vector 的定义

#include <vector>std::vector<int> vec;          // 定义一个存储整数的空vector
std::vector<int> vec(10);      // 定义一个包含10个元素的vector,元素值默认初始化为0
std::vector<int> vec(10, 5);   // 定义一个包含10个元素的vector,元素值为5
std::vector<int> vec2 = vec;   // 定义一个新vector,并通过拷贝构造函数初始化

2.2 基本操作

push_back():在 vector 的末尾插入元素。
pop_back():删除 vector 末尾的元素。
size():返回 vector 中元素的数量。
capacity():返回 vector 当前的容量,即它在不重新分配内存的情况下最多可以容纳的元素数。
clear():清空 vector 中的所有元素。
empty():判断 vector 是否为空。
resize():调整 vector 的大小。
reserve():为 vector 预留一定的容量,避免频繁的重新分配内存。

2.3 示例

#include <iostream>
#include <vector>int main() {std::vector<int> vec;// 向vector中添加元素vec.push_back(1);vec.push_back(2);vec.push_back(3);// 输出vector的元素for (int i = 0; i < vec.size(); ++i) {std::cout << vec[i] << " ";}std::cout << std::endl;// 删除最后一个元素vec.pop_back();// 检查是否为空if (!vec.empty()) {std::cout << "The vector is not empty!" << std::endl;}return 0;
}

2.4 迭代器的使用

迭代器是一种用于遍历 vector 元素的工具。vector 提供了多种迭代器,包括 begin() 和 end()。

std::vector<int> vec = {1, 2, 3, 4, 5};// 使用迭代器遍历
for (std::vector<int>::iterator it = vec.begin(); it != vec.end(); ++it) {std::cout << *it << " ";
}
std::cout << std::endl;

也可以使用 C++11 的范围 for 循环来遍历:

for (int val : vec) {std::cout << val << " ";
}

3. vector 的内部实现原理

3.1 动态数组的实现

vector 的底层实现基于动态数组。当需要插入新元素时,如果当前容量不足,vector 会自动分配更大的内存块,并将原来的元素拷贝到新的内存块中。这种动态扩展策略的时间复杂度较低,因为 vector 的容量在每次扩展时通常是当前容量的两倍。

std::vector<int> vec;
vec.push_back(1);  // 第一次插入,分配内存
vec.push_back(2);  // 插入,内存足够,不需要重新分配
vec.push_back(3);  // 插入,内存足够,不需要重新分配
// 当容量不足时,vector 会重新分配内存,通常是原来容量的两倍。

3.2 内存管理

vector 通过 capacity 来控制当前分配的内存大小,而 size 表示实际存储的元素数量。capacity 总是大于或等于 size。当 size 超过 capacity 时,vector 会重新分配内存,并将所有现有元素拷贝到新的内存地址。

std::vector<int> vec;
vec.reserve(10);  // 预先分配10个元素的内存
vec.push_back(1); // 不会触发内存重新分配
vec.push_back(2); // 不会触发内存重新分配

通过使用 reserve(),可以避免多次内存重新分配,从而提高效率。

3.3 内存扩展策略

当 vector 的容量不足时,它通常会以指数倍(通常是 2 倍)的方式扩展。每次扩展都会重新分配一块新的内存,并将旧的元素拷贝到新的位置。这种方式虽然在内存重新分配时会有较大的开销,但由于扩展的频率较低,总体上这种策略是高效的。

3.4 元素的插入与删除

3.4.1 尾部插入与删除

vector 尾部的插入和删除操作是最为高效的,时间复杂度为 O(1),因为它们不需要移动其他元素。使用 push_back() 和 pop_back() 可以高效地操作 vector 末尾的元素。

3.4.2 中间或头部插入与删除

在 vector 中间或头部插入和删除元素时,需要将插入位置之后的所有元素向后移动,这样才能为新元素腾出空间。这使得这些操作的时间复杂度为 O(n)。

vec.insert(vec.begin() + 1, 10);  // 在第二个位置插入10,后面的元素都需要向后移动
vec.erase(vec.begin() + 2);       // 删除第三个元素,后面的元素都需要向前移动

4. vector 高级功能

4.1 复制与赋值

当一个 vector 被赋值或复制时,会创建一个新对象,并将所有元素进行深拷贝。这意味着修改新对象不会影响原来的 vector。

std::vector<int> vec1 = {1, 2, 3};
std::vector<int> vec2 = vec1;   // 深拷贝
vec2[0] = 10;
std::cout << vec1[0];  // 输出1,vec1不受影响

4.2 移动语义与 std::move

C++11 引入了移动语义,允许将 vector 的资源直接转移到另一个对象,而不需要进行深拷贝。这可以极大地提高性能,尤其是在处理大型对象时。

std::vector<int> vec1 = {1, 2, 3};
std::vector<int> vec2 = std::move(vec1);  // 使用std::move,vec1的资源转移给vec2

在上面的例子中,std::move 将 vec1 的所有资源(如内存和元素)直接转移到 vec2 中,而不需要进行深拷贝。这种操作后,vec1 将处于“空”状态,不再拥有原来的数据,size() 将返回0。

4.3 vector 的初始化列表(C++11)

C++11 引入了初始化列表,可以直接通过大括号初始化 vector:

std::vector<int> vec = {1, 2, 3, 4, 5};  // 初始化列表

这种方式非常方便,不需要手动调用 push_back() 来插入每个元素。

4.4 emplace_back() 与 push_back() 的区别

emplace_back() 是 C++11 新增的功能,它允许直接在容器的末尾构造对象,而无需先构造对象再拷贝到 vector。相比之下,push_back() 会进行额外的拷贝操作,因此在某些情况下,emplace_back() 会比 push_back() 更高效。

class Person {
public:Person(const std::string& name, int age) : name(name), age(age) {}
private:std::string name;int age;
};// 使用push_back
std::vector<Person> people;
people.push_back(Person("John", 30));  // 先构造Person对象,然后拷贝到vector中// 使用emplace_back
people.emplace_back("Jane", 25);  // 直接在vector内部构造Person对象,避免拷贝

使用 emplace_back() 时,参数直接传递给对象的构造函数,从而减少了不必要的拷贝或移动操作。

4.5 shrink_to_fit() 减少容量浪费

由于 vector 通常会预留比实际所需更多的内存空间(capacity()),可能会造成内存浪费。shrink_to_fit() 函数用于释放未使用的内存,使得 vector 的容量等于其大小。

std::vector<int> vec = {1, 2, 3};
vec.reserve(10);   // 预留10个元素的空间
std::cout << vec.capacity();  // 输出10vec.shrink_to_fit();
std::cout << vec.capacity();  // 输出3,容量被调整为实际使用的大小

需要注意的是,shrink_to_fit() 并不保证一定会减少容量,但在支持该操作的系统上可以显著减少内存占用。

5. vector 的常见应用场景

5.1 动态数组

vector 最常见的应用场景就是作为动态数组使用。当程序中需要动态调整数组大小时,vector 提供了极大的方便。

std::vector<int> vec;
int n;
std::cin >> n;
for (int i = 0; i < n; ++i) {int x;std::cin >> x;vec.push_back(x);  // 动态添加元素
}

5.2 堆栈

vector 可以模拟堆栈的功能,因为它提供了高效的尾部插入(push_back())和删除(pop_back())操作。虽然 C++ STL 中已经有 stack 容器,但使用 vector 实现堆栈也是完全可行的。

std::vector<int> stack;
stack.push_back(1);  // 入栈
stack.push_back(2);
stack.pop_back();    // 出栈

5.3 动态队列

虽然 C++ STL 提供了 queue 容器,但 vector 同样可以用来实现队列。通过在 vector 的末尾插入元素并从头部移除元素,我们可以模拟队列的行为。

std::vector<int> queue;
queue.push_back(1);  // 入队
queue.push_back(2);
queue.erase(queue.begin());  // 出队,删除第一个元素

5.4 2D 矩阵的实现

vector 可以轻松实现二维或多维数组。通过将 vector 嵌套使用,可以构建动态调整大小的二维数组或矩阵。

std::vector<std::vector<int>> matrix(3, std::vector<int>(3));  // 创建3x3的矩阵
matrix[0][0] = 1;
matrix[1][1] = 2;
matrix[2][2] = 3;

这个方法可以处理动态大小的矩阵,使得二维数组的尺寸不需要在编译时确定。

6. vector 的复杂度分析

6.1 时间复杂度

随机访问:由于 vector 是连续的内存块,随机访问某个元素的时间复杂度为 O(1)。
尾部插入和删除:尾部插入(push_back())和尾部删除(pop_back())的平均时间复杂度为 O(1),但在某些情况下(如扩容时)插入操作的复杂度可能会暂时达到 O(n)。
中间或头部插入和删除:由于插入或删除会导致大量元素的移动,因此这些操作的时间复杂度为 O(n)。

6.2 空间复杂度

vector 使用连续的内存块来存储元素,其空间复杂度与存储的元素个数成正比,即 O(n)。由于 vector 会在扩展时预留更多的内存,因此有时它的实际内存使用量会超过其存储的元素量。

为了减少内存浪费,可以使用 shrink_to_fit() 来回收未使用的空间。

7. vector 的常见问题和陷阱

7.1 容量浪费问题

如前所述,vector 的容量通常大于其实际存储的元素数量。如果程序中频繁进行插入操作且对内存使用敏感,可以使用 shrink_to_fit() 来减少浪费。

7.2 迭代器失效(最需要注意的地方)

在 vector 中进行插入或删除操作时,所有指向 vector 元素的迭代器、指针或引用可能会失效。这是因为插入或删除操作可能导致 vector 重新分配内存,从而改变所有元素的地址。

std::vector<int> vec = {1, 2, 3};
auto it = vec.begin();
vec.push_back(4);  // 可能导致内存重新分配
std::cout << *it;  // 迭代器可能失效,行为未定义

解决方法是,在插入或删除操作后,尽量避免使用之前的迭代器或指针。

7.3 元素的析构

当 vector 中的对象被删除时,会调用对象的析构函数。因此,如果 vector 存储的是指针类型,在删除 vector 或清空元素时需要特别小心,确保不会引发内存泄漏。

std::vector<int*> vec;
vec.push_back(new int(10));
vec.clear();  // 仅删除了指针,但没有释放内存,可能导致内存泄漏

解决方案是在删除元素之前手动释放内存,或者使用智能指针。

相关文章:

深入理解C++ STL中的 vector

文章目录 1. vector 的概述1.1 vector 是什么&#xff1f;1.2 vector 的优点1.3 vector 的缺点 2. vector 的基本使用2.1 vector 的定义2.2 基本操作2.3 示例2.4 迭代器的使用 3. vector 的内部实现原理3.1 动态数组的实现3.2 内存管理3.3 内存扩展策略3.4 元素的插入与删除3.4…...

MySQL 安装与配置详细教程

MySQL 安装与配置详细教程 MySQL 是一款流行的关系型数据库管理系统&#xff0c;广泛应用于 Web 应用和应用程序中。在本文中&#xff0c;我们将提供一份详细的 MySQL 安装与配置教程&#xff0c;帮助初学者快速上手。 ## 1. 安装 MySQL 首先&#xff0c;我们需要从 MySQL 官…...

理解智能合约:区块链在Web3中的运作机制

随着区块链技术的不断发展&#xff0c;“智能合约”这一概念变得越来越重要。智能合约是区块链应用的核心之一&#xff0c;正在推动Web3的发展&#xff0c;为数字世界带来了前所未有的自动化和信任机制。本文将深入探讨智能合约的基本原理、运作机制&#xff0c;以及它在Web3生…...

QT工程概述

在Qt中&#xff0c;创建 "MainWindow" 与 "Widget" 项目的主要区别在于他们的用途和功能范围&#xff1a; MainWindow&#xff1a;这是一个包含完整菜单栏、工具栏和状态栏的主窗口应用程序框架。它适合于更复 杂的应用程序&#xff0c;需要这些额外的用户…...

redis安装 | 远程连接

1.redis的安装 在Ubuntu下安装redis【网址】使用root账号使用apt来安装。使用apt安装比较的方便&#xff0c;但是安装的版本可能就不是最新的版本。 $ su root $ apt list --installed | grep redis # 查看是否安装 $ apt search redis # 查看apt中的redis版本 $ apt install…...

性价比高的宠物空气净化器应该怎么挑?有哪几款推荐?

前几年和朋友住在一起之后就一起养了两只猫&#xff0c;没想到刚开始还好&#xff0c;到后期之后&#xff0c;我和朋友都苦不堪言&#xff0c;有泪都流不出。 主要是猫咪掉毛实在是太严重了&#xff0c;下班回去之后&#xff0c;发现朋友在打扫家里&#xff0c;又是擦又是扫的…...

Golang | Leetcode Golang题解之第466题统计重复个数

题目&#xff1a; 题解&#xff1a; func getMaxRepetitions(s1 string, n1 int, s2 string, n2 int) int {n : len(s2)cnt : make([]int, n)for i : 0; i < n; i {// 如果重新给一个s1 并且s2是从第i位开始匹配 那么s2可以走多少位&#xff08;走完了就从头开始走p1, p2 :…...

设计模式 - 行为模式

行为模式 观察者模式&#xff0c;策略模式&#xff0c;命令模式&#xff0c;中介者模式&#xff0c;备忘录模式&#xff0c;模板方法模式&#xff0c;迭代器模式&#xff0c;状态模式&#xff0c;责任链模式&#xff0c;解释器模式&#xff0c;访问者模式 保存/封装 行为/请求…...

InstructGPT的四阶段:预训练、有监督微调、奖励建模、强化学习涉及到的公式解读

1. 预训练 1. 语言建模目标函数&#xff08;公式1&#xff09;&#xff1a; L 1 ( U ) ∑ i log ⁡ P ( u i ∣ u i − k , … , u i − 1 ; Θ ) L_1(\mathcal{U}) \sum_{i} \log P(u_i \mid u_{i-k}, \dots, u_{i-1}; \Theta) L1​(U)i∑​logP(ui​∣ui−k​,…,ui−1​;Θ…...

没有HTTPS 证书时,像这样实现多路复用

在没有 HTTPS 证书的情况下,HTTP/2 通常不能直接通过 HTTP 协议使用。虽然 HTTP/2 协议的规范是可以支持纯 HTTP 连接(即通过 http:// 协议),但大多数主流浏览器(如 Chrome、Firefox)都 强制要求 HTTP/2 必须在 HTTPS 上运行。这是出于安全和隐私的考虑。 因此,如果你没…...

2.1.ReactOS系统NtReadFile函数的实现。

ReactOS系统NtReadFile函数的实现。 ReactOS系统NtReadFile函数的实现。 文章目录 ReactOS系统NtReadFile函数的实现。NtReadFile函数的定义NtReadFile函数的实现 NtReadFile()是windows的一个系统调用&#xff0c;内核中有一个叫NtReadFile的函数 NtReadFile函数的定义 NTS…...

2020-11-06《04丨人工智能时代,新的职业机会在哪里?》

《香帅中国财富报告25讲》 04丨人工智能时代&#xff0c;新的职业机会在哪里&#xff1f; 1、新机会的三个诞生方向 前两讲我们都在说&#xff0c;人工智能的出现会极大地冲击现有的职业&#xff0c;从2020年开始&#xff0c;未来一二十年&#xff0c;可能有一半以上的职业都会…...

TensorRT-LLM七日谈 Day5

模型加载 在day2, 我们尝试了对于llama8B进行转换和推理&#xff0c;可惜最后因为OOM而失败&#xff0c;在day4,我们详细的过了一遍tinyllama的推理&#xff0c;值得注意的是&#xff0c;这两个模型的推理走的是不同的流程。llama8b需要显式的进行模型的转换&#xff0c;引擎的…...

使用Java Socket实现简单版本的Rpc服务

通过如下demo&#xff0c;希望大家可以快速理解RPC的简单案例。如果对socket不熟悉的话可以先看下我的上篇文章 Java Scoket实现简单的时间服务器-CSDN博客 对socket现有基础了解。 RPC简介 RPC&#xff08;Remote Procedure Call&#xff0c;远程过程调用&#xff09;是一种…...

P2P 网络 简单研究 1

起因&#xff0c; 目的: P2P 网络&#xff0c; 一道题。题目描述&#xff0c; 在下面。 P2P 网络&#xff0c;我以前只是听说过&#xff0c;并不深入。如果我有5台电脑的话&#xff0c;我也想深入研究一下。 P2P 简介: P2P&#xff08;Peer-to-Peer&#xff09;网络是一种分…...

RAG(检索增强生成)面经(1)

1、RAG有哪几个步骤&#xff1f; 1.1、文本分块 第一个步骤是文本分块&#xff08;chunking&#xff09;&#xff0c;这是一个重要的步骤&#xff0c;尤其在构建与处理文档的大型文本的时候。分块作为一种预处理技术&#xff0c;将长文档拆分成较小的文本块&#xff0c;这些文…...

卫爱守护|守护青春,送出温暖

2024年10月10日&#xff0c;艾多美爱心志愿者来到校园。艾多美“卫艾守护”项目于吉林省白山市政务大厅会议室举办了捐赠仪式&#xff0c;东北区外事部经理黄山出席了捐赠仪式仪式&#xff0c;为全校女同学捐赠了青春关爱包。 此次捐赠&#xff0c;面向吉林省自山市第十八中学、…...

ubuntu-24.04.1 系统安装

使用VMware虚拟机上进行实现 官网下载地址&#xff1a; https://cn.ubuntu.com/download https://releases.ubuntu.com 操作系统手册&#xff1a; https://ubuntu.com/server/docs/ &#xff08;里面包含安装文档&#xff09; 安装指南&#xff08;详细&#xff09;&#xff1a…...

华为OD机试真题---生成哈夫曼树

华为OD机试中关于生成哈夫曼树的题目通常要求根据给定的叶子节点权值数组&#xff0c;构建一棵哈夫曼树&#xff0c;并按照某种遍历方式&#xff08;如中序遍历&#xff09;输出树中节点的权值序列。以下是对这道题目的详细解析和解答思路&#xff1a; 一、题目要求 给定一个…...

小红书新ID保持项目StoryMaker,面部特征、服装、发型和身体特征都能保持一致!(已开源)

继之前和大家介绍的小红书在ID保持以及风格转换方面相关的优秀工作&#xff0c;感兴趣的小伙伴可以点击以下链接阅读~ 近期&#xff0c;小红书又新开源了一款文生图身份保持项目&#xff1a;StoryMaker&#xff0c;是一种个性化解决方案&#xff0c;它不仅保留了面部的一致性&…...

【Linux】shell脚本忽略错误继续执行

在 shell 脚本中&#xff0c;可以使用 set -e 命令来设置脚本在遇到错误时退出执行。如果你希望脚本忽略错误并继续执行&#xff0c;可以在脚本开头添加 set e 命令来取消该设置。 举例1 #!/bin/bash# 取消 set -e 的设置 set e# 执行命令&#xff0c;并忽略错误 rm somefile…...

基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销&#xff0c;平衡网络负载&#xff0c;延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...

边缘计算医疗风险自查APP开发方案

核心目标:在便携设备(智能手表/家用检测仪)部署轻量化疾病预测模型,实现低延迟、隐私安全的实时健康风险评估。 一、技术架构设计 #mermaid-svg-iuNaeeLK2YoFKfao {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg…...

【大模型RAG】Docker 一键部署 Milvus 完整攻略

本文概要 Milvus 2.5 Stand-alone 版可通过 Docker 在几分钟内完成安装&#xff1b;只需暴露 19530&#xff08;gRPC&#xff09;与 9091&#xff08;HTTP/WebUI&#xff09;两个端口&#xff0c;即可让本地电脑通过 PyMilvus 或浏览器访问远程 Linux 服务器上的 Milvus。下面…...

oracle与MySQL数据库之间数据同步的技术要点

Oracle与MySQL数据库之间的数据同步是一个涉及多个技术要点的复杂任务。由于Oracle和MySQL的架构差异&#xff0c;它们的数据同步要求既要保持数据的准确性和一致性&#xff0c;又要处理好性能问题。以下是一些主要的技术要点&#xff1a; 数据结构差异 数据类型差异&#xff…...

ESP32 I2S音频总线学习笔记(四): INMP441采集音频并实时播放

简介 前面两期文章我们介绍了I2S的读取和写入&#xff0c;一个是通过INMP441麦克风模块采集音频&#xff0c;一个是通过PCM5102A模块播放音频&#xff0c;那如果我们将两者结合起来&#xff0c;将麦克风采集到的音频通过PCM5102A播放&#xff0c;是不是就可以做一个扩音器了呢…...

《C++ 模板》

目录 函数模板 类模板 非类型模板参数 模板特化 函数模板特化 类模板的特化 模板&#xff0c;就像一个模具&#xff0c;里面可以将不同类型的材料做成一个形状&#xff0c;其分为函数模板和类模板。 函数模板 函数模板可以简化函数重载的代码。格式&#xff1a;templa…...

协议转换利器,profinet转ethercat网关的两大派系,各有千秋

随着工业以太网的发展&#xff0c;其高效、便捷、协议开放、易于冗余等诸多优点&#xff0c;被越来越多的工业现场所采用。西门子SIMATIC S7-1200/1500系列PLC集成有Profinet接口&#xff0c;具有实时性、开放性&#xff0c;使用TCP/IP和IT标准&#xff0c;符合基于工业以太网的…...

《Docker》架构

文章目录 架构模式单机架构应用数据分离架构应用服务器集群架构读写分离/主从分离架构冷热分离架构垂直分库架构微服务架构容器编排架构什么是容器&#xff0c;docker&#xff0c;镜像&#xff0c;k8s 架构模式 单机架构 单机架构其实就是应用服务器和单机服务器都部署在同一…...

车载诊断架构 --- ZEVonUDS(J1979-3)简介第一篇

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 做到欲望极简,了解自己的真实欲望,不受外在潮流的影响,不盲从,不跟风。把自己的精力全部用在自己。一是去掉多余,凡事找规律,基础是诚信;二是…...