算法效率的度量(下):空间复杂度与递归栈
一、空间复杂度衡量什么空间复杂度衡量的是算法执行过程中额外申请的内存空间不包括输入数据本身占用的空间。我们关注的是当数据规模 N 增大时额外内存是否随之增长。二、O(1)固定额外空间如果算法只使用了固定数量的变量无论 N 多大内存占用都不变就是 O(1)。#include stdio.h /* * 功能查找数组中的最大值 * 空间复杂度O(1) * * 只使用了 maxVal 和 i 两个变量 * 没有申请与 N 相关的额外空间 */ int findMax(int arr[], int N) { int maxVal arr[0]; // 固定变量1 for (int i 1; i N; i) { // 固定变量2 if (arr[i] maxVal) { maxVal arr[i]; } } return maxVal; }三、O(N)额外数组空间当算法需要创建一个与输入规模 N 相当的新数组来存储中间结果时空间复杂度为 O(N)。#include stdio.h /* * 功能复制数组并反转 * 空间复杂度O(N) * * 创建了一个长度为 N 的辅助数组 helper * 额外空间随 N 线性增长 */ void reverseCopy(int arr[], int N) { int helper[N]; // 额外申请 N 个空间 for (int i 0; i N; i) { helper[i] arr[N - 1 - i]; } for (int i 0; i N; i) { printf(%d , helper[i]); } printf(\n); }四、递归的栈空间重点递归函数的空间复杂度不是看代码里定义了几个变量而是看递归调用栈的深度。每次递归调用系统都会在内存栈中创建一个栈帧来保存局部变量和返回地址。4.1 递归深度为 N每次减1#include stdio.h /* * 功能递归递减演示 O(N) 空间复杂度 * * 递归过程 * recurse(4) - recurse(3) - recurse(2) - recurse(1) * * 每一层递归都会占用一个栈帧同时存在的栈帧最多有 N 个 * 因此空间复杂度为 O(N) */ void recurseDown(int N) { if (N 1) { printf(到达底部\n); return; } int local N; // 局部变量存在当前栈帧中 printf(递归层 N%d\n, N); recurseDown(N - 1); // 每次减1深度为 N } int main() { recurseDown(4); return 0; }内存中的栈帧分布以 N4 为例栈顶 | recurse(1) | - 最先创建最后释放 | recurse(2) | | recurse(3) | 栈底 | recurse(4) | - 最后创建最先释放同时存在的栈帧有 4 个即 N 个。4.2 递归深度为 log N每次减半#include stdio.h /* * 功能递归折半演示 O(log N) 空间复杂度 * * 递归过程 * recurse(16) - recurse(8) - recurse(4) - recurse(2) - recurse(1) * * 深度为 log₂N同时最多只存在 log N 个栈帧 * 因此空间复杂度为 O(log N) */ void recurseHalve(int N) { if (N 1) { printf(到达底部\n); return; } int local N; printf(递归层 N%d\n, N); recurseHalve(N / 2); // 每次规模减半深度为 log N } int main() { recurseHalve(16); // 深度为 4 (16-8-4-2-1) return 0; }4.3 二分查找的递归版本#include stdio.h /* * 功能递归版二分查找 * 时间复杂度O(log N) * 空间复杂度O(log N) - 注意这里 * * 虽然代码里只有 left, right, mid 三个变量 * 但递归深度为 log N每层栈帧都要保存这些变量 * 因此总空间复杂度由递归深度决定 */ int binarySearchRec(int arr[], int left, int right, int target) { if (left right) { return -1; // 没找到 } int mid left (right - left) / 2; if (arr[mid] target) { return mid; } else if (arr[mid] target) { return binarySearchRec(arr, mid 1, right, target); } else { return binarySearchRec(arr, left, mid - 1, target); } }五、时间与空间的本质区别理解空间复杂度时必须牢记一个关键区别时间不能复用第一次循环花了 10ms第二次循环又花 10ms总时间是累加的。空间可以复用第一层递归的栈帧在函数返回后就被销毁了这块内存可以留给后面的递归层使用。因此空间复杂度只看同时存在的最大空间不是累计申请的空间。六、快速判断口诀代码特征空间复杂度判断要点固定数量的局部变量O(1)与 N 无关长度为 N 的辅助数组O(N)额外数组大小递归每次规模减1O(N)递归深度 N递归每次规模减半O(log N)递归深度 log N递归深度 log N 每层固定数组O(log N)空间可复用看最大同时占用七、练习题题目1void s1(int N) { int a, b, c; for (int i 0; i N; i) { a i; } }空间复杂度是多少题目2void s2(int N) { int temp[N]; // 额外数组 for (int i 0; i N; i) { temp[i] i; } }空间复杂度是多少题目3void s3(int N) { if (N 1) return; s3(N - 1); }空间复杂度是多少题目4void s4(int N) { if (N 1) return; s4(N / 2); }空间复杂度是多少题目5void s5(int N) { if (N 1) return; int arr[100]; // 固定大小100的数组 s5(N / 2); }空间复杂度是多少注意每层都有 arr[100]但空间可复用答案与解析题号空间复杂度解析1O(1)只有固定变量 a, b, c, i2O(N)申请了长度为 N 的辅助数组3O(N)递归深度为 N每次减14O(log N)递归深度为 log N每次减半5O(log N)递归深度为 log N。虽然每层有 arr[100]但栈帧是先后使用的不是同时存在最大同时空间为 100 × log N即 O(log N)

