算法复杂度分析是评估算法效率的关键工具,它帮助我们理解算法在不同规模输入下的性能表现。下面我将全面介绍C++中常见的算法复杂度分析方法。
复杂度 | 名称 | 示例算法 |
---|---|---|
O(1) | 常数时间 | 数组随机访问 |
O(log n) | 对数时间 | 二分查找 |
O(n) | 线性时间 | 线性搜索 |
O(n log n) | 线性对数时间 | 快速排序、归并排序 |
O(n²) | 平方时间 | 冒泡排序、选择排序、插入排序 |
O(n³) | 立方时间 | 简单的矩阵乘法 |
O(2ⁿ) | 指数时间 | 汉诺塔问题 |
O(n!) | 阶乘时间 | 旅行商问题的暴力解法 |
笔记(notes):好算法和坏算法的关键,就在于增加的快慢。好的算法,这个求解时间随着 n 增加不能太快。
问:那么什么叫快,什么叫慢呢?
答:数学家有一个定义,只要一个算法找到答案所需要的时间,能做到n^k可以了。这里的n就是问题的规模。
n^k 是n的多项式,因此满足这个条件的算法,叫做多项式时间算法。多项式时间算法是一个好算法。
比如上方的冒泡排序以及简单的矩阵乘法就可以说是好算法。
O(1) 示例:
int getFirstElement(const vector<int>& arr) {
if (!arr.empty()) return arr[0];
return -1;
}
O(n) 示例:
int linearSearch(const vector<int>& arr, int target) {
for (int num : arr) {
if (num == target) return num;
}
return -1;
}
O(n²) 示例:
void bubbleSort(vector<int>& arr) {
int n = arr.size();
for (int i = 0; i < n-1; i++) {
for (int j = 0; j < n-i-1; j++) {
if (arr[j] > arr[j+1]) swap(arr[j], arr[j+1]);
}
}
}
O(log n) 示例:
int binarySearch(const vector<int>& arr, int target) {
int left = 0, right = arr.size()-1;
while (left <= right) {
int mid = left + (right-left)/2;
if (arr[mid] == target) return mid;
if (arr[mid] < target) left = mid+1;
else right = mid-1;
}
return -1;
}
复杂度 | 描述 | 示例算法 |
---|---|---|
O(1) | 常量空间 | 冒泡排序、插入排序 |
O(n) | 线性空间 | 归并排序 |
O(log n) | 对数空间 | 快速排序(递归栈空间) |
O(n²) | 平方空间 | 某些动态规划实现 |
O(1) 空间复杂度:
void reverseArray(vector<int>& arr) {
int left = 0, right = arr.size()-1;
while (left < right) {
swap(arr[left++], arr[right--]);
}
}
O(n) 空间复杂度:
vector<int> mergeSort(const vector<int>& arr) {
if (arr.size() <= 1) return arr;
int mid = arr.size()/2;
auto left = mergeSort(vector<int>(arr.begin(), arr.begin()+mid));
auto right = mergeSort(vector<int>(arr.begin()+mid, arr.end()));
return merge(left, right); // 需要额外空间存储合并结果
}
示例:斐波那契数列(低效版本):
int fib(int n) {
if (n <= 1) return n;
return fib(n-1) + fib(n-2);
}
时间复杂度:O(2ⁿ)(指数级)
优化版本(动态规划):
int fib(int n) {
if (n <= 1) return n;
vector<int> dp(n+1);
dp[0] = 0; dp[1] = 1;
for (int i = 2; i <= n; i++) {
dp[i] = dp[i-1] + dp[i-2];
}
return dp[n];
}
时间复杂度:O(n)
空间复杂度:O(n)(可优化到O(1))
算法/操作 | 时间复杂度 | 空间复杂度 |
---|---|---|
std::sort | O(n log n) | O(log n) |
std::stable_sort | O(n log n) | O(n) |
std::partial_sort | O(n log k) | O(log n) |
std::nth_element | O(n) | O(1) |
std::binary_search | O(log n) | O(1) |
vector:(动态数组)
list:(双向链表)
map/set:(关联容器,键值对集合)
unordered_map/unordered_set:(哈希表实现的键值对映射,键唯一/哈希表实现的唯一元素集合)
通过了解算法复杂度分析,可以预测算法性能,做出更合理的算法选择,优化现有代码的效率。
So,不要再用那些坏算法了,学学更高效的吧!
(大数据来了,有些算法抵不住啊,必须要更新自己的知识库了)
(题外话:算法的改进需要人,人也需要反过来“驯服”算法,大家加油!)