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

时间复杂度和空间复杂度详解

     有一堆数据需要排序,A要使用快速排序,B要使用堆排序,A认为自己的代码更高效,B也认为自己的代码更高效,在这种情况下,怎么来判断谁的代码更好一点呢?这时候就有了时间复杂度和空间复杂度。

目录

一、算法效率

1.1 衡量算法好坏的关键

1.2 算法的复杂度

二、时间复杂度

2.1 时间复杂度的概念

2.2 大O的渐进表示法

2.3 常见的时间复杂度的计算案例

2.3.1 案例一

2.3.2 案例二

2.3.3 案例三

2.3.4 案例四

2.3.5 案例五

2.3.6 案例六

2.3.7 案例七

2.3.8 案例八

 三、空间复杂度

3.1 空间复杂度的概念

3.2 常见的空间复杂度计算案例

3.2.1 案例一

3.2.2 案例二

3.2.3 案例三

 3.2.4 案例四

四、常见的复杂度对比

五、复杂度的练习

5.1 消失的数字

5.2 旋转数组

一、算法效率

1.1 衡量算法好坏的关键

     我们在之前探讨过斐波那契数列计算的两种方式即递归和循环,这两种方式那种更好呢?我们认为循环的方式更好,使用递归去求斐波那契数列,会有大量的重复计算,那么显然循环的方式更好,这两个代码可以直接分析出来,但是对于其他一些不容易进行分析的算法,我们用什么来作为算法好坏的标准呢?这里就引入了算法复杂度的概念。

1.2 算法的复杂度

     算法在编写成可执行程序后,运行时需要耗费时间资源和空间资源。因此衡量一个算法的好坏,一般是从时间和空间两个维度来衡量的,即时间复杂度和空间复杂度。在下面的文章中我们会依次讲解时间复杂度和空间复杂度。

二、时间复杂度

2.1 时间复杂度的概念

     时间复杂度不是算的算法所用的时间,在计算机科学中,算法的时间复杂度是一个函数,它定量描述了该算法的运行时间。一 个算法执行所耗费的时间,从理论上说,是不能算出来的,只有你把你的程序放在机器上跑起来,才能知 道。但是我们需要每个算法都上机测试吗?是可以都上机测试,但是这很麻烦,所以才有了时间复杂度这个分析方式。一个算法所花费的时间与其中语句的执行次数成正比例,算法中的基本操作的执行次数,为算法的时间复杂度。

     对于算法的时间复杂度,我们不需要计算出精确的执行次数,只需要对执行次数进行估算,得到大致的量级,在计算时间复杂度和空间复杂度的时候,我们统一使用的是大O的渐进表示法

2.2 大O的渐进表示法

     在计算算法的复杂度的时候,我们只需要得到大概次数所属的量级,即忽落掉一些对结果影响不大的项,在这里我们主要使用大O的渐进表示法。

大O符号(Big O notation):是用于描述函数渐进行为的数学符号。

推导大O阶方法:

1.用常数1取代运行时间中的所有加法常数。

2.在修改后的运行次数函数中,只保留最高阶项。

3.如果最高阶项存在且不是1,则去除与这个项目相乘的常数。得到的结果就是大O阶。

     通过上面我们会发现大O的渐进表示法去掉了那些对结果影响不大的项,简洁明了的表示出了执行次数。

     对于有一些算法,算法的时间复杂度存在最好、平均和最坏情况:

     1.最坏情况:任意输入规模的最大运行次数(上界)

     2.平均情况:任意输入规模的期望运行次数

     3.最好情况:任意输入规模的最小运行次数(下界)

     在实际中中一般情况关注的是算法的最坏运行情况。

2.3 常见的时间复杂度的计算案例

2.3.1 案例一

// 计算Func2的时间复杂度?
void Func2(int N)
{int count = 0;for (int k = 0; k < 2 * N ; ++ k){++count;}int M = 10;while (M--){++count;}printf("%d\n", count);
}

     在上面的概念中我们知道时间复杂度就是基本语句的执行次数,在上述算法中,有两个循环,一个for循环,执行2*N次,一个while循环,执行10次,所以执行次数为2*N+10次,计算时间复杂度我们使用大O的渐进表示法,忽略掉对整体影响不大的项,所以在此算法中的时间复杂度为:O(N)

2.3.2 案例二

