成为编程大佬!!——数据结构与算法(1)——算法复杂度!!

ops/2024/10/19 15:35:24/

前言:解决同一个程序问题可以通过多个算法解决,那么要怎样判断一个算法的优劣呢?🤔

算法复杂度

算法复杂度是对某个程序运行时的时空效率粗略估算,常用来判断一个算法的好坏。

我们通过两个维度来看算法复杂度——时间复杂度 和 空间复杂度

时间复杂度

随着计算机科学技术的发展,计算机的内存从原来的256MB、512MB直到现在的16G甚至32G,存储空间的限制逐渐减小。因此,现在对于程序算法复杂度,更多地关注到时间上面去。

不难知道,假设每条语句的执行时间相同,则有:

程序运行所需要的总时间 = 每条语句的执行时间 x 执行语句的次数——①

这条公式里,执行次数是可以确定的,但是执行时间缺难以确定

int begin = clock();//clock()函数返回程序运行到当前位置已花费的时间。
int count = 0;
for(int i = 0; i < 100000000; ++i)
{count++;
}
int end = clock();
printf("%d",begin - end);//打印循环完毕后总共消耗的时间

PS:clock()函数包含在头文件time.h中,返回值的时间单位是毫秒。

我们可以试着在本地多次运行这段代码,然后就可以发现,并不是每一次的运行时间都是相同的,但是相差并不大。

而对于复杂度来说,我们只需要进行粗略的估算即可,因此,我们省略公式①中对执行时间的计算,只关注可以准确计算得出的执行次数。

T(N)函数式

时间复杂度的T(N) 函数式用来表示程序的执行语句次数。

