数据结构:时间复杂度
文章目录
- 为什么需要时间复杂度分析?
- 一、大O表示法:复杂度的语言
- 1.1 什么是大O?
- 1.2 常见复杂度速查表
- 二、实战分析:解剖C语言代码
- 2.1 循环结构的三重境界
- 单层循环:线性时间
- 双重循环:平方时间
- 动态边界循环:隐藏的平方
- 2.2 递归的时空折叠
- 线性递归:阶乘计算
- 指数递归:斐波那契噩梦
- 三、高级技巧:复杂度组合计算
- 3.1 顺序结构:取最大值
- 3.2 嵌套结构:乘积法则
- 四、常见误区与破解之道
- 误区1:误判循环边界
- 误区2:低估数学级数
- 破解工具:关键公式
- 五、复杂度优化实战
- 案例:寻找数组中的重复元素
- 暴力解法(O(n²))
- 优化方案(O(n))
- 六、自测练习
- 结语:复杂度即格局
为什么需要时间复杂度分析?
想象你正在处理一个包含百万条数据的数组:
- O(n²) 的算法可能需要几天才能完成
- O(n log n) 的算法可能只需几秒
- O(n) 的算法眨眼间就能得出结果
时间复杂度就像算法的「体检报告」,它揭示了代码执行效率如何随数据规模增长而变化。本文将用C语言示例,手把手教你掌握这项核心技能!
一、大O表示法:复杂度的语言
1.1 什么是大O?
- 本质:描述算法执行时间的增长趋势
- 特点:忽略常数项和低阶项,专注主要矛盾
- 公式:
T(n) = O(f(n))表示存在常数C,使得当n足够大时,T(n) ≤ C·f(n)
1.2 常见复杂度速查表
| 复杂度 | 典型场景 | 可视化增长趋势 |
|---|---|---|
| O(1) | 数组下标访问 | 水平直线 |
| O(log n) | 二分查找 | 缓慢爬坡 |
| O(n) | 遍历数组 | 线性上升 |
| O(n log n) | 快速排序 | 优雅曲线 |
| O(n²) | 冒泡排序 | 陡峭抛物线 |
| O(2ⁿ) | 暴力穷举 | 垂直火箭 |
二、实战分析:解剖C语言代码
2.1 循环结构的三重境界
单层循环:线性时间
// 示例:计算数组和
int sum = 0;
for (int i = 0; i < n; i++) { // 执行n次sum += array[i]; // O(1)操作
}
// 总复杂度:O(n)
双重循环:平方时间
// 示例:打印所有数对
for (int i = 0; i < n; i++) { // 外层n次for (int j = 0; j < n; j++) { // 内层n次printf("(%d,%d)", i, j); // O(1)操作}
}
// 总复杂度:O(n) × O(n) = O(n²)
动态边界循环:隐藏的平方
for (int i = 0; i < n; i++) { // 外层n次for (int j = 0; j < i; j++) { // 内层i次(0到n-1)count++; // 总次数 = 0+1+2+...+(n-1) = n(n-1)/2}
}
// 总复杂度:O(n²)
2.2 递归的时空折叠
线性递归:阶乘计算
int factorial(int n) {if (n <= 1) return 1; // 基准情形return n * factorial(n-1); // 递归调用n次
}
// 调用栈深度:O(n)
// 时间复杂度:O(n)
指数递归:斐波那契噩梦
int fib(int n) {if (n <= 1) return n;return fib(n-1) + fib(n-2); // 每次产生2个分支
}
// 时间复杂度:O(2ⁿ) (实际约为O(1.618ⁿ))
递归树呈指数级展开
三、高级技巧:复杂度组合计算
3.1 顺序结构:取最大值
void process_data(int n) {// 阶段1: O(n)for (int i=0; i<n; i++) { /* ... */ }// 阶段2: O(n²)for (int i=0; i<n; i++) {for (int j=0; j<n; j++) { /* ... */ }}
}
// 总复杂度 = O(n) + O(n²) = O(n²)
3.2 嵌套结构:乘积法则
void matrix_ops(int n) {for (int i=0; i<n; i++) { // O(n)for (int j=1; j<n; j*=2) { // O(log n)printf("%d", i*j); // O(1)}}
}
// 总复杂度 = O(n) × O(log n) = O(n log n)
四、常见误区与破解之道
误区1:误判循环边界
int k = 0;
while (k < 100) { // 固定循环100次process(data[k++]);
}
// 真实复杂度:O(1) 而非 O(n)
误区2:低估数学级数
for (int i=1; i<=n; i*=2) { // 执行次数:log₂nfor (int j=0; j<i; j++) { // 内层总次数:1+2+4+...+2^log₂n = 2n-1count++;}
}
// 总复杂度:O(n) 而非 O(n log n)
破解工具:关键公式
- 等差数列和:
1+2+3+...+n = n(n+1)/2 → O(n²) - 等比数列和:
1+2+4+...+2^k = 2^(k+1)-1 → O(2^k) - 对数计算:
循环变量i每次乘以2 → 循环次数log₂n
五、复杂度优化实战
案例:寻找数组中的重复元素
暴力解法(O(n²))
for (int i=0; i<n; i++) {for (int j=i+1; j<n; j++) {if (arr[i] == arr[j]) return true;}
}
优化方案(O(n))
// 使用哈希表记录出现次数
int hash_table[MAX_SIZE] = {0};
for (int i=0; i<n; i++) {if (hash_table[arr[i]]++) return true;
}
六、自测练习
- 分析以下代码复杂度:
for (int i=0; i<n; i+=5) {for (int j=0; j<1000; j++) {sum += i*j;}
}
答案:O(n)(外层循环n/5次,内层固定1000次 → 忽略常数后为线性)
- 递归函数复杂度分析:
void fun(int n) {if (n <= 0) return;printf("%d", n);fun(n/2);fun(n/2);
}
答案:O(n)(递归树总节点数=1+2+4+…+n → 约2n个节点)
结语:复杂度即格局

不同复杂度的时间增长对比
掌握时间复杂度分析,就像获得了一副「算法透视眼镜」:
- 在面试中快速评估解法优劣
- 在大数据场景下避免性能灾难
- 培养对代码的直觉敏感性
下次看到嵌套循环时,试着在心中画出它的增长曲线。当复杂度从O(n²)优化到O(n log n)时,那种思维的跃迁感,正是编程最迷人的魔法时刻!
相关文章:
数据结构:时间复杂度
文章目录 为什么需要时间复杂度分析?一、大O表示法:复杂度的语言1.1 什么是大O?1.2 常见复杂度速查表 二、实战分析:解剖C语言代码2.1 循环结构的三重境界单层循环:线性时间双重循环:平方时间动态边界循环&…...
[创业之路-276]:从燃油汽车到智能汽车:工业革命下的价值变迁
目录 前言: 从燃油汽车到智能汽车:工业革命下的价值变迁 前言: 燃油汽车,第一次、第二次工业革命,机械化、电气化时代的产物,以机械和电气自动化为核心价值。 智能汽车,第三次、第四次工业革…...
vue页面和 iframe多页面无刷新方案和并行 并接入 micro 微前端部分思路
前: 新进了一家公司,公司是做电商平台的, 用的系统竟然还是jsp的网站,每次修改页面还需要我下载idea代码,作为一个前端, 这可不能忍,于是向上申请,意思你们后台做的太辣鸡,我要重做,经领导层商议从去年6月开始到今年12月把系统给重构了 公司系统采用的是每个jsp页面都是一个ifr…...
Linux特权组全解析:识别GID带来的权限提升风险
组ID(Group ID,简称 GID)是Linux系统中用来标识不同用户组的唯一数字标识符。每个用户组都有一个对应的 GID,通过 GID,系统能够区分并管理不同的用户组。 在Linux系统中,系统用户和组的配置文件通常包括以…...
RTMP 和 WebRTC
WebRTC(Web Real-Time Communication)和 RTMP(Real-Time Messaging Protocol)是两种完全不同的流媒体协议,设计目标、协议栈、交互流程和应用场景均有显著差异。以下是两者的详细对比,涵盖协议字段、交互流程及核心设计思想。 一、协议栈与设计目标对比 特性RTMPWebRTC传…...
系统通解:超多视角理解
在科学研究和工程应用中,我们常常面临各种复杂系统,需要精确描述其行为和变化规律。从物理世界的运动现象,到化学反应的进程,再到材料在受力时的响应,这些系统的行为往往由一系列数学方程来刻画。通解,正是…...
11.享元模式 (Flyweight)
定义 Flyweight 模式(享元模式) 是一种结构型设计模式,它旨在通过共享对象来有效支持大量细粒度对象的复用。该模式主要通过共享细节来减少内存使用,提升性能,尤其在需要大量对象时非常有效。 基本思想: …...
Python 自学秘籍:开启编程之旅,人生苦短,我用python。
从2009年,用了几次python后就放弃了,一直用的php,现在人工智能时代,完全没php什么事情。必须搞python了,虽然已经40多岁了。死磕python了。让滔滔陪着你一起学python 吧。 开启新世界 在当今人工智能化的时代ÿ…...
验证工具:SVN版本控制
1-SVN概念 SVN(Subversion)是一种集中式版本控制系统,它用于文件和目录的版本管理,允许多个用户协同工作,同时追踪每个文件和目录的历史修改记录。以下是关于SVN版本控制的详细介绍: 一、SVN的基本概念 仓库(Repository):SVN的仓库是一个集中存储所有文件和目录的地…...
每日一题洛谷P5721 【深基4.例6】数字直角三角形c++
#include<iostream> using namespace std; int main() {int n;cin >> n;int t 1;for (int i 0; i < n; i) {for (int j 0; j < n - i; j) {printf("%02d",t);t;}cout << endl;}return 0; }...
React开发中箭头函数返回值陷阱的深度解析
React开发中箭头函数返回值陷阱的深度解析 一、箭头函数的隐式返回机制:简洁背后的规则二、块函数体中的显式返回要求:容易被忽视的细节三、真实场景下的案例分析案例1:忘记return导致组件渲染失败案例2:异步操作中的返回值陷阱 四…...
解决每次打开终端都需要source ~/.bashrc的问题(记录)
新服务器或者电脑通常需要设置一些环境变量,例如新电脑安装了Anaconda等软件,在配置环境变量后发现每次都需要重新source,非常麻烦,执行下面添加脚本实现一劳永逸 vim .bash_profile# .bash_profileif [ -f ~/.bashrc ]; then. ~…...
解决DeepSeek服务器繁忙问题:本地部署与优化方案
deepseek服务器崩了,手把手教你如何在手机端部署一个VIP通道! 引言 随着人工智能技术的快速发展,DeepSeek等大语言模型的应用越来越广泛。然而,许多用户在使用过程中遇到了服务器繁忙、响应缓慢等问题。本文将探讨如何通过本地部…...
【后端开发】系统设计101——通信协议,数据库与缓存,架构模式,微服务架构,支付系统(36张图详解)
【后端开发】系统设计101——通信协议,数据库与缓存,架构模式,微服务架构,支付系统(36张图) 文章目录 1、通信协议通信协议REST API 对比 GraphQL(前端-web服务)grpc如何工作&#x…...
Java基础——分层解耦——IOC和DI入门
目录 三层架构 Controller Service Dao 编辑 调用过程 面向接口编程 分层解耦 耦合 内聚 软件设计原则 控制反转 依赖注入 Bean对象 如何将类产生的对象交给IOC容器管理? 容器怎样才能提供依赖的bean对象呢? 三层架构 Controller 控制…...
武汉火影数字|VR虚拟现实:内容制作与互动科技的奇妙碰撞
VR虚拟现实是一种利用计算机技术生产三维虚拟世界的技术,通过头戴式显示器、手柄等设备,用户可以身临其境地感受虚拟世界,与其中的物体进行自然交互。 当内容制作遇上 VR,会发生什么? 当内容制作遇上VR,就像…...
一文了解性能优化的方法
背景 在应用上线后,用户感知较明显的,除了功能满足需求之外,再者就是程序的性能了。因此,在日常开发中,我们除了满足基本的功能之外,还应该考虑性能因素。关注并可以优化程序性能,也是体现开发能…...
SpringBoot扩展篇:@Scope和@Lazy源码解析
SpringBoot扩展篇:Scope和Lazy源码解析 1. 研究主题及Demo2. 注册BeanDefinition3. 初始化属性3.1 解决依赖注入3.2 创建代理 ContextAnnotationAutowireCandidateResolver#getLazyResolutionProxyIfNecessary3.3 代理拦截处理3.4 单例bean与原型bean创建的区别 4. …...
tkvue 入门,像写html一样写tkinter
介绍 没有官网,只有例子 安装 像写vue 一样写tkinter 代码 pip install tkvue作者博客 修改样式 import tkvue import tkinter.ttk as ttktkvue.configure_tk(theme"clam")class RootDialog(tkvue.Component):template """ <Top…...
c++ stl 遍历算法和查找算法
概述: 算法主要由头文件<algorithm> <functional> <numeric> 提供 <algorithm> 是所有 STL 头文件中最大的一个,提供了超过 90 个支持各种各样算法的函数,包括排序、合并、搜索、去重、分解、遍历、数值交换、拷贝和…...
Hackmyvm Connection
基本信息 难度:简单 靶机:192.168.194.11 kali:192.168.194.9 扫描 常规nmap扫描起手 nmap -sT -sV -A -T4 192.168.194.11 -p- 查看smb服务开启目录 139和445端口的smb服务直接以访客账号登录,无需密码验证成功。对应的ht…...
内置渲染管线和通用渲染管线的区别
内置渲染管线和通用渲染管线(URP)有以下区别: 功能特性 内置渲染管线:提供了一套较为基础的渲染功能,包括几何渲染、光照计算、阴影生成和后期处理等基本环节。但自定义选项相对有限,渲染次序基本是固…...
Unity 2D实战小游戏开发跳跳鸟 - 记录显示最高分
上一篇文章中我们实现了游戏的开始界面,在开始界面中有一个最高分数的UI,本文将接着实现记录最高分数以及在开始界面中显示最高分数的功能。 添加跳跳鸟死亡事件 要记录最高分,则需要在跳跳鸟死亡时去进行判断当前的分数是否是最高分,如果是最高分则进行记录,如果低于之前…...
算法随笔_40: 爬楼梯
上一篇:算法随笔_39: 最多能完成排序的块_方法2-CSDN博客 题目描述如下: 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢? 示例 1: 输入:n 2 输出:2 解释&am…...
数据结构(2)——线性表与顺序表实现
目录 前言 一、线性表 二、顺序表 2.1概念 2.2类型的选择 2.3实现 1.初始化 2.检查是否需要扩容 3.尾插 4.尾删 5.头插 6.头删 7.某一个位置添加 8.某一个位置删除 9.基于某一位置的尾插删 10.查找 11.修改 12.销毁 总结 前言 今天对顺序表进行学习…...
全面解析机器学习优化算法中的进化策略
全面解析机器学习优化算法中的进化策略 全面解析机器学习优化算法中的进化策略引言什么是进化策略?基本概念核心组件算法流程数学基础高斯扰动期望值更新与其他优化方法的比较梯度下降法(Gradient Descent, GD)遗传算法(Genetic Algorithm, GA)Python案例基本实现改进版:…...
【LeetCode】5. 贪心算法:买卖股票时机
太久没更了,抽空学习下。 看一道简单题。 class Solution:def maxProfit(self, prices: List[int]) -> int:cost -1profit 0for i in prices:if cost -1:cost icontinueprofit_ i - costif profit_ > profit:profit profit_if cost > i:cost iret…...
软件测试丨PyTorch 图像目标检测
随着人工智能和机器学习的飞速发展,图像目标检测技术在各个领域扮演着越来越重要的角色。无论是在安防监控、自动驾驶车辆,还是在医疗影像分析和智能家居中,图像目标检测都发挥着不可或缺的作用。今天,我们将深入探讨其中一种热门…...
SpringSecurity密码编码器:使用BCrypt算法加密、自定义密码编码器
1、Spring Security 密码编码器 Spring Security 作为一个功能完备的安全性框架,一方面提供用于完成加密操作的 PasswordEncoder 组件,另一方面提供一个可以在应用程序中独立使用的密码模块。 1.1 PasswordEncoder 抽象接口 在 Spring Security 中,PasswordEncoder 接口代…...
FastReport.NET控件篇之交叉表控件
认识交叉表 上面是交叉表的原型,关键的三个单元格。 单元格①:用于扩展行数据,譬如打印学生成绩表时,每个学生一行,那么这个地方就是以学生姓名列进行打印。 单元格②:用于扩展列数据,譬如打印…...
