系统掌握数据结构2-算法
算法:算法是解决特定问题求解步骤的描述,在计算机中表现为指令的有限序列,并且每条指令表示一个或多个操作。
(数据结构中的算法是为了更加清晰的了解数据结构问题求解的过程,算法是另外一门课,所以这门课不会涉及背包问题、贪心、动态规划等)
1.算法的特性
- 输入输出:算法有零个或多个输入,一个或多个输出。
- 有穷性:算法在执行有限的步骤后结束,并且每一个步骤在可接受的时间内完成。
- 确定性:算法的每一步骤都具有确定的含义,不会出现二义性。
- 可行性:算法的每一步都是可行的,也就是说,每一步都能通过执行有限次数完成。
2.算法设计的要求
- 正确性:是指至少应该具有输入输出和加工处理无歧义能正确反映问题的需求、能够得到问题的正确答案。
- 可读性:便于阅读、理解和交流。(命名、注释等)
- 健壮性:输入数据不合法是,算法也能做出相关处理而不是产生异常或莫名其妙的结果。
- 效率与低存储量需求:效率指执行时间,设计算法应该尽量满足执行时间少、存储需求低。
3.算法效率的度量方法
1.引论
- 函数的渐进增长:给定两个函数f(n)和g(n),如果存在一个正数N,使得对于所有的n>N,f(n)总是比g(n)大,那么,我们说f(n)的增长渐进快于g(n)。
(这个定义有什么意义呢?我们来看一张表格)
(算法A要执行2n+3次操作,算法B要执行3n+1次操作,n逐渐增大)
(随着n的增大我们发现,常数是不影响算法A与算法B的比较的,结合函数的渐近增长,无论g(n)加了多大的常数,当n>N时,f(n)总是大于g(n)。正如表中所示:算法A’仍然优于算法B’,即使一个+3,一个+1)
(在上面这个表中,随着n的增大我们发现,与最高次项相乘的常数并不重要,算法C优于算法D,算法C’优于算法D’,即使C乘以了4又加了8,而D乘以了2又加1)
(在上面这个表中,随着n的增大我们发现,最高次项的指数大的,结果增长的也会特别快)
(这个是最后一张表格了,我们发现,随着n的增大,算法H已经没办法和其他两个算法比较了,而其他两个算法相差的操作次数和自身的操作次数比微不足道,2 000 000 000 000和3 000 001相比后者微不足道。通过以上直观的分析,我们可以引入时间复杂度)
2.时间复杂度
- 算法的时间复杂度:在进行算法分析时,语句总的执行次数T(n)是关于问题规模n的函数,进而分析T(n)随n的变化情况并确定T(n)的数量级。T(n) =O(f(n))。它表示随着n的增大,算法执行时间的增长率和f(n)的增长率相同。f(n)是问题规模n的某个函数。
(定义有些啰嗦,简而言之,T(n)是指一个数量级,例如O(n),O(n^2))
-
时间复杂度的计算:最高次项是常数为O(1),否则为O(最高次项/与该项相乘的常数)
*常数阶:f(n) = 3是常数,所以时间复杂度=O(1)。
(下图仍然是O(1)
线性阶:下面代码操作次数是n+1,时间复杂第=O(n)
int i; for (i = 0;i < n;i++){ print("执行了一次") }
对数阶:设循环执行x次,2^x=n,x = logn(下标为2)。故时间复杂度=O(logn) (此处不写下标)
int count = 1; while (count < n ){ count = count * 2 }
平方阶:嵌套循环,时间复杂度=O(n^2),若外循环m次则为O(m*n)
int i,j; for(i = 0; i < n; i++){ for(j = 0; i < n; j++){ print("执行了一次") } }
举个例子,下面的代码计算一下时间复杂度
int i,j; for(i = 0; i < n; i++){ for(j = i; i < n; j++){ print("执行了一次") } }
这段代码和上面只差了一个j=i,其实操作次数=1+2+3+…+n=(1+n)*n/2。所以时间复杂度=O(n^2)
(其实求时间复杂度是个数学问题,大家可以随便复习下高数数列的知识,并不难)
(常用的时间复杂度如上图,若考试中你的算法比O(n^2)还大,很可能被扣分)
3.时间复杂度的三种情况
- 最好时间复杂度:情况最好的时间下,例如查找算法查到第一个元素就是。
- 平均时间复杂度:平均情况下的时间复杂度,很难分析出。
- 最坏时间复杂度:运行最坏条件下,是一种保证,不会更坏了,我们所算的都是最坏时间复杂度。
4.空间复杂度
算法的空间复杂度通过计算算法所需要的存储空间实现,算法空间复杂度的计算公式记作:S(n)=O(f(n))。其中n为问题规模,f(n)为语句关于n所占存储空间的函数。
当S(n)=O(1)时我们称为原地工作。通常我们可以用空间换时间或者时间换空间。
(这门课的重点是时间复杂度,空间复杂度再以后学算法时会简单提到。)
4.结语
(程序设计 = 数据结构 + 算法,空洞的数据结构是没有作用的,这一章介绍算法的基本概念,尤其是时间复杂度的概念非常重要。在以后的学习中,每学习一种算法我们都会尝试计算它的时间复杂度。感谢阅读!)