// 计算Func3的时间复杂度?
void Func3(int N, int M)
{int count = 0;for (int k = 0; k < M; ++k){++count;}for (int k = 0; k < N; ++k){++count;}printf("%d\n", count);
}

     在上述算法中,有两个for循环,按照大O的渐进表示法,上述算法的时间复杂度是:O(M+N),在此案例中并未对M和N的大小进行说明,如果题目指明M远大于N,那就说明N对最终结果影响不大,可以忽略,时间复杂度就是:O(M);如果题目指明N远大于M,那就说明M对最终结果影响不大,可以忽略,时间复杂度就是:O(N);如果题目指明M=N,时间复杂度就是:O(N)或者O(M)。

2.3.3 案例三

// 计算Func4的时间复杂度?
void Func4(int N)
{int count = 0;for (int k = 0; k < 100; ++k){++count;}printf("%d\n", count);
}

     上述算法中,基本语句的执行次数为100,按照大O的渐进表示法,时间复杂度为:O(1)

     在这里如果有同学不理解常数阶的执行次数为什么一律用O(1)来表示,实际上,CPU是足够快的,循环100000000次和循环100次对他而言,时间都差不多,所以他会认为是一个量级,所以常数阶都用O(1)来表示

2.3.4 案例四

// 计算strchr的时间复杂度?
const char * strchr ( const char * str, int character );

     上述的strchr库函数的功能,参数介绍如下图:

     strchr函数相当于:

while(str)
{if(*str == character)return str;elsestr++;
}

     上述函数的时间复杂度我们需要分情况来看:

//假设有一个字符串
a d c g e h e a x \0
//如果我们要在上述字符串中找a字符,那么只需要找1次就可以找到,时间复杂度为O(1),这个情况属于最好的情况。
//如果我们要在上述字符串中找x字符,那么只需要找N(假设一共有N个字符)次就可以找到,时间复杂度为O(N),这个情况属于最坏的情况。

      对于时间复杂度,我们一般关注的是最坏时间复杂度,所以此算法的时间复杂度为O(N)。

2.3.5 案例五

// 计算BubbleSort的时间复杂度?
void BubbleSort(int* a, int n)
{assert(a);for (size_t end = n; end > 0; --end){int exchange = 0;for (size_t i = 1; i < end; ++i){if (a[i - 1] > a[i]){Swap(&a[i - 1], &a[i]);exchange = 1;}}if (exchange == 0)break;}
}

     上述案例是冒泡排序冒泡排序的主题思想是两两相邻的元素进行比较,对于冒泡排序,一趟冒泡排序可以把一个数排到正确的位置上,那么N个数就需要N-1趟冒泡排序,在这里是冒泡排序的优化版本(如果想要对冒泡排序了解的更加清晰可以看看我的《数组》那篇博文),如果在进行循环的过程中,数组已经是升序那么接下来的循环就不会再继续,对于上述时间复杂度的计算,我们主要通过思想来进行分析,分为最好情况和最坏情况,如下图:

      从上图我们就可以看出,在最好情况下,只需要进行一趟冒泡排序,即N-1次的比较,所以最好时间复杂度为O(1),在最坏情况下,我们需要进行N-1趟冒泡排序,每趟冒泡排序需要对两两相邻的数进行比较,最坏情况下的执行次数为:N-1+N-2+N-3+......3+2+1=N*(N-1)/2,按照大O的渐进表示法,此算法的最坏时间复杂度是:O(N^2)

     对于时间复杂度,我们一般关注的是最坏时间复杂度,所以此算法的时间复杂度为O(N^2)。

2.3.6 案例六

// 计算BinarySearch的时间复杂度?
int BinarySearch(int* a, int n, int x)
{assert(a);int begin = 0;int end = n - 1;// [begin, end]:begin和end是左闭右闭区间,因此有=号while (begin <= end){int mid = begin + ((end - begin) >> 1);if (a[mid] < x)begin = mid + 1;else if (a[mid] > x)end = mid - 1;elsereturn mid;}return -1;
}

     二分查找是什么?二分查找,例如我们需要在arr= {1,2,3,4,5,6,7,8,9,10}中找到7对应的下标,此时我们先看中间的数即arr[4],此时数组中arr[4]对应的数字是5,比7小,我们从arr[5]到arr[9]范围内寻找,再次找到arr[5]到arr[9]中间的数,即arr[7],对应的数字是8,比7大,我们从arr[5]到arr[6]的范围找,再找arr[5]到arr[6]中间的数即arr[5],arr[5]对应的数为6比7小,此时再将arr[6]对应的数字与7比较,相等,二分查找的前提是有序

     上述算法是二分查找的算法,这个算法也分为最好情况和最坏情况,最好情况是进行一次二分查找就能够找到,此时最好时间复杂度是:O(1)。

     接下来我们通过分析二分查找的算法来计算它的最坏时间复杂度,

     二分查找的时间复杂度为O(logN)。 

