【算法与数据结构】4 算法利器,详解循环不变量与复杂度分析

简介: 【算法与数据结构】4 算法利器,详解循环不变量与复杂度分析

一、前情回顾

👉传送门:1 详解线性查找法

👉传送门:2 线性查找的优化

👉传送门:3 线性查找的测试

二、循环不变量

✳️循环是程序设计中非常重要的一种构建逻辑的方式,我们总是要循环的去做一件事情,逐渐的把算法想求解的问题给求解出来


1.通俗解析线性查找循环代码

对于前面学习的线性查找,只有一个重复循环:要做的是每一轮循环中确认一下data[i]是否是目标,如果data[i]和target是相等的,就把i给return回去,否则的话就继续进行这个循环

循环体中只有一个if语句,这个if语句执行完以后,相当于在这一轮循环中确认出了data[i]不是我们的目标,然后就进行下一次的循环

在每轮循环循环结束的时候能确定data[0…i]中没有找到我们的目标

public static <E> int search(E[] data, E target){

for(int i = 0; i < data.length; i ++)

 if(data[i].equals(target))

  return i;

return -1;

   }

1

2

3

4

5

6

2.线性查找循环的开始/末尾

微信图片_20230701104245.png


1️⃣在循环开始的时候,满足一个条件:data[0…i-1]没有找到目标


2️⃣当i等于0的时候,i-1就是-1——这个区间不存在,所以没有找到目标


3️⃣然后我们来判断data[0]是否是目标,如果data[0]不是目标的话,i++在下一轮循环中i变成了1,在i==1这轮循环开始的时候,i-1=0,也就是从0到0这一段区间中没有找到目标,相应的我们来判断data[1]是否是目标


4️⃣还不是目标的话,i++后,i就变成了2,i-1=1,也就是在i==2这轮循环开始的时候,从0到1这一段区间中没有找到目标

… …


✔️循环开始的时候 ,data[0…i-1]这段区间中没有找到目标,整个循环体是判断data[i]是否是目标


🟢如果data[i]是目标,return i

🔴如果不是目标,那么在这个循环末尾的时候就说明data[0…i]都没有找到目标

i++操作后,到了下一轮循环中,下一轮循环的i-1就是上一轮循环结束时的i

3.循环不变量的真面目

3.1 什么是循环不变量

✳️循环不变量其实就是指在每一轮循环开始的时候算法都满足这样的性质:对于上面的线性查找法来说,在每一轮循环开始的时候,都满足data[0…i-1]区间中没有目标target, 区间也可以表示data[0…i),这两种表示方法是等价的,循环每一轮开始的时候都一定是满足这样的一个条件的就叫做循环不变量


在上面的算法代码中,循环体其实就是判断一下data[i]是否是target,如果是的话就return了,如果不是的话,本轮循环就结束了,就要进行下一轮循环。


3.2循环体维持循环不变量

✳️依靠循环体,维持了循环不变量:


public static <E> int search(E[] data, E target){

for(int i = 0; i < data.length; i ++)

 if(data[i].equals(target))

  return i;

return -1;

   }

1

2

3

4

5

6

1️⃣在上面的算法代码中,循环体在做的事情,其实就是在维持这个循环不变量——经过了这轮循环体之后,要么整个循环结束了,完成了return i;要么循环继续,在下一轮循环中依旧满足[0,i-1]这个区间中没有找到目标。


2️⃣在循环结束的时候,如果i = data.length,对应到这个循环不变量中,就是data在[0,data.length-1]即在整个data中都没有找到目标,那么就return -1代表没有找到,如果找到了的话当然就是直接return i了


三、复杂度分析

1. 为何需要复杂度分析?

✅之所以要对算法做复杂度分析,是因为需要表示算法的性能


对于做同样的一个任务,我们会有不同的算法能够完成这个任务,对于不同的算法来说,他们的时间性能有差异,可以具体的用一个或者是一组测试用例对不同的算法都运行一下,实际的去比较一下他们的性能差异,但是这样的比较结果是有局限性的,因为无法保证运行不同的算法的这个计算机性能是完全一致的,甚至很难保证系统当时的状态都是完全一致的。而且这样做我们必须先把这个算法实际的实现出来才能看到它的性能。


❓很多时候有一个算法思想后,我们可不可能通过这个算法的思想就大致评估出算法的性能是优是劣、能否能够满足真正的业务需求再来决定是否要去实现它。


❗这些原因使得我们需要有一套工具能够非常抽象的从数学的层面就去判断一个算法它的性能是怎样的。


✔️为了解决上述需求,就产生了复杂度分析


2.复杂度分析如何表示算法性能?

依旧以前面线性查找的代码为例,分析它的复杂度


public static <E> int search(E[] data, E target){

for(int i = 0; i < data.length; i ++)

 if(data[i].equals(target))

  return i;

return -1;

   }

1

2

3

4

5

6

☑️**逻辑:**从头到尾遍历一次data这个数组,如果发现是我们要找到目标元素的话,返回对应的索引,否则的话整个for循环都走一遍,没有找到目标元素直接return -1


