目录
1.与数据元素本身的形式、内容、大小个数等无关的是数据的(B )
8.在算法输入规模为n时,算法运行时间正比于9log(3 n),则该算法的时间复杂度为
1.算法特性与评价算法
1.1引言:
算法是一系列的操作相当于去做特定目的的事情,一步一步操作的集合
1.2菜谱特性:
比如菜谱:要保证能做出一道美味的菜应该具备那些特性
有穷:有穷步,才能结束
确定:不能模棱两可,到底放盐还是放糖
可行:这个菜要到火星上去炒?!
→算法特性:有穷性,确定性,可行性,输入性,输出性
1.3评价菜谱:
正确:菜谱书上把花椒打成了芥末
可读:加50%NaCl
健壮:没有考虑边界人群,对某一种调料忌用
高效:明明三步,搞成三百步
→算法评价:正确性,可读性,健壮性,高效性
→如何评价一道菜谱也是评价算法,这四点不是必须满足,虽然不满足,但也可以作出一道菜,只是评价低了
1.4总结
算法:做一件事的步骤 => 有穷、确定、可行、输入、输出 => 正确、可读、健壮、高效
2.如何衡量高效→最坏的复杂度
2.1引言
假如买房,别人给你说先生我们的房子距离某地很近,开车15min可以到,后来买主实地调查,15min是在凌晨三点没车,超速才能完成。
可想而知15min不能评价距离,不是一个保证,实际应用中可能遇到早高峰,保证最糟糕情况下需要多少时间 一定能做完,需要多少额外的空间一定能完成
复杂度是一个上限,用O(数量级)表示
数量级与输入规模有关,O是一个渐进符号。
输入规模表达式是一个数量级,不带常量,10N的数量级为N,假如算出输入规模为10N写N
2.2总结
• (最坏)复杂度:1. 时间复杂度:给定输入规模n,在 最坏情况 下需要多少时间 一定 能做完2. 空间复杂度:给定输入规模n,在 最坏情况 下需要多少 额外 空间 一定 能做完复杂度是一个保证,一个承诺3.例题
3.1选择题
1.与数据元素本身的形式、内容、大小个数等无关的是数据的(B )
A.存储结构(实践元素与元素之间的关系)B.逻辑结构(描述元素与元素之间的关系)C.存储实现D.运算实现2.从逻辑上可以把数据结构分成(C )
A.动态结构和静态结构B.紧凑结构和非紧凑结构C.线性结构和非线性结构D.内部结构和外部结构3.下面哪个是非线性数据结构(A)
A.树B.字符串C.队列D.栈4.对一个算法的评价,不包括如下( C)方面的内容
A.正确性和可读性B.健壮性C.并行性D.时间复杂度3.2计算复杂度
1.分析下列算法(程序段)的时间复杂度:
算法输入:n和m int ans = 0; for (int i = 0; i < n; i += 1) { for (int j = 0; j < m; j += 1) { ans += 1; } }
用上限执行次数表示时间复杂度重复多少遍取决于输入,也就是输入规模外层循环为线性循环,内层循环为线性循坏,可以算出具体循环多少遍内层循坏执行次数与m有关,对于每一次外层,每个j都会做m次循环分析:在给定算法输入n和m的情况下,该嵌套循环内的语句将至多执行nm次,因此运行时间的上限, 也即时间复杂度是O(mn).例1变式:
int ans = 0; for (int i = 0; i < n; i += 1) { for (int j = 0; j < m; j += 1) { ans += 1; ans - =1; ans+=1; } }
分析:在给定算法输入n和m的情况下,该嵌套循环内的语句将至多执行3nm次,因此运行时间的上限, 也即时间复杂度是O(3nm),但输入表达式为数量级写为O(nm)2.分析下列算法(程序段)的时间复杂度:
算法输入:大小为n的数组nums、一个整数val for (int i = 0; i < n; i += 1) { if (nums[i] == val) { return i; } }
算法复杂度不是衡量具体执行次数,而是去找与输入规模呈什么数量级,不带常数,算出表达式中取输入规模有关的最高阶分析:最坏情况下,val位于nums的最后一位,循环内的if判断需要执行n次,因此时间复杂度为O(n).换句话说,这个算法保证在执行 至多n次 判断后能结束,这是理解时间复杂度的另一个角度。3.分析下列算法(程序段)的时间复杂度:
算法输入:n int ans = 0; for (int i = 1; i <= n; i += 1) { if (i > 1000) break; ans += i; }
分析:无论输入n是多少,循环 至多 执行1000次,因此时间复杂度为O(1000),也即常数复杂度不管这个常数多大,我们都认为其为O(1)。O表示渐近数,指的是随着循环次数的增加,时间复杂度的数量级4.分析下列算法(程序段)的时间复杂度:
算法输入:n int ans = 0; for (int i = 1; i <= n; i += 1) { for (int j = 1; j < n; j *= 2) { ans += 1; } }
2^x=n,x=log2(n),内层循环次数为log2(n),对数中底数是可以改变的且不被影响,因此2可以不写,直接写log(n)
分析:内层循环(j)次数和 n 呈 对数关系 → 因此内层复杂度是O(log 2 (n))外层循环(i)次数和 n 呈 线性关系 → 即执行n次O(log 2 (n))的内层循环,得到O(n * log 2 (n))即O(n * log (n))5.分析下列算法(程序段)的时间复杂度:
// 内层循环的上限在变动!算法输入:n int ans = 0; for (int i = 0; i < n; i += 1) { for (int j = 0; j < i; j += 1) { ans += 1; } }
①计算确切的执行次数表达式②取最高阶项0 + 1 + 2 + 3 + ... + (n - 1)= (n - 1) * n / 2= n^2 / 2 - n / 2分析:对 i 为 0,1,2,...,n - 1时,内层循环的循环次数:0, 1, 2, 3, ..., n - 1 求和得到的表达式中,最高阶的项是n 2 ,因此整个表达式的数量级是n 2 ,最终答案为O(n ^ 2 )6.分析下列算法(程序段)的时间复杂度:
算法输入:n int ans = 0; for (int i = 1; i <= n; i += 1) { for (int j = 1; j <= i; j *= 2) { ans += 1; } }
分析:对log 2 (1), log 2 (2), log 2 (3), ... log 2 (n) 求和:log 2 (1)+log 2 (2)+log 2 (3)+...+log 2 (n)= log 2 (n!)= C * n * log 2 (n) (C为某个常数)(公式记住即可)7.分析下列算法(程序段)的时间复杂度:
算法输入:n int ans = 0; for (int i = 1; i <= n; i *= 2) { for (int j = 1; j <= i; j += 1) { ans += 1; } }
分析:对2^ 0 , 2^ 1 , 2^ 2 , 2^ 3 ... 2^ log2(n) 求和:2^ 0 + 2^ 1 + 2^ 2 + 2^ 3 + ... + 2^ log2(n)= 1 + 2 + 4 + 8 + 16 +...+ n= 1 * (1 - 2^ log2(n) ) / (1 - 2)= 2^ log2(n) = n8.在算法输入规模为n时,算法运行时间正比于9log(3 n),则该算法的时间复杂度为
O(n)分析:9log(3^ n ) = 9nlog(3),对于算法的复杂度分析时,我们不关心 常数 和 低阶项 ,只关心和输入规模n有关的数量级,因此O(9n*log(3)) → O(n)4.总结
给定n时,算法确切执行的语句次数?随着n增加,算法执行的语句次数如何增加!⭐ Key 1 :逻辑结构描述的是关系,与数据元素本身特点以及计算机参数等没有关系⭐ Key 2 :算法的5个特性:有穷、确定、可行、输入和输出⭐ Key 3 :算法的4个评价准则:正确性、可读性、健壮性、高效性⭐ Key 4 :算法复杂度是一个保证,用O(数量级)表示⭐ Key 5 :算法复杂度描述的是算法执行时间的增加和输入规模的增加呈何种关系
算法与复杂度
最新推荐文章于 2024-07-25 11:43:17 发布