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

初学者关于算法复杂度的学习笔记

1.前言

1.1数据结构(Data structure)

数据结构是计算机储存、组织数据的方式,指相互之间存在一种或多种特定关系数据元素的集合

1.2算法(Algorithm)

算法就是定义良好的计算过程,简单来说就是一系列计算步骤,用来将输入的数据转化为输出的结果

2.算法的效率

一个算法的好坏通常用复杂度来衡量(复杂度越小,效率越高),包括时间复杂度空间复杂度

 2.1时间复杂度(衡量一个算法运行的快慢)

由于计算机的配置,编译环境的差异以及运行时间的不可预测性(只能写完代码测试才能知道不好通过理论思想来评估。)我们不直计算时间来衡量计算效率,从而引入时间复杂度。


定义:在计算机科学中,算法的时间复杂度是一个函数式T(N),这个T(N)函数式计算了程序的执⾏次数,那么我们通过程序代码或者理论思想计算出程序的执⾏次数的函数式T(N),假设每句指令执⾏时间基本⼀样(实际中有差别,但是微乎其微),那么执⾏次数和运⾏时间就是等⽐正相关,这样也脱离了具体的编译运⾏环境。

我们计算时间复杂度的目的实际上是比较算法程序的增长量级,所以计算出精确的执行次数意义也不大,也就是说时间复杂度衡量的是随变量N的变化,算法运行时间的变化,而不是聚焦于计算一个具体的值。

所以我们只需要计算程序能代表增⻓量级的⼤概执⾏次数,复杂度的表⽰通常使⽤⼤O的渐进表⽰法

2.2大O的渐进表示法

⼤O符号(Big O notation):是⽤于描述函数渐进⾏为的数学符号
推导大O阶规则:
1.只保留最高阶
2.最高阶存在且不是1,去除常系数
3.只有常数一律用1取代所有加法常数

3.时间复杂度的计算示

3.1示例1

// 计算Func2的时间复杂度?
void Func2(int N)
{int count = 0;for (int k = 0; k < 2 * N ; ++ k)//-------2n{++count;}int M = 10;while (M--)//---------------------------10{++count;}printf("%d\n", count);
}

T(N)=2N+10

O(N)

不是计算语句的执行次数吗,为什么不用算其他的语句如:int count = 0;printf("%d\n", count); 

  • 像这样的语句,其执行时间不随输入规模变化,是 O(1) 的操作。

  • 在大多数情况下,这些操作的时间复杂度可以忽略,因为它们不会影响整体的增长趋势。

 3.2示例2

// 计算Func3的时间复杂度?
void Func3(int N, int M)
{int count = 0;for (int k = 0; k < M; ++ k)//-----------------M{++count;}for (int k = 0; k < N ; ++k)//-----------------N{++count;}printf("%d\n", count);
}

T(N)=M+N

O(M+N)     这里我们不确定M和N大小

这里可以进一步讨论:

  • M>>N     O(M)
  • N>>M     O(N)
  • N==M     O(N)或者O(M)

3.3示例3

// 计算Func4的时间复杂度?
void Func4(int N)
{int count = 0;for (int k = 0; k < 100; ++ k)//------------100{++count;}printf("%d\n", count);
}

O(1)

3.4示例4

// 计算strchr的时间复杂度?
const char * strchr ( const char* str, int character)
{const char* p_begin = s;while (*p_begin != character){if (*p_begin == '\0')return NULL;p_begin++;}return p_begin;
}
有些算法的时间复杂度存在最好、平均和最坏情况。
最坏情况:任意输⼊规模的最⼤运⾏次数(上界)
平均情况:任意输⼊规模的期望运⾏次数
最好情况:任意输⼊规模的最⼩运⾏次数(下界)
⼤O的渐进表⽰法在实际中⼀般情况关注的是算法的上界,也就是最坏运⾏情况

按照最差的情况来看,最多要找N次

O(N)

3.5示例5

