算法设计的目标:
1.找到问题的解法
2.寻找最优解法
衡量算法的优劣的的主要评价指标:时间效率、空间效率
效率评估的方法:实际测试、理论估算
复杂度分析能够体现算法运行所需的时间和空间资源与输入数据大小之间的关系
迭代与递归
实现方式:
迭代循环结构函数调用自身时间效率效率通常较高,无函数调用开销
递归每次函数调用都会产生开销
内存使用:
迭代:通常使用固定大小的内存空间
递归:累积函数调用可能使用大量的栈帧空间
适用问题:
迭代:适用于简单循环任务,代码直观、可读性好适用于子问题
递归:分解,如树、图、分治、回溯等,代码结构简洁、清晰
时间复杂度和空间复杂度
时间复杂度的意义:评断算法的优劣的指标、算法优化的导向
时间复杂度类型:
常数阶O(1):常数阶的操作数量与输入数据大小 n无关,即不随着 n的变化而变化。
线性阶O(n):线性阶的操作数量相对于输入数据大小 n以线性级别增长。线性阶通常出现在单层循环中。
平方阶O(n²):平方阶的操作数量相对于输入数据大小 n以平方级别增长。平方阶通常出现在嵌套循环中,外层循环和内层循环的时间复杂度都为 O(n) ,因此总体的时间复杂度为 O(n²) 。
指数阶O(2^n):生物学的“细胞分裂”是指数阶增长的典型例子:初始状态为 1 个细胞,分裂一轮后变为 2 个,分裂两轮后变为 4 个,以此类推,分裂n轮后有 2^n 个细胞。
对数阶(log n):对数阶反映了“每轮缩减到一半”的情况。设输入数据大小为 n ,由于每轮缩减到一半,因此循环次数是 log2 n ,即 2^n 的反函数。
线性对数阶(nlogn):线性对数阶常出现于嵌套循环中,两层循环的时间复杂度分别为 O(logn) 和 O(n)。
阶乘阶O(n!):
阶乘阶对应数学上的“全排列”问题。给定 � 个互不重复的元素,求其所有可能的排列方案,方案数量为:n!=n×(n−1)×(n−2)×⋯×2×1
阶乘通常使用递归实现。
“最差时间复杂度”对应函数渐近上界,使用大O记号表示。相应地,“最佳时间复杂度”对应函数渐近下界,用Ω记号表示。
空间复杂度 space complexity:用于衡量算法占用内存空间随着数据量变大时的增长趋势。这个概念与时间复杂度非常类似,只需将“运行时间”替换为“占用内存空间”。
算法在运行时使用的三种空间:
1.输入空间 2.暂存空间 3.输出空间
空间复杂度的统计范围是“暂存空间”加上“输出空间”
暂存空间可以划分为三个部分:
- 暂存数据:用于保存算法运行过程中的各种常量、变量、对象等。
- 栈帧空间:用于保存调用函数的上下文数据。系统在每次调用函数时都会在栈顶部创建一个栈帧,函数返回后,栈帧空间会被释放。
- 指令空间:用于保存编译后的程序指令,在实际统计中通常忽略不计。
常数阶常见于数量与输入数据大小n无关的常量、变量、对象
线性阶常见于元素数量与n 成正比的数组、链表、栈、队列
平方阶常见于矩阵和图,元素数量与 n成平方关系
指数阶常见于二叉树,满二叉树的结点个数为2^n-1
对数阶常见于分治算法。例如归并排序,输入长度为n的数组,每轮递归将数组从中点处划分为两半,形成高度为 logn 的递归树,使用 O(logn) 栈帧空间。