算法效率的度量(上):时间复杂度中的对数思维

一、大O表示法:只看趋势

大O表示法描述的是算法执行时间随数据规模增长的变化趋势。推导时只需记住:保留最高阶项,去掉所有系数。

例如:2N + 3logN + 10 最终记为 O(N)。


二、O(log N):折半就是对数

对数复杂度的核心特征只有一个:每次循环或递归,问题的规模都缩小一半(或按固定比例缩小)。

2.1 循环折半

复制代码
#include <stdio.h>
/*
 * 功能:演示对数复杂度 O(log N)
 * 关键特征:循环变量 i 每次乘以 2(翻倍)
 * 
 * 推导:设循环执行 x 次后结束
 * 第1次:i = 2
 * 第2次:i = 4
 * 第3次:i = 8
 * ...
 * 第x次:i = 2^x
 * 
 * 结束条件:2^x >= N  =>  x >= log₂N
 * 因此时间复杂度为 O(log N)
 */
void demoLogN(int N) {
    int count = 0;
    int i = 1;
while (i < N) {
    i = i * 2;      // 关键:每次翻倍
    count++;
}
printf("N=%d, 循环次数=%d\n", N, count);
}
int main() {
demoLogN(16);       // N=16, 循环4次 (log₂16 = 4)
demoLogN(1024);     // N=1024, 循环10次
return 0;
}

快速判断 :看到循环变量 i *= 2 或 i /= 2,立刻想到 O(log N)。底数是 2 还是 3 不影响大O表示。

2.2 二分查找

复制代码
#include <stdio.h>
/*
 * 功能:二分查找,在有序数组中查找目标值
 * 时间复杂度:O(log N)
 * 
 * 核心思想:每次比较后,搜索范围缩小一半
 * 无论目标在哪,最多只需 log₂N 次比较
 */
int binarySearch(int arr[], int n, int target) {
    int left = 0;
    int right = n - 1;
while (left <= right) {
    int mid = left + (right - left) / 2;  // 防止溢出的写法
if (arr[mid] == target) {
    return mid;         // 找到目标
}
else if (arr[mid] < target) {
    left = mid + 1;     // 目标在右半部分,范围减半
}
else {
    right = mid - 1;    // 目标在左半部分,范围减半
}
}
return -1;  // 未找到
}
int main() {
int arr[] = {3, 8, 12, 25, 31, 47, 58, 69, 81, 95};
int n = 10;
int result = binarySearch(arr, n, 47);
printf("查找结果下标:%d\n", result);  // 输出 5
return 0;
}

2.3 递归折半

复制代码
#include <stdio.h>
/*
 * 功能:递归方式演示对数复杂度
 * 时间复杂度:O(log N)
 * 
 * 分析:递归深度决定了执行次数
 * 每次递归 N 变为 N/2,深度为 log₂N
 * 每层只执行常数操作(打印、判断)
 */
void recursiveHalve(int N) {
    if (N <= 1) {
        return;             // 递归终止条件
    }
printf("当前 N = %d\n", N);
recursiveHalve(N / 2);  // 关键:每次规模减半
}
int main() {
recursiveHalve(16);     // 会打印 16, 8, 4, 2,共 log₂16 = 4 层
return 0;
}

三、O(N log N):线性遍历套折半操作

O(N log N) 是高效排序算法(如归并排序、堆排序)的典型复杂度。它的结构很固定:外层是 N 次的线性遍历,内层是 O(log N) 的折半操作。

复制代码
#include <stdio.h>
/*
 * 功能:演示线性对数复杂度 O(N log N)
 * 
 * 外层循环:i 从 1 到 N,执行 N 次
 * 内层循环:j 每次翻倍,执行 log N 次
 * 总操作次数 = N * log N
 */
