当前位置: 首页 > news >正文

算法效率:复杂度原理解析


个人主页: 流年如梦

专栏: 《C语言》 《数据结构》

文章目录

  • 一.数据结构与算法基础
  • 二.算法效率与复杂度概念
  • 三.时间复杂度
    • 3.1定义
    • 3.2大O渐进表示法
    • 3.3最好、最坏、平均情况
    • 3.4举例
      • 3.4.1 双层循环( O(N²) )
      • 3.4.2 单层循环( O(N) )
      • 3.4.3 两个独立变量( O(M+N) )
      • 3.4.4 常数次( O(1) )
      • 3.4.5 查找字符( O(N) )
      • 3.4.6 冒泡排序( O(N²) 或 O(N) )
      • 3.4.7 倍数增长( O(logN) )
      • 3.4.8 阶乘递归( O(N) )
  • 四.空间复杂度
    • 4.1定义
    • 4.2举例
      • 4.2.1 冒泡排序
      • 4.2.2 阶乘递归
  • 五.常见复杂度对比
  • 六.复杂度算法题 --> 旋转数组
    • 6.1方案一 --> 逐次移动(暴力美学)
    • 6.2方案二 --> 创建新的数组
    • 6.3方案三 --> 三次逆置(最优方案)
  • 🎯总结
  • ⚠️易错点

Ladies and gentlemen,本篇文章主要学的是时间复杂度、空间复杂度、大 O 表示法、复杂度计算与常见复杂度对比;全程高能,不容错过!!!
前言

算法复杂度是衡量算法快慢与耗内存的核心标准。不计算精确时间与空间,而是用大O渐进表示法估算增长趋势,用来在编码前就判断算法优劣,写出高效代码

一.数据结构与算法基础

数据结构
数据结构是计算机存储、组织数据的方式,是数据元素之间的关系集合;常见的有顺序表、链表、栈、队列、二叉树、哈希表