// 计算BubbleSort的时间复杂度?
void BubbleSort(int* a, int n)
{assert(a);for (size_t end = n; end > 0; --end){int exchange = 0;for (size_t i = 1; i < end; ++i){if (a[i-1] > a[i]){Swap(&a[i-1], &a[i]);exchange = 1;}if (exchange == 0)break;}
}

最差的情况:数据排列为降序

O(N^2) 

3.6示例6

void func5(int n)
{int cnt = 1;while (cnt < n){cnt *= 2;}
}

 O(logn)

当n接近⽆穷⼤时,底数的⼤⼩对结果影响不⼤。因此,⼀般情况下不管底数是多少都可以省略不
写,即可以表⽰为 logn

3.7示例7

// 计算阶乘递归Fac的时间复杂度?
long long Fac(size_t N)
{if(0 == N)return 1;return Fac(N-1)*N;
}

函数递归,时间复杂度 =递归次数递归次数*单次递归的时间复杂度 

4.空间复杂度

空间复杂度是对⼀个算法在运⾏过程中因为算法的需要额外临时开辟的空间
空间复杂度不是程序占⽤了多少bytes的空间,因为常规情况每个对象⼤⼩差异不会很⼤,所以空间复杂度算的是变量的个数。
注意
函数运⾏时所需要的栈空间(存储参数、局部变量、⼀些寄存器信息等)在编译期间已经确定好
了,因此空间复杂度主要通过函数在运⾏时候显式申请的额外空间来确定。

4.1空间复杂度的计算

4.1.1示例1

// 计算BubbleSort的时间复杂度?
void BubbleSort(int* a, int n)
{assert(a);for (size_t end = n; end > 0; --end){int exchange = 0;for (size_t i = 1; i < end; ++i){if (a[i-1] > a[i]){Swap(&a[i-1], &a[i]);exchange = 1;}}if (exchange == 0)break;}
}
exchange等有限个局部变量,使⽤了常数个额外空间
因此空间复杂度为 O(1)

4.1.2示例2

// 计算阶乘递归Fac的空间复杂度?
long long Fac(size_t N)
{if(N == 0)return 1;return Fac(N-1)*N;
}

递归空间复杂度=递归次数*单次递归复杂度

O(N)

http://www.dtcms.com/a/275770.html

相关文章:

  • goframe框架中获取url内容并转成Base64字符串
  • 【QGC】深入解析 QGC 配置管理
  • AAAI-2025 | 西交模拟人类空间推理策略的具身导航!REGNav:房间专家引导的图像目标导航
  • Linux文件的权限
  • Kotlin基础学习记录
  • 【MediaSoup】MS_DUMP打印转换为PLOGI的形式
  • Python-难点-uinttest
  • 网络资源模板--基于Android Studio 实现的记事本App
  • 通过卫星图像追踪城市扩张
  • Windows npx n8n 方式运行n8n密码忘了重置密码
  • IDEA中一个服务创建多个实例
  • PyQt5布局管理(QBoxLayout(框布局))
  • 企业商业秘密保卫战:经营信息类案件维权全攻略
  • WildCard野卡已跑路(包含gpt plus升级方案)
  • C++结构体嵌套
  • Datawhale AI夏令营 MCP初体验——简历小助手
  • DeepSeek-Qwen蒸馏模型解析
  • 苍穹外卖-day06
  • 自助空间系统迭代历程|自助门店运营系统全新升级
  • AI炼丹日志-30-新发布【1T 万亿】参数量大模型!Kimi‑K2开源大模型解读与实践
  • 电子电气架构 --- ECU存储与计算资源冗余设计规范
  • 实习内容总结
  • 笔记/了解未来:财务建模与预测
  • 系统思考助力转型
  • Git企业级开发(最终篇)
  • 【PTA数据结构 | C语言版】车厢重排
  • JDBC 事务控制详解:保障数据安全的完整指南
  • ​Windows API 介绍及核心函数分类表
  • 使用langgraph 构建RAG 智能问答代理
  • Kotlin文件