相关新闻

柔性生产系统技术解析:人形机器人如何实现换型换线与自适应工艺执行

柔性生产系统技术解析:人形机器人如何实现换型换线与自适应工艺执行

一、为什么刚性生产正在失效?传统刚性制造系统(Rigid Manufacturing System, RMS)的架构设计遵循"专用化"原则:特定的机械结构、固化的控制逻辑、预定义的工艺参数,所有设计决策都指向单一目标——在既定产品…

2026/11/4 8:11:58 阅读更多 →
XAML Border 控件完全教程

XAML Border 控件完全教程

一、Border 是什么在 WPF、.NET MAUI、Xamarin.Forms、UWP、WinUI 等 XAML 技术栈中&#xff0c;Border 是一个装饰性布局容器。它的核心职责只有一个&#xff1a;给单个子元素添加边框、背景、圆角和内边距等视觉装饰。二、最基础的用法 <Border Background"Li…

2026/11/13 19:44:13 阅读更多 →
涌现现象模拟

涌现现象模拟

>涌现现象1. 没有总控制器&#xff1a;没有代码直接指挥群体怎么流动、怎么编队&#xff1b;2. 每个个体只有 3 条极简局部规则&#xff1a;a.向同伴平均位置靠近b.和离得太近的个体保持距离c.和周围同伴运动方向对齐涌现结果&#xff1a;大量小球自发形成群组、分流、盘旋&…

2026/10/24 15:06:15 阅读更多 →

最新新闻

Electron桌面应用开发实战:从环境搭建到打包发布全流程

Electron桌面应用开发实战:从环境搭建到打包发布全流程

做前端这些年&#xff0c;我大部分时间都在跟浏览器标签页打交道&#xff0c;直到第一次把桌面应用跑起来&#xff0c;才发现原来自己一直被限制在地址栏和刷新按钮围起来的框框里。Electron这个词&#xff0c;最开始是在某段时间频繁出现在同事的讨论里&#xff0c;一个用HTML…

2026/11/14 5:13:29 阅读更多 →
滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

简介&#xff1a;亚太天能T109滑盖智能锁产品说明书是一份PDF格式的官方技术文档&#xff0c;主要面向智能锁安装人员、终端用户及售后维护者&#xff0c;帮助快速掌握产品安装、配置与常见故障处理。全包仅1个PDF文件&#xff0c;大小4.37MB&#xff0c;内容结构清晰&#xff…

2026/11/14 5:13:29 阅读更多 →
PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

上个月我在调试一台高速AGV的驱动系统&#xff0c;整车要求空载跑到8m/s&#xff0c;电机转速已经拉到额定点&#xff0c;驱动器的输出电压也顶到了母线电压极限附近。再往上踩速度指令&#xff0c;转速纹丝不动&#xff0c;三相电流反而开始震荡。那会儿我的第一反应就是&…

2026/11/14 5:13:29 阅读更多 →
C++核心知识点:从内存管理到STL的实战指南

C++核心知识点:从内存管理到STL的实战指南

C 这门语言我前前后后折腾了十几年&#xff0c;用它写过嵌入式驱动、做过游戏服务端&#xff0c;也搭过基础组件库。每次看到新人一头扎进"C 核心知识点"这个搜索词&#xff0c;我其实挺感慨的——这门语言的难点从来不是语法多&#xff0c;而是知识点之间的耦合太深…

2026/11/13 22:08:41 阅读更多 →
T109滑盖智能锁怎么装?安装调试与故障排查全攻略

T109滑盖智能锁怎么装?安装调试与故障排查全攻略

简介&#xff1a;亚太天能T109滑盖智能锁产品说明书以PDF格式发布&#xff0c;适合智能锁用户、安装人员与售后维修人员阅读。内容围绕T109系列指纹密码刷卡锁展开&#xff0c;先介绍前面板、后面板、锁体、机械钥匙、电池盒盖等部件名称与功能&#xff0c;再给出完整安装步骤&…

2026/11/14 2:41:37 阅读更多 →
LLM知识降熵:从信息垄断到理解权下放

LLM知识降熵:从信息垄断到理解权下放

你有没有过这种经历&#xff1a;翻开源码注释、论文摘要或者一份专业报告&#xff0c;每个字都认识&#xff0c;连在一起却像天书。想找人聊聊&#xff0c;身边要么没人懂&#xff0c;要么懂的懒得跟你解释。后来我试着把同一段内容丢给一个大语言模型&#xff0c;几秒钟之后&a…

2026/11/14 5:13:29 阅读更多 →

日新闻

周新闻

月新闻