算法(问题求解步骤的一种描述)
- 时间复杂度:算法计算执行的基本操作次数(与数据量相关)
- 空间复杂度:算法需要消耗多少辅助空间(与数据量相关,不计数据本身占用的空间)
- 算法在时间的高效性和空间的高效性之间通常是矛盾的,所以会有"时间换空间,空间换时间"一说
时间复杂度
执行时间固定的操作都是常数时间操作
- 算术运算 (+ - * / % 等)
- 位运算( >> >>> << | & ^ 等)
- 赋值 比较 数组寻址 HashMap查找指定元素 等
执行时间不固定的操作都是非常数时间操作
- 链表查询指定元素
执行效率(由高至低)
常数阶O(1) -> 对数阶O(
l
o
g
2
n
{log_2{n}}
log2n) -> 线性阶O(n) -> 线性对数阶O(n
l
o
g
2
n
{log_2{n}}
log2n) -> 平方阶O(
n
2
{n^2}
n2) -> 立方阶O(
n
3
{n^3}
n3) -> k次方阶O(
n
k
{n^k}
nk) -> 指数阶O(
2
n
{2^n}
2n) -> 指数阶O(
k
n
{k^n}
kn) -> 阶乘O(N!)k
ps: markdown显示 2 l o g 2 n 7 2^{log_2{n^7}} 2log2n7 的方法
$2^{log_2{n^7}}$
计算时间复杂度
只保留最高阶项, 忽略常数项, 样本量很大情况下, 低阶项及每项的系数并不重要; 以最差情况来计算复杂度, 概率事件算期望.
- 选择排序(ASC):
第一轮:
第一个数与后面每个数比较, 较小值交换至第一个位置;(第一个数字为最小值)
第二轮:
第二个数与后面每个数比较, 较小值交换至第二个位置;(第二个数字为次小值)
…
后续同理(每次循环在[m, n]区间内获取最小值, 放置m处)
常数操作次数 = (n-1) * (元素寻址(查询)+比较) + 交换 + (n-2) * (元素寻址+比较) + 交换 …
常数操作次数 = (n-1) * (2) + 1 + (n-2) * (2) + 1 … 1*2 + 1
常数操作次数 = n 2 {n^2} n2 + n
T(n) = O( n 2 {n^2} n2 )
不稳定排序 : (相等数据的顺序被打乱)
[7, 7, 3]
[3, 7, 7] 原顺序第一个7到了第二个7后面
- 冒泡排序(ASC):
第一轮:
第一个数与第二个数比较, 较小值交换至第一个位置; 第二个数与第三个数比较, 较小值交换至第二个位置…第n-1与第n个数比较, 较小值交换至第n-1位置;(第n个数字为最大值)
第二轮:
第一个数与第二个数比较, 较小值交换至第一个位置; 第二个数与第三个数比较, 较小值交换至第二个位置…第n-2与第n-1个数比较, 较小值交换至第n-2位置;(第n-1个数字为次最大值)
…
后续同理(每次循环在[1, n-m]区间内获取最大值, 放置n-m处)
常数操作次数 = (n-1) * (元素寻址(查询)+比较) + 交换 + (n-2) * (元素寻址+比较) + 交换 …
常数操作次数 = (n-1) * (2) + 1 + (n-2) * (2) + 1 … 1*2 + 1
常数操作次数 = n 2 {n^2} n2 + n
T(n) = O( n 2 {n^2} n2 )
稳定排序 : (相等数据的顺序保持不变)
[7, 7, 3]
[7, 3, 7] 原顺序第一个7还是在第二个7前面
[3, 7, 7]
- 插入排序(ASC):
第一轮:
第一个数,与前一个数(null)相比有序不处理( 类似斗地主,每抽一张牌按顺序方式插入原先牌库 )
第二轮:
第二个数与第一个数比较, 第二个数较小则交换至第一个位置,否则结束此轮,
第三轮:
第三个数与第二个数比较, 第三个数较小则交换至第二个位置,否则结束此轮; 若没结束,则第二个数与第一个数比较, 第二个数较小则交换至第一个位置,否则结束此轮;
…
后续同理(每次循环加入一个数n-m, 与有序区间[1, n-m-1]进行排序合并后, 当前数据[1, n-m]中的最大值, 放置n-m处)
常数操作次数 = 0 * 元素寻址+比较) + 交换 + 1 * (元素寻址+比较) + 交换 … (n-1) * (元素寻址(查询)+比较) + 交换
常数操作次数 = 0 + 1 * 2+1 + 2 * 2+1 + … + (n-1) * (2) + 1
常数操作次数 = n 2 {n^2} n2 + n
T(n) = O( n 2 {n^2} n2 )
特殊情况: {1, 2, 3} 使用插入排序遍历 N-1 次即有序
稳定排序 : (相等数据的顺序保持不变)
{7, 7, 3}
{7, 3, 7} 原顺序第一个7还是在第二个7前面
{3, 7, 7}
空间复杂度
- 一个算法在运行过程中临时占用存储空间大小的一个量度(与数据量相关)
- 算法执行所需临时空间不随着数据量(n)的大小而变化,即此算法空间复杂度为一个常量,可表示为 O(1)
- 算法执行所需临时空间随着数据量(n)的大小而变化: 以二分查找(递归)为例,递归深度是 l o g 2 n {log_2{n}} log2n,每次递归的辅助空间为常数,所以空间复杂度为O( l o g 2 n {log_2{n}} log2n)