时间复杂度与空间复杂度分析

一、什么是复杂度?

1.1 为什么需要复杂度分析?

假设你写了两个程序来解决同一个问题,如何判断哪个程序更好?我们不能只看运行时间,因为:

  • 不同电脑性能不同
  • 同一电脑在不同时刻状态也不同
  • 数据规模不同,结果也不同

所以我们需要一个客观的标准来衡量算法的效率,这就是复杂度分析。

1.2 两种复杂度

  • 时间复杂度:程序运行需要多少时间(执行多少步骤)
  • 空间复杂度:程序运行需要多少额外内存

二、时间复杂度基础

2.1 什么是时间复杂度?

时间复杂度描述的是随着输入规模n的增长,程序执行时间的增长趋势

让我们看一个最简单的例子:

// 例子1:打印一个数字
void print_once(int n) {printf("%d\n", n);  // 执行1次
}

无论n是多少,这个函数都只执行1次打印操作。

// 例子2:打印n次
void print_n_times(int n) {for (int i = 0; i < n; i++) {printf("%d ", i);  // 执行n次}
}

这个函数会执行n次打印操作。

2.2 大O表示法

我们用大O表示法来描述时间复杂度:

  • O(1) - 常数时间
  • O(n) - 线性时间
  • O(n²) - 平方时间
  • O(log n) - 对数时间

上面的例子1是O(1),例子2是O(n)。

2.3 如何计算时间复杂度?

步骤1:计算每行代码的执行次数

void example(int n) {int sum = 0;           // 执行1次for (int i = 0; i < n; i++) {sum += i;          // 执行n次}printf("%d", sum);     // 执行1次
}
// 总执行次数:1 + n + 1 = n + 2

步骤2:保留最高次项,忽略常数

  • n + 2 → O(n)
  • 3n² + 2n + 1 → O(n²)
  • 5n³ + 100n → O(n³)

三、常见时间复杂度详解

3.1 O(1) - 常数时间复杂度

// 无论数组多大,都只访问一个元素
int get_first(int arr[], int n) {return arr[0];  // O(1)
}// 简单的数学运算
int calculate(int a, int b) {int sum = a + b;      // O(1)int product = a * b;  // O(1)return sum + product; // O(1)
}  // 总体:O(1)

3.2 O(n) - 线性时间复杂度

// 遍历数组一次
int find_max(int arr[], int n) {int max = arr[0];              // O(1)for (int i = 1; i < n; i++) {  // 循环n-1次if (arr[i] > max) {        // O(1)max = arr[i];          // O(1)}}return max;                    // O(1)
}  // 总体:O(n)

3.3 O(n²) - 平方时间复杂度

// 双重循环 - 冒泡排序
void bubble_sort(int arr[], int n) {for (int i = 0; i < n - 1; i++) {      // 外循环:n-1次for (int j = 0; j < n - i - 1; j++) { // 内循环:平均n/2次if (arr[j] > arr[j + 1]) {// 交换int temp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = temp;}}}
}  // 总体:O(n²)

3.4 O(log n) - 对数时间复杂度

// 二分查找(数组必须有序)
int binary_search(int arr[], int n, int target) {int left = 0, 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;
}  // 总体:O(log n)

为什么是O(log n)?因为每次循环都将搜索范围减半:

  • n → n/2 → n/4 → … → 1
  • 需要log₂n次才能将n减到1

四、空间复杂度

4.1 什么是空间复杂度?

空间复杂度描述的是程序运行过程中需要的额外内存空间

注意:

  • 输入数据占用的空间不算
  • 只计算额外申请的空间

4.2 空间复杂度示例

// O(1) 空间复杂度 - 只用了固定的几个变量
int sum_array(int arr[], int n) {int sum = 0;  // 额外空间:1个intfor (int i = 0; i < n; i++) {sum += arr[i];}return sum;
}// O(n) 空间复杂度 - 创建了新数组
int* copy_array(int arr[], int n) {int* new_arr = (int*)malloc(n * sizeof(int));  // 额外空间:n个intfor (int i = 0; i < n; i++) {new_arr[i] = arr[i];}return new_arr;
}// O(n) 空间复杂度 - 递归调用
int factorial(int n) {if (n <= 1) return 1;return n * factorial(n - 1);  // 递归调用栈:O(n)
}

五、复杂度分析实战

5.1 分析技巧

  1. 看循环

    • 单层循环通常是O(n)
    • 双层嵌套循环通常是O(n²)
    • 三层嵌套循环通常是O(n³)
  2. 看递归

    • 递归深度 × 每层的工作量
  3. 看数据结构

    • 数组访问:O(1)
    • 链表查找:O(n)

5.2 综合例子

// 分析这个函数的时间和空间复杂度
void process_matrix(int n) {// 创建二维数组 - 空间:O(n²)int** matrix = (int**)malloc(n * sizeof(int*));for (int i = 0; i < n; i++) {matrix[i] = (int*)malloc(n * sizeof(int));}// 初始化 - 时间:O(n²)for (int i = 0; i < n; i++) {for (int j = 0; j < n; j++) {matrix[i][j] = i + j;}}// 查找最大值 - 时间:O(n²)int max = matrix[0][0];for (int i = 0; i < n; i++) {for (int j = 0; j < n; j++) {if (matrix[i][j] > max) {max = matrix[i][j];}}}// 释放内存for (int i = 0; i < n; i++) {free(matrix[i]);}free(matrix);
}
// 时间复杂度:O(n²) + O(n²) = O(n²)
// 空间复杂度:O(n²)

六、复杂度比较

当n很大时,不同复杂度的差异:

n值O(1)O(log n)O(n)O(n log n)O(n²)O(2ⁿ)
101310331001,024
1001710066410,0001.27×10³⁰
100011010009,9661,000,0001.07×10³⁰¹

效率排序:O(1) > O(log n) > O(n) > O(n log n) > O(n²) > O(2ⁿ)

七、实践建议

  1. 先写对,再优化:先确保程序正确,然后考虑效率

  2. 空间换时间:有时可以用更多内存来加快速度

  3. 选择合适的数据结构:不同数据结构有不同的复杂度特性

  4. 注意最坏情况:算法分析通常考虑最坏情况

小结

  • 时间复杂度关注执行步数随输入规模的增长趋势
  • 空间复杂度关注额外内存使用随输入规模的增长趋势
  • 使用大O表示法,只保留最高次项
  • 通过数循环层数可以快速估算复杂度

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/87637.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/87637.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

上下文工程:从提示词到自动化流程的AI应用新范式

上下文工程&#xff1a;从提示词到自动化流程的 AI 应用新范式 一、背景与概述&#xff1a;从提示词工程到上下文工程的演进 随着大语言模型 (LLM) 技术的飞速发展&#xff0c;AI 应用开发正经历从 “提示词工程”(Prompt Engineering) 到 “上下文工程”(Context Engineerin…

HTML网页应用打包Android App 完整实践指南

技术准备与工具下载 必需工具清单 在开始之前&#xff0c;需要准备以下开发工具&#xff1a; Android Studio官网&#xff1a;https://developer.android.com/studio HBuilderX官网&#xff1a;https://www.dcloud.io/hbuilderx.html 离线SDK下载&#xff1a;https://nati…

简单 Python 爬虫程序设计

爬虫是获取网页数据的常用工具&#xff0c;我们一起来设计一个基于 requests 和 BeautifulSoup 的简单爬虫&#xff0c;它可以获取网页内容并提取文本信息。 所需库安装 首先需要安装两个必要的库&#xff1a; pip install requests beautifulsoup4 完整代码 import reques…

AUTOSAR图解==>AUTOSAR_AP_EXP_ARAComAPI

AUTOSAR ara::com API详解 自适应平台通信API技术详解 目录 1. 概述2. ara::com API架构 2.1 Proxy/Skeleton架构2.2 通信方式2.3 服务连接方式 3. 详细API说明 3.1 Proxy类3.2 Skeleton类3.3 实例标识符3.4 通信组 4. ara::com API状态管理 4.1 服务生命周期4.2 事件与方法状…

Spring Boot + 本地部署大模型实现:优化与性能提升

在将大语言模型集成到 Spring Boot 应用中时&#xff0c;性能优化是一个关键环节。本地部署的大模型虽然提供了强大的功能&#xff0c;但也可能带来一些性能挑战&#xff0c;如响应时间较长、资源占用较高等问题。本文将介绍如何在 Spring Boot 应用中优化本地部署大模型的性能…

QML 鼠标只响应左键处理方法

【1】问题描述 默认情况下qml支持左键&#xff0c;如果需要支持右键&#xff0c;甚至是中键那需要设置 【2】设置方法 MouseArea{ id: mouse anchors.fill: parent property int cx: 0 pr…

北方算网亮相2025全球数字经济大会|共绘数字友好城市建设

7月2日&#xff0c;以“建设数字友好城市”为主题的2025全球数字经济大会隆重开幕&#xff0c;为构建技术与人、城市与生态和谐共进的全球数字经济新生态提供交流合作平台。自7月3日开始&#xff0c;北方算网将在大会集中亮相&#xff0c;先后在多个论坛中发表主题演讲&#xf…

Android PNG/JPG图ARGB_8888/RGB_565‌解码形成Bitmap在物理内存占用大小的简单计算

Android PNG/JPG图ARGB_8888/RGB_565‌解码形成Bitmap在物理内存占用大小的简单计算 Android的Bitmap 是一个用于表示图像数据的核心类&#xff0c;代表一张图片在内存中的存储&#xff0c;Bitmap存储了图像的像素信息数据。 Bitmap把图像理解为像素点组成的二维矩阵&#xff…

力扣网编程55题:跳跃游戏之逆向思维

一. 简介 前面一篇文章使用贪心算法解决 力扣网55题&#xff1a;跳跃游戏&#xff0c;文章如下&#xff1a; 力扣网编程55题&#xff1a;跳跃游戏之贪心算法-CSDN博客 二. 力扣网编程55题&#xff1a;跳跃游戏之逆向思维 给你一个非负整数数组 nums &#xff0c;你最初位于数…

苍穹外卖--day12数据统计-Excel报表

1.工作台1.1实现思路工作台是系统运营的数据看板&#xff0c;并提供快捷操作入口&#xff0c;可以有效提高商家的工作效率。工作台展示的数据&#xff1a;①今日数据②订单管理③菜品总览④套餐总览⑤订单信息名词解释&#xff1a;①营业额&#xff1a;已经完成订单的总金额②有…

鸿蒙应用开发:从网络获取数据

一、网络状态概述上述任一指标的变化均可视为网络状态的改变 二、获取网络信息 创建网络对象 //创建网络对象 //?表示可传可不传 connection.createNetConnection(netSpecifier?:NetSpecifier,timeout?:number):NetConnection;获取默认激活网络及其能力 //获取默认激活网络 …

探索开源虚拟 Excel 函数模块:Python 中的 Excel 功能利器

在数据处理和分析的领域中&#xff0c;Excel 一直是一款备受青睐的工具&#xff0c;它提供了丰富多样的函数&#xff0c;帮助用户高效地完成各种数据操作。而现在&#xff0c;我&#xff08;董翔&#xff09;开发一个基于 Python 的虚拟 Excel 函数模块&#xff0c;它将 Excel …

开源 vGPU 方案 HAMi: corememory 隔离测试

本文主要对开源的 vGPU 方案 HAMi 的 GPU Core&Memory 隔离功能进行测试。 省流&#xff1a; HAMi vGPU 方案提供的 Core&Memory 隔离基本符合预期&#xff1a; Core 隔离&#xff1a;Pod 能使用的算力会围绕设定值波动&#xff0c;但是一段时间内平均下来和申请的 g…

openstack安装并初始化

openstack安装并初始化openStack 概述OpenStack 起源什么是Openstackopenstack优势使用本地仓库离线安装系统基本环境设置为系统设置本地仓库创建openstack-train的仓库更新系统安装部署工具一键安装设置桥接网络通过 Dashboard 体验 OpenStack 功能创建云主机创建网络(1)用adm…

解决 Cannot create Swift scratch context

场景复现 Xcode 控制台输出&#xff1a; Cannot create Swift scratch context (couldnt create a Clang Importer)Analysis 分析 发生了什么&#xff1f; 在调试 Swift 代码或在 LLDB 里执行 po/expr 命令时&#xff0c;LLDB 需要为表达式临时创建一份 “Swift scratch co…

机械时代的计算

1、机械计算起源 最近在想平衡三进制的除法&#xff0c;想看看那么大牛是怎么做的&#xff0c;资料很少&#xff0c;但还是有的&#xff0c;有但是看不懂&#xff0c;也不知靠不靠谱&#xff0c;后面跟着实践了能行&#xff0c;下面就看看Balanced Ternary Arithmetic&#xff…

相机光学(四十八)——渐晕

1.什么是渐晕 渐晕&#xff0c;又称“光衰减”&#xff0c;在光学和摄影中很常见&#xff0c;简单来说就是与中心相比&#xff0c;图像角落变暗。渐晕要么是由光学引起的&#xff0c;要么是在后期处理中故意添加的&#xff0c;目的是将观看者的视线从角落的干扰物吸引到图像的中…

LabVIEW多通道阻抗测试仪

LabVIEW集成 Keysight 数字万用表与 NI 矩阵开关卡&#xff0c;构建多通道阻抗测试系统&#xff0c;实现设备连接电缆的多芯阻抗自动化测试&#xff0c;涵盖数据采集、分析、记录与显示功能&#xff0c;适用于高精度阻抗检测场景&#xff0c;展现LabVIEW在仪器控制与自动化测试…

MySQL的5.0和8.0版本区别

目录 1、MySQL版本-- 》5版本 1.1、InnoDB存储引擎 1.2、存储过程和触发器 1.3、视图 1.4、增强的查询优化器 1.5、增强的索引支持 1.6、外键支持 1.7、分区表和分布式查询 2、MySQL版本-- 》8版本 2.1、性能 2.2、字符编码改变 2.3、持久化保存 2.4、隐藏索引和降…

python实现简单的地图绘制与标记20250705

用python语言绘制显示范围不大于上海地区的地图 您的代码实现了一个 上海武馆地理信息系统&#xff0c;主要功能是通过可视化地图展示上海各区的传统武术馆信息。 通过和deeps对话一晚上实现的&#xff0c;我就是描述修改 高德的api key我搞了一会&#xff0c;平时很少接触密…