2.3.7 案例七

// 计算阶乘递归Fac的时间复杂度?
long long Fac(size_t N)
{if(0 == N)return 1;return Fac(N-1)*N;
}

     上述算法涉及递归我们用图来解释:

2.3.8 案例八

// 计算斐波那契递归Fib的时间复杂度?
long long Fib(size_t N)
{if(N < 3)return 1;return Fib(N-1) + Fib(N-2);
}

     此处补充斐波那契数列的知识:斐波那契数列指的是这样一个数列:0、1、1、2、3、5、8、13、21、34、55、89……满足:从第3项起,每一项都等于前两项之和,我们可以使用递归来计算斐波那契数列。

     使用递归求斐波那契数列的调用如下:

需要注意的是,在实际调用过程中,如果我们要求Fib(5),图示如下:

     调用的模型类似于下方:


 

 三、空间复杂度

3.1 空间复杂度的概念

     空间复杂度也是一个数字表达式,是对一个算法在运行过程中临时占用存储空间大小的量度(是这个算法额外开辟的空间),空间复杂度不是程序占用了多少bytes的空间,他计算的是变量的大小,空间复杂度计算规则基本跟实践复杂度类似,也使用大O渐进表示法

     注意:函数运行时所需要的栈空间(存储参数、局部变量、一些寄存器信息等)在编译期间已经确定好了,因此空间复杂度主要通过函数在运行时候显示申请的额外空间来确定。

3.2 常见的空间复杂度计算案例

3.2.1 案例一

// 计算BubbleSort的空间复杂度?
void BubbleSort(int* a, int n)
{	assert(a);for (size_t end = n; end > 0; --end){int exchange = 0;for (size_t i = 1; i < end; ++i){if (a[i - 1] > a[i]){Swap(&a[i - 1], &a[i]);exchange = 1;}}if (exchange == 0)break;}
}

      上述算法的空间复杂度是:O(1),空间复杂度算的是由于算法额外需要开辟的空间,即由于算法需要额外开辟的变量个数,在上述算法中我们额外开辟了三个变量:end、exchange、i,按照大O的渐进表示法,空间复杂度即为:O(1)。

      在这里许多人会有一个误区:把函数的参数也算作额外开辟变量的个数,这种想法显然不对,函数的参数属于数据源,即给一些数据,按照算法对这些数据进行一定的处理,最后得到想要结果,这些数据不属于算法所需要的额外开辟的空间。

3.2.2 案例二

// 计算Fibonacci的空间复杂度?
// 返回斐波那契数列的前n项
long long* Fibonacci(size_t n)
{if (n == 0)return NULL;long long* fibArray = (long long*)malloc((n + 1) * sizeof(long long));fibArray[0] = 0;fibArray[1] = 1;for (int i = 2; i <= n; ++i){fibArray[i] = fibArray[i - 1] + fibArray[i - 2];}return fibArray;
}

     上述算法中,额外开辟了n+3个变量,首先开辟了n+1个long long类型的数据,其次开辟了一个long long*类型的变量fibArray和int类型的变量i,按照大O的渐进表示法,空间复杂度为:O(n)

3.2.3 案例三

// 计算斐波那契递归Fib的空间复杂度?
long long Fib(size_t N)
{if(N < 3)return 1;return Fib(N-1) + Fib(N-2);
}

     求斐波那契递归的空间复杂度,我们依然先看递归的调用图示:

     对于上述算法,它的空间复杂度是:O(N),主要是由于它的调用顺序:
 

 

    对于Fib(N),调用时先调用 Fib(N-1),然后调用Fib(N-2),一直到调用到Fib(2),然后返回Fib(2)的值,把Fib(2)函数调用开辟的函数帧还给存储空间,然后调用Fib(1),也就是说Fib(2)和Fib(1)是使用的同一块空间,以此类推,在此函数递归调用的过程中,有一些调用复用同一块空间,所以实际上该算法额外开辟的空间为N个,即空间复杂度为:O(N)

     此处主要还涉及了一些关于函数栈帧的创建与销毁的知识,这部分知识大家可以从“我的资源”中找到,或者私聊我要相关的笔记。

     此处我们还可以通过求解Fib(5)来演示:
 

 

 3.2.4 案例四

