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

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

算法复杂度

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

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

时间复杂度

随着计算机科学技术的发展,计算机的内存从原来的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.mzph.cn/pingmian/43975.shtml

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

相关文章

Maven在Windows中的配置方法

本文介绍在Windows电脑中&#xff0c;下载、配置Maven工具的详细方法。 Maven是一个广泛使用的项目管理工具&#xff0c;主要针对Java项目&#xff0c;但也可以用于其他类型的项目&#xff1b;其由Apache软件基金会维护&#xff0c;旨在简化和标准化项目构建过程&#xff0c;依…

数字经济时代,你有数商吗?

引言&#xff1a;随着科技的飞速发展&#xff0c;我们正步入一个全新的数字经济时代。在这个时代里&#xff0c;数据成为了新的石油&#xff0c;是推动经济增长和社会进步的关键要素。而在这个数据洪流中&#xff0c;一个新兴的概念——“数商”&#xff0c;正逐渐进入公众的视…

递归、搜索与回溯算法 2024.7.4-24.7.9

专题介绍&#xff1a; 一、递归 1、汉诺塔问题 class Solution {public void hanota(List<Integer> A, List<Integer> B, List<Integer> C) {int n A.size();move(n,A,B,C);// 将A柱上的n个盘子通过借助B盘子全部挪到C柱子上}void move(int m,List<Integ…

Python | Leetcode Python题解之第226题翻转二叉树

题目&#xff1a; 题解&#xff1a; class Solution:def invertTree(self, root: TreeNode) -> TreeNode:if not root:return rootleft self.invertTree(root.left)right self.invertTree(root.right)root.left, root.right right, leftreturn root

01_空中机器人

空中机器人&#xff08;Aerial Robotics&#xff09;最早由美国乔治亚理工大学的Robert Michelson提出&#xff0c;是指各种搭载了GPS、机载导航设备、视觉识别设备以及无线通信设备等&#xff0c;能够在一定的范围内实现无人飞行的旋翼无人飞行器、无人飞艇等。 空中机器人拓…

Zynq系列FPGA实现SDI视频编解码+图像缩放+多路视频拼接,基于GTX高速接口,提供8套工程源码和技术支持

目录 1、前言工程概述免责声明 2、相关方案推荐本博已有的 SDI 编解码方案本博已有的FPGA图像缩放方案本方案的无缩放应用本方案在Xilinx--Kintex系列FPGA上的应用 3、详细设计方案设计原理框图SDI 输入设备Gv8601a 均衡器GTX 解串与串化SMPTE SD/HD/3G SDI IP核BT1120转RGB自研…

14-58 剑和诗人32 - 使用矢量数据库增强 LLM 应用程序

GPT-4、Bloom、LaMDA 等大型语言模型 (LLM) 在生成类似人类的文本方面表现出了令人印象深刻的能力。然而,它们在事实准确性和推理能力等方面仍然面临限制。这是因为,虽然它们的基础是从大量文本数据中提取统计模式,但它们缺乏结构化的知识源来为其输出提供依据。 最近,我们…

基于信号量的生产者消费者模型