算法
算法是一系列计算步骤,把输入转化为输出(为了效率高、资源省、逻辑清晰

重要性:写出高效程序的基础;决定程序在大数据量下是否能跑;对今后的笔试和面试有着重要作用

二.算法效率与复杂度概念

衡量算法好坏主要看时间复杂度和空间复杂度

  1. 时间复杂度--> 衡量算法运行快慢
  2. 空间复杂度--> 衡量算法额外占用内存

三.时间复杂度

3.1定义

时间复杂度是描述算法执行次数与数据规模N的函数关系,用大O表示法表示

不算真实运行时间(受机器或编译器影响),只算执行次数的增长趋势

3.2大O渐进表示法

  1. 只保留最高阶项
  2. 最高阶系数去掉
  3. 常数复杂度统一写O(1)

例如后面举例的双层循环:

其中执行次数为T(N) = N²+2N+10,根据大O渐进表示法我们得知它的时间复杂度为O(N²)

3.3最好、最坏、平均情况

  1. 最好情况:最少执行次数(下界)
  2. 最坏情况:最多执行次数(上界)
  3. 平均情况:期望次数

注意❗复杂度默认取最坏情况

3.4举例

3.4.1 双层循环( O(N²) )

voidFunc1(intN){intcount=0;for(inti=0;i<N;i++)for(intj=0;j<N;j++)count++;for(intk=0;k<2*N;k++)count++;intM=10;while(M--)count++;}

🧐分析:执行次数为T(N) =N²+2N+10,所以时间复杂度为O(N²)大O渐进表示法

3.4.2 单层循环( O(N) )

voidFunc2(intN){for(intk=0;k<2*N;k++)count++;while(10--)count++;}

🧐分析T(N)=2N+10,时间复杂度为O(N)大O渐进表示法

3.4.3 两个独立变量( O(M+N) )

voidFunc3(intN,intM){for(intk=0;k<M;k++);for(intk=0;k<N;k++);}

🧐分析T(N)=M+N,所以时间复杂度为O(M+N)

3.4.4 常数次( O(1) )

voidFunc4(intN){for(intk=0;k<100;k++);}

🧐分析:执行次数固定,时间复杂度为O(1)

3.4.5 查找字符( O(N) )

constchar*strchr(constchar*str,intc){while(*str&&*str!=c)str++;returnstr;}

🧐分析:最好情况时时间复杂度为O(1);最坏情况与平均情况的时间复杂度一样,为O(N)

3.4.6 冒泡排序( O(N²) 或 O(N) )

voidBubbleSort(int*a,intn){for(intend=n;end>0;end--){intexchange=0;for(inti=1;i<end;i++){if(a[i-1]>a[i]){swap(a+i-1,a+i);exchange=1;}}if(exchange==0)break;}}

🧐分析:分两种情况,如果是乱序(即最坏情况),则时间复杂度为O(N²);如果是已排序(即最好情况),则时间复杂度为O(N),一遍就行

3.4.7 倍数增长( O(logN) )

voidfunc5(intn){intcnt=1;while(cnt<n)cnt*=2;}

🧐分析:其中执行次数 x:2ˣ=N-->x=log₂N,所以时间复杂度为O(logN)

3.4.8 阶乘递归( O(N) )

longlongFac(size_tN){if(N==0)return1;returnFac(N-1)*N;}

🧐分析:递归N次,时间复杂度为O(N)

四.空间复杂度

4.1定义

空间复杂度衡量算法额外开辟的临时空间,不算输入输出本身占用的空间,同样与时间复杂度使用大O表示法

4.2举例

4.2.1 冒泡排序

voidBubbleSort(...){intexchange;}

🧐分析:因为只开辟常数个变量,所以空间复杂度为O(1)

4.2.2 阶乘递归

longlongFac(size_tN){if(N==0)return1;returnFac(N-1)*N;}

🧐分析:因为递归调用N层栈帧,所以空间复杂度为O(N)

五.常见复杂度对比

如下表格👇:

从快到慢依次为复杂度
常数O(1)
对数O(logN)
线性O(N)
线性对数O(NlogN)
平方O(N²)
立方O(N³)
指数O(2ⁿ)
阶乘O(N!)

下面为时间复杂度对比曲线图👇:

六.复杂度算法题 --> 旋转数组

转跳力扣👉LeetCode 189:旋转数组

原题

6.1方案一 --> 逐次移动(暴力美学)

voidrotate(int*nums,intlen,intk){while(k--){intend=nums[len-1];for(inti=len-1;i>0;i--)nums[i]=nums[i-1];nums[0]=end;}}

提交结果

🧐分析:时间复杂度为O(N×K)O(N²),空间复杂度为O(1);但缺点是数据量大超时

6.2方案二 --> 创建新的数组

voidrotate(int*nums,intlen,intk){int*tmp=(int*)malloc(len*sizeof(int));for(inti=0;i<len;i++)tmp[(i+k)%len]=nums[i];for(inti=0;i<len;i++)nums[i]=tmp[i];free(tmp);}

🧐分析:时间复杂度为O(N),空间复杂度为O(N);相对于思路一它不会因为数据量大超时,可行

6.3方案三 --> 三次逆置(最优方案)

voidreverse(int*nums,intbegin,intend){while(begin<end){intt=nums[begin];nums[begin]=nums[end];nums[end]=t;begin++;end--;}}voidrotate(int*nums,intlen,intk){k%=len;reverse(nums,0,len-k-1);reverse(nums,len-k,len-1);reverse(nums,0,len-1);}

🧐分析:时间复杂度为O(N),空间复杂度为O(1)

🎯总结

  1. 复杂度衡量时间快慢、空间大小
  2. 时间复杂度看执行次数,空间复杂度看额外开辟空间
  3. 统一用大O渐进表示法,只看最高阶
  4. 算法默认取最坏复杂度
  5. 复杂度从优到劣O(1)<O(logN)<O(N)<O(NlogN)<O(N²)
  6. 旋转数组最优:三次逆置O(N)时间 +O(1)空间

⚠️易错点

  1. 计算复杂度时保留低阶项或系数
  2. 递归复杂度不会算(看递归深度)
  3. logN复杂度判断错误
  4. 混淆时间或者空间复杂度
  5. 暴力算法超时,不会优化

👀 关注我们一路同行,从入门到大师,慢慢沉淀、稳步成长
❤️ 点赞鼓励原创,让优质内容被更多人看见
⭐ 收藏收好核心知识点与实战技巧,需要时随时查阅
💬 评论分享你的疑问或踩坑经历,一起交流避坑、共同进步

http://www.jsqmd.com/news/715216/

相关文章:

  • Matlab信号处理:FFT频谱分辨率
  • 免费音乐解锁工具Unlock-Music:打破平台限制,让音乐自由播放
  • Dism++终极指南:5分钟学会Windows系统优化与维护
  • 从一次真实的HW行动复盘讲起:我们是如何通过‘弱口令字典’快速突破内网的?
  • 为什么92%的AI团队在Docker AI Toolkit 2026 Beta测试中放弃Kubeflow?4个核心接入指标对比实测报告
  • 2026年3月水塔拆除工程队推荐,室外装修拆除/拆除垃圾清运/酒店装修拆除/水塔拆除/房屋建筑拆除,水塔拆除工程怎么选择 - 品牌推荐师
  • EgerGergeeert 企业知识库构建:从零搭建基于向量检索的 QA 系统
  • Qwen3-4B-Instruct部署教程:supervisor.conf配置解析与进程守护机制
  • Verilog 进阶教程(个人总结)
  • 用香橙派OrangPi PC和Lakka,打造你的复古游戏机:从镜像烧录到中文设置全攻略
  • MCP (Model Context Protocol) 深度解析:构建下一世代 AI Agent 的基石
  • 2026年分销小程序开发:为什么我只推荐微积木?深度实测对比 - 品牌企业推荐师(官方)
  • 从Docker Desktop到边缘网关:12分钟复现完整WASM微服务链路(含metrics暴露、自动扩缩容策略)
  • A53性能验证:从微架构到系统级——芯片性能的“全息检测“
  • 《心跳文学部》Mod制作避坑指南:从option.rpy到definitions.rpy,这些文件千万别乱改
  • 新盟创业者戈壁徒步挑战赛 - 新沙州文旅
  • 终极内存健康检测指南:用Memtest86+快速定位系统不稳定元凶
  • vue3 - 基于 Vue3 + Vite4 + TypeScript5 + Element-Plus + Pinia 技术栈的后台管理系统
  • 八年携手同行!昊客网络 净万嘉,解锁制造企业数字化成长样本 - 深圳昊客网络
  • 彻底告别Microsoft Edge自动重装:EdgeRemover开源工具完全指南
  • 告别卡顿!PixiJS资产管理系统让资源加载快3倍的终极指南
  • CH9329避坑指南:从选型到调试,搞定USB HID透传的3个关键步骤
  • 别再只发一次了!用C++写个UDP消息重发机制,解决局域网传输丢包问题
  • 2026中医执医考试课程选择:面向这五大类考生的选择指南 - 医考机构品牌测评专家
  • 【简单】在双链表中删除倒数第K个节点-Java
  • 用MATLAB手把手教你画4QAM到256QAM的BER性能曲线(附完整代码)
  • 缺失 released SAP API 时,ABAP Cloud 项目怎样守住 Clean Core
  • JCSprout位运算:从基础到实战的Java高效算法优化指南
  • GNOME Pomodoro:终极番茄工作法工具,提升300%生产力效率
  • 从GB2312到GBK:在STM32上实现全字符集中文显示的避坑指南