​int time = 0;//------------1
scanf("%d", &time);//-----------1​
int count = 0;//---------1
for(int i = 0; i < time; ++i)
{for(int j = 0; j < time; ++j){count++;//-------------N*Nprintf("%d ", count);//---------N*N}
}
for(int i = 0; i < time; ++i)
{count--;//------------N
}
printf("%d",count);//--------1
count = 0;//-----------1​​​

如上代码,我们来用T(N)表达式来表示执行语句次数,可得:                  T(N)=1+1+1+n*n+n*n+n+1+1 = 2N^{2}+N+5

这段代码,对执行次数有影响的是time,所以把 time 作为T(N)函数式的变量,用大写字母N来替换。最终  2N^{2}+N+5 就表示这段代码的执行语句次数。

大O渐进表示法

T(N)函数式还不是我们需要的最终结果,复杂度的最终结果,是一个数量级结果。那我们就要根据T(N)函数式,并运用大O渐进表示法来求得数量级结果。(下面用上文求得的T(N)函数式作例子)

基本规则:

①先求得T(N)函数式。(若对执行语句次数有影响的变量不止一个,函数式就为T(N,M,……)。)已求得T(N)= 2N^{2}+N+5 。

②取T(N)中最高阶项。取得2N^{2}

③最高阶项舍去系数(系数取1)。得N^{2}

④放入O()的括号中。得O(N^{2})。

O(N^{2})就是上述代码的时间复杂度结果。根据O(N^{2})我们可知,上述代码的时间复杂度是平方级的。

其他规则:

其他规则也务必得遵守其他规则才ok喔。

⑤若最高阶项为常数,则均表示为O(1),表示数量级为常数级。

⑥对于被多个变量的影响执行次数的程序来说:

i.T(N)函数式就有多个变量,我们一般依次用N,M,L,……来替换表示,最终得到一个多元函数式。如T(N,M) = N + M。

ii.不同的变量,各自遵守②③进行取舍。若有如取舍后的结果为 N^{2}+N*M就要分情况讨论

N远大于M,则把M看作1;

M远大于N,就把N看作1;

如果N、M相差不大,可以把 N看成M 或者 M看成N

再进一步取舍,得到最终答案。

当然,不分情况讨论也是正确的大O表示法结果,但是我们更需要的是一个数量级结果,所以,我们最好如上进行进一步讨论

对数级复杂度,即O(\lg N)、O(\log_{2}N)等等,可以写做O(\log N)省去底数

会出现对数级复杂度的例子:

int k = 2;//-------------1
int n = 0;//------------1
scanf("%d", &n);//----------1
while(k < n)
{k *= 2;//------------2^k < n时循环,结束时2^k > n
}
printf("%d", k);

可得程序结束时,有2^{k+1} >  2^{k} > n,可求得循环次数N = \log_{2}n,即k乘了N次2。T(N)=\log_{2}n,时间复杂度为O(\log N),或者O(\log_{2}N)皆可(因为底数对于对数得最终结果影响很小,所以一般都写成第一种情况)

递归情况

如下代码,求n的阶乘:

int fac(int n)
{if(n == 0){return 1;}return fac(n - 1) * n;
}

可知求阶乘要进行n层递归。同时,肉眼可见,每次递归的时间复杂度为O(1),因此,完成n层递归的时间复杂度为 N * O(1)= O(N)。(也就是直接在数量级层面做乘法即可

以上规则已足够应对对大多数程序的算法判断了。

空间复杂度

即使存储空间现在已经不是重头问题了,但是存储空间也不能随意浪费。空间复杂度仍然是算法好坏的评判标准之一。

T(N)函数式

空间复杂度的T(N)函数式用来表示 程序运行时 创建的 空间个数

运行时创建的空间——编译完成之后,创建的所有空间。包括全局变量,局部变量,函数栈帧……

空间个数——不考虑空间的大小,只考虑开辟空间的个数

注意

i.数组的空间个数为数组长度。

ii.动态申请的空间,如malloc(sizeof(int)*n),这个语句的T(N)=N。

​
int func(int** arr, int n)
{*arr = (int*)malloc(sizeof(int) * n);//-------------nif(!*arr){perror("malloc");return 0;}return 1;   
}int main()
{int* arr = NULL;//----------------1scanf("%d", &n);func(&arr, n);//------------1——函数栈帧(里面包含了形参的开辟空间)return 0;
}​

T(N)=1+1+n=N+2,其中两个1,分别是指针arr的空间,和func函数栈帧的空间;n为func中动态申请的空间

然后同时间复杂度一样,通过大O渐进表示法来求得最终空间复杂度结果。

最终上述代码的空间复杂度是O(N)。

结语

看完这篇博客,相信你已经对算法复杂度有了深刻认识了。有什么疑问和困惑欢迎来评论区留言!!🤩我一定尽力及时解答!!制作不易,求关注!!求点赞!!之后还会有更多有用的干货博客会发出哦!!欢迎做客我的主页!!❤❤Elnaij-CSDN博客❤❤


http://www.ppmy.cn/ops/56326.html

相关文章

[hudsonL@cock.li].mkp勒索病毒的最新威胁:如何恢复您的数据?

引言&#xff1a; 在当今数字化时代&#xff0c;勒索病毒成为网络安全领域的一个严重挑战。最近出现的.[hudsonLcock.li].mkp、[hendersoncock.li].mkp、[myersairmail.cc].mkp勒索病毒&#xff0c;以其具有破坏力的加密技术和极具威胁性的赎金要求&#xff0c;给个人用户和组…

普中51单片机:中断系统与寄存器解析(六)

文章目录 引言中断流程图中断优先级下降沿中断结构图中断相关寄存器IE中断允许寄存器&#xff08;可位寻址&#xff09;XICON辅助中断控制寄存器&#xff08;可位寻址&#xff09;TCON标志控制寄存器SCON串行口控制寄存器 中断号中断响应条件中断函数代码模板电路图开发板IO连接…

docker相关

docker状态 systemctl status docker 启动docker systemctl start docker 关闭docker systemctl stop docker 查询docker 镜像&#xff0c;容器 docker images docker ps docker ps -a 数据卷 docker volume ls docker volume create xxx docker volume inspect xxx …

深度学习--系统配置流程

Win10系统配置双系统Ubuntu18.04 深度学习台式服务器自装练手1.win10磁盘管理2.下载系统镜像制作U盘3.系统安装4. 安装后的系统设置工作5.配置CUDA环境CUDNN安装 深度学习台式服务器自装练手 写在最前 CUDA最高支持11.4 显卡3060 1.win10磁盘管理 首先对原有磁盘进行分区整理…

Fastjson反序列化漏洞

title: Fastjson反序列化漏洞 categories: 漏洞复现 date: 2024-07-08 16:41:38 1.前言 fastjson是一个有阿里开发的一个开源Java 类库&#xff0c;可以将 Java对象转换为 JSON 格式(序列化)&#xff0c;当然它也可以将 JSON 字符串转换为 Java 对象&#xff08;反序列化&…

闲聊C++与面向对象思想

艾伦凯曾说&#xff0c;“I made up the term object-oriented, and I can tell you I did not have C in mind.”&#xff08;“我发明了术语‘面向对象’&#xff0c;可以告诉您我没有C”&#xff09;。 今天看到这句话&#xff0c;激发了笔者写一篇文章聊聊C与面向对象思想…

MOJO语言中的字典和哈希表:数据结构的灵活性与效率

MOJO是一种编程语言&#xff0c;它以其独特的语法和对现代编程范式的支持而闻名。在MOJO中&#xff0c;字典&#xff08;也称为哈希表或散列表&#xff09;是一种非常重要的数据结构&#xff0c;它允许开发者以键值对的形式存储和检索数据。本文将深入探讨MOJO语言中的字典和哈…

JRE、JVM、JDK分别是什么。

JDK JDK的英文全称是Java Development Kit。JDK是用于制作程序和Java应用程序的软件开发环境。JDK 是 Java 开发工具包&#xff0c;它是 Java 开发者用来编写、编译、调试和运行 Java 程序的集合。JDK 包括了 Java 编译器&#xff08;javac&#xff09;、Java 运行时环境&…