void demoNLogN(int N) {
    int total = 0;
for (int i = 1; i <= N; i++) {      // 外层:线性 N 次
    int j = 1;
while (j < N) {                 // 内层:对数 log N 次
    j = j * 2;
    total++;
}
}
printf("N=%d, 总操作次数=%d\n", N, total);
}
int main() {
demoNLogN(8);   // 8 * 3 = 24
demoNLogN(16);  // 16 * 4 = 64
return 0;
}

实际场景 :对 N 个元素分别进行一次二分查找,整体就是 O(N log N)。


四、快速判断口诀

表格

代码特征 时间复杂度 判断要点
循环变量每次乘2或除2 O(log N) 折半、翻倍就是对数
外层 N 次 + 内层折半 O(N log N) 线性套对数
递归每次规模减半 O(log N) 递归深度为 log N
递归先遍历 N 再折半递归(两次) O(N log N) 类似归并排序的递归树

五、练习题

题目1:

复制代码
void funcA(int N) {
    int i = N;
    while (i > 1) {
        i = i / 3;      // 每次变为原来的 1/3
    }
}

时间复杂度是多少?

题目2:

复制代码
void funcB(int N) {
    for (int i = 0; i < N; i++) {
        int j = 1;
        while (j < N) {
            j = j * 2;
        }
    }
}

时间复杂度是多少?

题目3(递归):

复制代码
void funcC(int N) {
    if (N <= 1) return;
    funcC(N / 2);
}

时间复杂度是多少?

题目4(递归):

复制代码
void funcD(int N) {
    if (N <= 1) return;
    for (int i = 0; i < N; i++) {
        printf("%d ", i);
    }
    printf("\n");
    funcD(N / 2);
    funcD(N / 2);
}

时间复杂度是多少?

题目5(双参数):

复制代码
void funcE(int N, int M) {
    for (int i = 0; i < N; i++) printf("1");
    for (int j = 0; j < M; j++) printf("2");
}

时间复杂度是多少?(提示:O(M+N) 与 O(max(M,N)) 在渐进意义下等价,因为 max(M,N) ≤ M+N ≤ 2×max(M,N),两者只相差常数倍。通常写 O(M+N) 更直观。)

答案与解析

表格

题号 时间复杂度 解析
1 O(log N) 循环变量每次除以3,底数不影响大O
2 O(N log N) 外层N次 × 内层log N次
3 O(log N) 递归深度为 log N,每层常数操作
4 O(N log N) 递归树深度为 log N,每层总工作量约为 N(N + N/2 + N/2 = 2N),总复杂度为 O(N log N)
5 O(M+N) 两个独立循环,复杂度相加。也可写作 O(max(M,N))
相关推荐
Dream it possible!11 分钟前
蓝桥杯_翻转_C++
c++·算法·蓝桥杯
Ivanqhz12 分钟前
BURG(自底向上重写生成器)
服务器·数据库·人工智能·深度学习·算法
言乐618 分钟前
逻辑回归与利弊
人工智能·算法·机器学习·数据挖掘·逻辑回归
海绵宝宝转agent27 分钟前
Leetcode100 二叉树的中序遍历
java·算法
根目录下的猫32 分钟前
ROS 2 C++(rclcpp)版本,实现话题订阅、话题发布,以及完整编译运行流程
开发语言·c++·算法
大侠归来2 小时前
C 语言 | 在函数中操作数组
c语言·c++·算法
怕浪猫7 小时前
GEO 优化到底是什么?AI时代内容创作者必须懂的新技能
算法·面试·github
朝朝辞暮i9 小时前
C++ 第 23 课:class —— 开始真正进入面向对象
开发语言·c++·算法
7yewh9 小时前
SLAM 三维空间刚体运动(2)
数据结构·人工智能·机器人·嵌入式·slam
Evand J9 小时前
【MATLAB例程】三维RRT+APF避障路径规划与到达角(AOA)定位算法|三维路径优化与定位仿真例程
算法·matlab·路径规划·代码·定位·rrt·aoa