// 计算阶乘递归Fac的空间复杂度?
long long Fac(size_t N)
{if (N == 0)return 1;return Fac(N - 1) * N;
}

     上述的函数递归调用与案例三有所不同,在本案例中,函数调用层层嵌套,此函数递归调用的方式类似下图:

 

     对于上述函数的每次调用我们可以认为开辟了常数个变量,需要进行N次函数调用,所以上述算法的空间复杂度是:O(N)。

四、常见的复杂度对比

一般算法常见的复杂度如下:

            (上图来源于百度,如有侵权,告知删除) 

五、复杂度的练习

5.1 消失的数字

oj链接:https://leetcode-cn.com/problems/missing-number-lcci/

5.2 旋转数组

oj链接:https://leetcode-cn.com/problems/rotate-array/

注:上面两个题大家可以先做一下,他们将在下一篇博客中具体分析。

 

相关文章:

时间复杂度和空间复杂度详解

有一堆数据需要排序&#xff0c;A要使用快速排序&#xff0c;B要使用堆排序&#xff0c;A认为自己的代码更高效&#xff0c;B也认为自己的代码更高效&#xff0c;在这种情况下&#xff0c;怎么来判断谁的代码更好一点呢&#xff1f;这时候就有了时间复杂度和空间复杂度。 目录 …...

【C++】面向对象---封装

【C】面向对象—封装 1.封装的意义 封装是C面向对象三大特性之一 封装的意义&#xff1a; 将属性和行为作为一个整体&#xff0c;表现生活的事物将属性和行为加以权限控制 封装意义一&#xff1a; 在设计类的时候&#xff0c;属性和行为写在一起&#xff0c;表现事物 语…...

Docker简介

一、介绍容器虚拟化技术&#xff08;带环境安装的一种解决方案&#xff09;打破程序即应用的观念&#xff0c;透过镜像image将作业系统核心除外&#xff0c;运用应用程序所需要的运行环境&#xff0c;由上而下打包&#xff0c;达到应用程序跨平台间的无缝接轨运作。Docker是基于…...

量化学习(一)数据获取

试验环境 windows10 AnacondaPyCharm&#xff08;小白参考文章&#xff1a;https://coderx.com.cn/?p14&#xff09; VM中安装MySQL5.7&#xff08;设置utf8及相应配置优化&#xff09; 关于复权 小白参考文章&#xff1a;https://zhuanlan.zhihu.com/p/469820288 数据来源 AK…...

java并发编程讨论:锁的选择

java并发编程 线程堆栈大小 单线程的堆栈大小默认为1M&#xff0c;1000个线程内存就占了1G。所以&#xff0c;受制于内存上限&#xff0c;单纯依靠多线程难以支持大量任务并发。 上下文切换开销 ReentrantLock 2个线程交替自增一个共享变量&#xff0c;使用ReentrantLock&…...

大数据框架之Hadoop:MapReduce(三)MapReduce框架原理——ReduceTask工作机制

1、ReduceTask工作机制 ReduceTask工作机制&#xff0c;如下图所示。 &#xff08;1&#xff09;Copy阶段&#xff1a;ReduceTask从各个MapTask上远程拷贝一片数据&#xff0c;并针对某一片数据&#xff0c;如果其大小超过一定阈值&#xff0c;则写到磁盘上&#xff0c;否则直…...

Nginx的介绍、安装与常用命令

前言&#xff1a;传统结构上(如下图所示)我们只会部署一台服务器用来跑服务&#xff0c;在并发量小&#xff0c;用户访问少的情况下基本够用但随着用户访问的越来越多&#xff0c;并发量慢慢增多了&#xff0c;这时候一台服务器已经不能满足我们了&#xff0c;需要我们增加服务…...

less基础

一、less介绍 1、介绍 是css预处理语言&#xff0c;让css更强大&#xff0c;可以实现在less里面定义变量函数运算等 2、less默认浏览器不识别 less转成csS (框架: less/sass 框架的内置了转码less-css) 3、使用语法 1.创建less文件xxx.less 后缀.less 2. less编译成css 再引入…...

电子统计台账:海量数据中导入特定行,极力减少键盘编辑工作量

1 前言从事企业统计工作的小伙伴&#xff0c;本来已经够忙的了&#xff0c;现在又要加上什么电子台账这种鬼任务&#xff0c;而且居然还要每月来一次&#xff0c;简直不能忍。如果非要捏着鼻子忍了&#xff0c;那么有什么办法&#xff0c;减轻工作量&#xff1f;2 问题的提出有…...