文章目录 信号量认识概念基于线程分析信号量信号量操作 循环队列下的生产者消费者模型理论认识代码部分 信号量 认识概念 信号量本质: 计数器 它也叫做公共资源 为了线程之间,进程间通信------>多个执行流看到的同一份资源---->多个资源都会并发访问这个资源(此时易出现…

【Linux】进程(9):进程控制2(进程等待)

大家好&#xff0c;我是苏貝&#xff0c;本篇博客带大家了解Linux进程&#xff08;9&#xff09;进程控制2&#xff0c;如果你觉得我写的还不错的话&#xff0c;可以给我一个赞&#x1f44d;吗&#xff0c;感谢❤️ 目录 一. 为什么要进程等待二. 如何进行进程等待1.wait函数—…

使用linux的mail命令发送html格式的邮件

1、关闭本机的sendmail服务或者postfix服务 #执行下面的命令&#xff0c;各位大侠都对号入座吧 #sendmial service sendmail stop chkconfig sendmail off #postfix service postfix stop chkconfig postfix off#再狠一点就直接卸载吧.. yum remove sendmail yum remove postf…

欧拉部署nginx

1.下载nginx 下载地址&#xff1a;https://nginx.org/en/download.html 选择稳定版本 下的镜像文件进行下载 2.解压Nginx包 cd /root/nginx tar -zxvf nginx-1.26.0.tar.gz cd nginx-1.26.03.安装nginx相关依赖 yum -y install gcc zlib zlib-devel pcre-devel openssl o…

如何在 CentOS 中配置 Linux 命名空间(ip netns)

引言 Linux 命名空间是一项强大的技术&#xff0c;允许在同一系统上创建多个独立的虚拟化实例&#xff0c;每个实例可以拥有自己的网络栈、路由表、IP 地址等网络资源&#xff0c;实现资源的隔离和管理。本文将深入探讨如何在 CentOS 中配置和使用 ip netns 命名空间&#xff0…

【面试题】正向代理和反向代理的区别?

正向代理&#xff08;Forward Proxy&#xff09;和反向代理&#xff08;Reverse Proxy&#xff09;是两种常见的代理服务器类型&#xff0c;它们在网络通信中扮演着不同的角色&#xff0c;具有不同的功能和应用场景。 一、正向代理 1. 定义与位置 正向代理是位于客户端和目标…

TextView 实现最后一行缩进指定距离

实现图上类似的效果。 指定最大行数为三行&#xff0c;最后一行缩进指定的距离。 如果行数小于三行&#xff0c;则不缩进。 同时文字两端对齐 代码里的 JustifyTextView &#xff08;两端对齐的 Textview &#xff09;详见 Android Textview 多行文本两端对齐_android tex…

Go语言入门之基础语法

Go语言入门之基础语法 1.简单语法概述 行分隔符&#xff1a; 一行代表一个语句结束&#xff0c;无需写分号。将多个语句写在一行可以用分号分隔&#xff0c;但是不推荐 注释&#xff1a; // 或者/* */ 标识符&#xff1a; 用来命名变量、类型等程序实体。 支持大小写字母、数字…

k8s核心操作_Deployment的扩缩容能力_Deployment自愈和故障转移能力---分布式云原生部署架构搭建022

然后我们上面说了k8s中的deployment的多副本能力 然后,我们再来看 k8s中的deployment的扩缩容能力 可以看到,对于扩容,要使用 kubectl scale 命令 对于缩容 要使用kubectl scale 命令都是使用这个命令对吧 来试试,可以看到上面命令 首先看看 kubectl get pod 可以看到有…

第58期 | GPTSecurity周报

GPTSecurity是一个涵盖了前沿学术研究和实践经验分享的社区&#xff0c;集成了生成预训练Transformer&#xff08;GPT&#xff09;、人工智能生成内容&#xff08;AIGC&#xff09;以及大语言模型&#xff08;LLM&#xff09;等安全领域应用的知识。在这里&#xff0c;您可以找…

网络编程:TCP

一、tcp编程 注意 1.数据本身有顺序 2.发送和接收次数不需要对应 3. 1. C/S 模式 》服务器/客户端模型 server:socket()-->bind()--->listen()-->accept()-->recv()-->close() client:socket()-->connect()-->send()-->close(); int on 1; setso…

常用的设计模式和使用案例汇总

常用的设计模式和使用案例汇总 【一】常用的设计模式介绍【1】设计模式分类【2】软件设计七大原则(OOP原则) 【二】单例模式【1】介绍【2】饿汉式单例【3】懒汉式单例【4】静态内部类单例【5】枚举&#xff08;懒汉式&#xff09; 【三】工厂方法模式【1】简单工厂模式&#xf…

GuLi商城-商品服务-API-品牌管理-OSS获取服务端签名

新建第三方服务: 引入common 把common中oss的依赖都拿到第三方服务中来 配置文件: 加上nacos注解:<