算法效率的评估
评估算法效率的好坏主要涉及到算法的时间复杂度(Time Complexity)、空间复杂度(Space Complexity)以及在实际应用中的运行性能。 曾经调侃中文压缩包事件[1] ,白话、成语、文言文,大多数时候我们明意思白时间和知识量是递增的,时间增长和我们学习的文言文长短有关,就可以一定程度上反映难度,时间的增长情况反映的更为明显, 我们要查的书籍也会增长,要的知识量就会越大,反映他的增长情况(求一阶导数的作用)这些因素有助于我们理解算法在不同输入规模下的表现,预测其在实际应用中的可行性和效率。以下是评估算法效率的几个关键方面:
1. 时间复杂度
时间复杂度是描述算法运行时间如何随着输入规模增加而变化的数学表示。常见的时间复杂度有:
计算时间复杂度(Time Complexity)主要是通过分析算法的运行步骤,并估算其在输入规模 (n) 增长时,执行步骤的增长情况。这通常涉及以下几个步骤:
1. 识别算法中的基本操作
基本操作是算法中最频繁执行的操作,通常是最内层的操作,可以是比较、赋值、交换等。
2. 计算基本操作的执行次数
分析算法中基本操作随输入规模 (n) 增长的执行次数。通常需要分析循环、递归等结构的执行次数。
3. 用大O表示法表示时间复杂度
将基本操作的执行次数表示为输入规模 (n) 的函数,并使用大O表示法来表示时间复杂度。大O表示法关注的是执行次数增长的数量级,而忽略常数因子和低阶项。
具体示例
1. 常数时间复杂度 (O(1))
算法的运行时间不随输入规模的变化而变化。
int x = 5; // 这个操作只执行一次,与输入规模无关
2. 线性时间复杂度 (O(n))
算法的运行时间与输入规模成正比。例如,一个遍历数组的操作:
for (int i = 0; i < n; i++) {
System.out.println(arr[i]);
}
此处,基本操作 System.out.println
执行 (n) 次,所以时间复杂度是 (O(n))。
3. 平方时间复杂度 (O(n^2))
算法的运行时间与输入规模的平方成正比。例如,两个嵌套的循环:
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
System.out.println(arr[i][j]);
}
}
此处,基本操作 System.out.println
在每次外层循环中执行 (n) 次,而外层循环也执行 (n) 次,总执行次数为 n2,所以时间复杂度是 (O(n^2))。
4. 对数时间复杂度 (O(log n))
算法的运行时间随输入规模的对数增长。
例如,二分查找:
int binarySearch(int[] arr, int target) {
int low = 0, high = arr.length - 1;
while (low <= high) {
int mid = (low + high) / 2;
if (arr[mid] == target) {
return mid;
} else if (arr[mid] < target) {
low = mid + 1;
} else {
high = mid - 1;
}
}
return -1;
}
此处,每次迭代都将搜索范围减半,因此基本操作的执行次数是对数级别的,时间复杂度是 (O(log n))。
5. 线性对数时间复杂度 (O(n log n))
例如,快速排序在平均情况下的时间复杂度:
void quickSort(int[] arr, int low, int high) {
if (low < high) {
int pi = partition(arr, low, high);
quickSort(arr, low, pi - 1);
quickSort(arr, pi + 1, high);
}
}