ChatGPT是如何训练得到的?通俗讲解

首先声明喔&#xff0c;我是没有任何人工智能基础的小白&#xff0c;不会涉及算法和底层原理。 我依照我自己的简易理解&#xff0c;总结出了ChatGPT是怎么训练得到的&#xff0c;非计算机专业的同学也应该能看懂。看完后训练自己的min-ChatGPT应该没问题 希望大牛如果看到这…...

刷题28-有效的变位词

32-有效的变位词 解题思路&#xff1a; 注意变位词的条件&#xff0c;当两个字符串完全相等或者长度不等时&#xff0c;就不是变位词。 把字符串中的字符映射成整型数组&#xff0c;统计每个字符出现的次数 注意数组怎么初始化&#xff1a; int [] s1new int[26]代码如下&a…...

JavaWeb中异步交互的关键——Ajax

文章目录1,Ajax 概述1.1 作用1.2 同步和异步1.3 案例1.3.1 分析1.3.2 后端实现1.3.3 前端实现2&#xff0c;axios2.1 基本使用2.2 快速入门2.2.1 后端实现2.2.2 前端实现2.3 请求方法别名3&#xff0c;JSON3.1 概述3.2 JSON 基础语法3.2.1 定义格式3.2.2 代码演示3.2.3 发送异步…...

python爬虫常见错误

python爬虫常见错误前言python常见错误1. AttributeError: WebDriver object has no attribute find_element_by_id1. 问题描述2. 解决办法2. selenium&#xff1a;DeprecationWarning: executable_path has been deprecated, please pass in1. 问题描述2. 解决办法3. 下载了包…...

AI_Papers周刊:第三期

CV - 计算机视觉 | ML - 机器学习 | RL - 强化学习 | NLP 自然语言处理 2023.02.20—2023.02.26 文摘词云 Top Papers Subjects: cs.CL 1.LLaMA: Open and Efficient Foundation Language Models 标题&#xff1a;LLaMA&#xff1a;开放高效的基础语言模型 作者&#…...

在win7上用VS2008编译skysip工程

在win7上用VS2008编译skysip工程 1. 安装vs2008及相应的补丁包,主要包含以下安装包: 1.1 VS2008TeamSuite90DayTrialCHSX1429243.iso 1.2 VS2008SP1CHSX1512981.iso 1.3 VS90sp1-KB945140-CHS.exe 2. 安装Windows SDK: 6.0.6001.18000.367-KRMSDK_EN.zip 例如安装路径为…...

python 数据结构习题

旋转图像给定一个nn的二维矩阵表示一个图像。将图像顺时针旋转90度。你必须在原地旋转图像&#xff0c;这意味着你需要直接修改输入的二维矩阵。请不要使用另一个矩阵来旋转图像。例如&#xff0c;给定matrix[[1&#xff0c;2&#xff0c;3]&#xff0c;[4&#xff0c;5&#x…...

18、MySQL8其它新特性

文章目录1 MySQL8新特性概述1.1 MySQL8.0 新增特性1.2 MySQL8.0移除的旧特性2 新特性1&#xff1a;窗口函数2.1 使用窗口函数前后对比2.2 窗口函数分类2.3 语法结构2.4 分类讲解1 序号函数2 分布函数3 前后函数4 首尾函数5 其他函数2.5 小 结3 新特性2&#xff1a;公用表表达式…...

【Android笔记79】Android之接口请求库Retrofit的介绍及使用

这篇文章,主要介绍Android之接口请求库Retrofit的介绍及使用。 目录 一、Retrofit接口请求库 1.1、什么是Retrofit 1.2、Retrofit的使用 (1)引入依赖...

蓝桥杯 考勤打卡

问题描述 小蓝负责一个公司的考勤系统, 他每天都需要根据员工刷卡的情况来确定 每个员工是否到岗。 当员工刷卡时, 会在后台留下一条记录, 包括刷卡的时间和员工编号, 只 要在一天中员工刷过一次卡, 就认为他到岗了。 现在小蓝导出了一天中所有员工的刷卡记录, 请将所有到岗…...

逻辑回归

逻辑回归 在分类问题中&#xff0c;要预测的变量y为离散值&#xff08;y0~1&#xff09;&#xff0c;逻辑回归模型的输出变量范围始终在 0 和 1 之间。 训练集为 {(x(1),y(1)),(x(2),y(2)),...,(x(m),y(m))}\{(x^{(1)},y^{(1)}),(x^{(2)},y^{(2)}),...,(x^{(m)},y^{(m)})\} {…...