☑️时间:这个算法它执行的时间的多少,其实是和target出现在data中的位置相关的——target就在data[0]的位置,那么for循环执行一趟,算法直接结束,return i即可;如果target在data的末尾或者是target没有在data中,那么这个算法整个for循环从头到尾就都要执行一遍


☑️根据我们的测试用例的不同,算法实际执行的时间是不一样的


✔️对于复杂度分析来说,表示的是我们算法运行的上界,预估算法的性能,即不能比这更差了,通常是看最差的情况的


3.复杂度分析的运用

✳️对于前面线性查找的算法,算法运行的时间的大小,是和data数组中元素个数相关的


☑️通常我们对一个算法所作用的数据的大小叫做数据的规模,使用字母n表示——在线性查找法中,数据规模n就是数组data的大小,即data.length


☑️我们无需仔细的分析一轮循环对n个元素操作需要多少指令,我们只需要知道整个算法的性能和data数组的大小即数据规模n成一个正比的关系,把它记作大O,n级别的算法即O(n)


☑️在算法复杂度分析的世界中,常数是不重要的。


✴️复杂度描述的是随着这个数据规模n的增大算法性能变化的趋势


相关文章
|
2月前
|
机器学习/深度学习 算法 搜索推荐
从理论到实践,Python算法复杂度分析一站式教程,助你轻松驾驭大数据挑战!
【10月更文挑战第4天】在大数据时代,算法效率至关重要。本文从理论入手,介绍时间复杂度和空间复杂度两个核心概念,并通过冒泡排序和快速排序的Python实现详细分析其复杂度。冒泡排序的时间复杂度为O(n^2),空间复杂度为O(1);快速排序平均时间复杂度为O(n log n),空间复杂度为O(log n)。文章还介绍了算法选择、分而治之及空间换时间等优化策略,帮助你在大数据挑战中游刃有余。
87 4
|
22天前
|
并行计算 算法 测试技术
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面,旨在通过综合策略提升程序性能,满足实际需求。
50 1
|
2月前
|
并行计算 算法 IDE
【灵码助力Cuda算法分析】分析共享内存的矩阵乘法优化
本文介绍了如何利用通义灵码在Visual Studio 2022中对基于CUDA的共享内存矩阵乘法优化代码进行深入分析。文章从整体程序结构入手,逐步深入到线程调度、矩阵分块、循环展开等关键细节,最后通过带入具体值的方式进一步解析复杂循环逻辑,展示了通义灵码在辅助理解和优化CUDA编程中的强大功能。
|
2月前
|
算法
PID算法原理分析
【10月更文挑战第12天】PID控制方法从提出至今已有百余年历史,其由于结构简单、易于实现、鲁棒性好、可靠性高等特点,在机电、冶金、机械、化工等行业中应用广泛。
|
3月前
|
算法 搜索推荐 开发者
别再让复杂度拖你后腿!Python 算法设计与分析实战,教你如何精准评估与优化!
在 Python 编程中,算法的性能至关重要。本文将带您深入了解算法复杂度的概念,包括时间复杂度和空间复杂度。通过具体的例子,如冒泡排序算法 (`O(n^2)` 时间复杂度,`O(1)` 空间复杂度),我们将展示如何评估算法的性能。同时,我们还会介绍如何优化算法,例如使用 Python 的内置函数 `max` 来提高查找最大值的效率,或利用哈希表将查找时间从 `O(n)` 降至 `O(1)`。此外,还将介绍使用 `timeit` 模块等工具来评估算法性能的方法。通过不断实践,您将能更高效地优化 Python 程序。
69 4
|
3月前
|
算法 程序员 Python
程序员必看!Python复杂度分析全攻略,让你的算法设计既快又省内存!
在编程领域,Python以简洁的语法和强大的库支持成为众多程序员的首选语言。然而,性能优化仍是挑战。本文将带你深入了解Python算法的复杂度分析,从时间与空间复杂度入手,分享四大最佳实践:选择合适算法、优化实现、利用Python特性减少空间消耗及定期评估调整,助你写出高效且节省内存的代码,轻松应对各种编程挑战。
59 1
|
2月前
|
算法
PID算法原理分析及优化
【10月更文挑战第6天】PID控制方法从提出至今已有百余年历史,其由于结构简单、易于实现、鲁棒性好、可靠性高等特点,在机电、冶金、机械、化工等行业中应用广泛。
|
2月前
|
算法
数据结构(复杂度)
数据结构(复杂度)
27 0
|
3月前
|
算法 数据可视化
基于SSA奇异谱分析算法的时间序列趋势线提取matlab仿真
奇异谱分析(SSA)是一种基于奇异值分解(SVD)和轨迹矩阵的非线性、非参数时间序列分析方法,适用于提取趋势、周期性和噪声成分。本项目使用MATLAB 2022a版本实现从强干扰序列中提取趋势线,并通过可视化展示了原时间序列与提取的趋势分量。代码实现了滑动窗口下的奇异值分解和分组重构,适用于非线性和非平稳时间序列分析。此方法在气候变化、金融市场和生物医学信号处理等领域有广泛应用。
190 19
|
2月前
|
存储 机器学习/深度学习 算法
探索数据结构:入门及复杂度的解锁
探索数据结构:入门及复杂度的解锁
下一篇
DataWorks