stm32G473的flash模式是单bank还是双bank?

今天突然有人stm32G473的flash模式是单bank还是双bank&#xff1f;由于时间太久&#xff0c;我真忘记了。搜搜发现&#xff0c;还真有人和我一样。见下面的链接&#xff1a;https://shequ.stmicroelectronics.cn/forum.php?modviewthread&tid644563 根据STM32G4系列参考手…...

智慧医疗能源事业线深度画像分析(上)

引言 医疗行业作为现代社会的关键基础设施,其能源消耗与环境影响正日益受到关注。随着全球"双碳"目标的推进和可持续发展理念的深入,智慧医疗能源事业线应运而生,致力于通过创新技术与管理方案,重构医疗领域的能源使用模式。这一事业线融合了能源管理、可持续发…...

Qt/C++开发监控GB28181系统/取流协议/同时支持udp/tcp被动/tcp主动

一、前言说明 在2011版本的gb28181协议中&#xff0c;拉取视频流只要求udp方式&#xff0c;从2016开始要求新增支持tcp被动和tcp主动两种方式&#xff0c;udp理论上会丢包的&#xff0c;所以实际使用过程可能会出现画面花屏的情况&#xff0c;而tcp肯定不丢包&#xff0c;起码…...

Java如何权衡是使用无序的数组还是有序的数组

在 Java 中,选择有序数组还是无序数组取决于具体场景的性能需求与操作特点。以下是关键权衡因素及决策指南: ⚖️ 核心权衡维度 维度有序数组无序数组查询性能二分查找 O(log n) ✅线性扫描 O(n) ❌插入/删除需移位维护顺序 O(n) ❌直接操作尾部 O(1) ✅内存开销与无序数组相…...

蓝桥杯 2024 15届国赛 A组 儿童节快乐

P10576 [蓝桥杯 2024 国 A] 儿童节快乐 题目描述 五彩斑斓的气球在蓝天下悠然飘荡&#xff0c;轻快的音乐在耳边持续回荡&#xff0c;小朋友们手牵着手一同畅快欢笑。在这样一片安乐祥和的氛围下&#xff0c;六一来了。 今天是六一儿童节&#xff0c;小蓝老师为了让大家在节…...

MVC 数据库

MVC 数据库 引言 在软件开发领域,Model-View-Controller(MVC)是一种流行的软件架构模式,它将应用程序分为三个核心组件:模型(Model)、视图(View)和控制器(Controller)。这种模式有助于提高代码的可维护性和可扩展性。本文将深入探讨MVC架构与数据库之间的关系,以…...

Psychopy音频的使用

Psychopy音频的使用 本文主要解决以下问题&#xff1a; 指定音频引擎与设备&#xff1b;播放音频文件 本文所使用的环境&#xff1a; Python3.10 numpy2.2.6 psychopy2025.1.1 psychtoolbox3.0.19.14 一、音频配置 Psychopy文档链接为Sound - for audio playback — Psy…...

WordPress插件:AI多语言写作与智能配图、免费AI模型、SEO文章生成

厌倦手动写WordPress文章&#xff1f;AI自动生成&#xff0c;效率提升10倍&#xff01; 支持多语言、自动配图、定时发布&#xff0c;让内容创作更轻松&#xff01; AI内容生成 → 不想每天写文章&#xff1f;AI一键生成高质量内容&#xff01;多语言支持 → 跨境电商必备&am…...

C++八股 —— 单例模式

文章目录 1. 基本概念2. 设计要点3. 实现方式4. 详解懒汉模式 1. 基本概念 线程安全&#xff08;Thread Safety&#xff09; 线程安全是指在多线程环境下&#xff0c;某个函数、类或代码片段能够被多个线程同时调用时&#xff0c;仍能保证数据的一致性和逻辑的正确性&#xf…...

C++ Visual Studio 2017厂商给的源码没有.sln文件 易兆微芯片下载工具加开机动画下载。

1.先用Visual Studio 2017打开Yichip YC31xx loader.vcxproj&#xff0c;再用Visual Studio 2022打开。再保侟就有.sln文件了。 易兆微芯片下载工具加开机动画下载 ExtraDownloadFile1Info.\logo.bin|0|0|10D2000|0 MFC应用兼容CMD 在BOOL CYichipYC31xxloaderDlg::OnIni…...