【马里奥数据结构吃“金币”】时间复杂度和空间复杂度
作者:一个喜欢猫咪的的程序员
专栏:《数据结构》
喜欢的话:世间因为少年的挺身而出,而更加瑰丽。 ——《人民日报》
目录
时间复杂度:
大O渐进表示法:
空间复杂度:
常见复杂度对比:
我们学数据结构之前我们已经写过了不少代码,我们在写代码的过程中,我们往往追求的是效率,那我们怎么来衡量一个代码的效率呢?
这就涉及到了本章的知识点:时间复杂度和空间复杂度!
因此衡量一个算法的好坏,一般是从时间和空间两个维度来衡量的,即时间复杂度和空间复杂度。
- 时间复杂度主要衡量一个算法的运行快慢,
- 空间复杂度主要衡量一个算法运行所需要的额外空间。
但我们一般比较在乎时间复杂度。
时间复杂度:
时间复杂度的定义:在计算机科学中,算法的时间复杂度是一个函数,它定量描述了该算法的运行时间。一个算法执行所耗费的时间,从理论上说,是不能算出来的,只有你把你的程序放在机器上跑起来,才能知道。但是我们需要每个算法都上机测试吗?是可以都上机测试,但是这很麻烦,所以才有了时间复杂度这个分析方式。一个算法所花费的时间与其中语句的执行次数成正比例,算法中的基本操作的执行次数,为算法的时间复杂度。
这里的函数指的是数学函数,而不是编程语言的函数。
执行的次数指的是循环的次数,以及递归时候函数调用的次数。
我们先来看一个问题:下面这个代码执行了几次?
// 请计算一下Func1中++count语句总共执行了多少次?
void Func1(int N)
{
int count = 0;
for (int i = 0; i < N ; ++ i)
{
for (int j = 0; j < N ; ++ j)
{
++count;
}
}
for (int k = 0; k < 2 * N ; ++ k)
{
++count;
}
int M = 10;
while (M--)
{
++count;
}
printf("%d\n", count);
}
我们结合下图来理解一下:圆圈一和圆圈二都循环了N次,而圆圈3 循环了2N次,圆圈4循环了M次。一和二是嵌套关系,圆圈一每循环一次圆圈二循环N次,所以N次圆圈一应该是执行了N^2。圆圈3和4都是普通的循环,所以三个加起来为:N^2+2N+M,这是一个具体的时间复杂度。
而我们平常算的时间复杂度是一个大概值,我们运用了一种计算方法:大O渐进表示法!!!
大O渐进表示法:
大O符号(Big O notation):是用于描述函数渐进行为的数学符号。
推导大O阶方法:
1、用常数1取代运行时间中的所有加法常数。
2、在修改后的运行次数函数中,只保留最高阶项。
3、如果最高阶项存在且不是1,则去除与这个项目相乘的常数。得到的结果就是大O阶。
我们观看这三个规则很抽象,我们下面通过一些例子来理解一下:
// 计算Func2的时间复杂度?
void Func2(int N)
{
int count = 0;
for (int k = 0; k < 2 * N; ++k)
{
++count;
}
int M = 10;
while (M--)
{
++count;
}
printf("%d\n", count);
}//O(2N+10)=O(N)
此代码我们容易算出它的具体的时间复杂度为2N+10。
我们这边利用了规则2和3,2N+10中2N为最高项,所以时间复杂度为2N,然后最高项2N存在,2这个常数去掉,所以最后是时间复杂度为O(N)。
// 计算Func4的时间复杂度?
void Func4(int N)
{
int count = 0;
for (int k = 0; k < 100; ++ k)
{
++count;
}
printf("%d\n", count);
}//O(100)=O(1)
本题跟前几题不太一样,因为本题的时间复杂度的具体值是一个参数(100)。
我们利用规则1,O(100)就变为了O(1)。
当我们以后面试或者考研面试的时候,我们经常是不看代码,以思想来算他的时间复杂度,我们来试一下不看代码算出冒泡排序(N个数)的时间复杂度:
void BubbleSort(int* a, int N)
我们假设它N个数进行冒泡排序,第一个数执行了N次,第二数N-1个数,第三个数N-2个数.......以此类推。第N个数就执行一次。那时间复杂度O(N+N-1+N-2+.....+1)。
这里就涉及到了等差数列,等差数列求和如下:
Sn=[n*(a1+an)]/2
那这里我们时间复杂度就变为O(0.5N^2+0.5N)=O(N^2)
// 计算BinarySearch的时间复杂度?
int BinarySearch(int* a, int n, int x)
{
assert(a);
int begin = 0;
int end = n - 1;
// [begin, end]:begin和end是左闭右闭区间,因此有=号
while (begin <= end)
{
int mid = begin + ((end - begin) >> 1);
if (a[mid] < x)
begin = mid + 1;
else if (a[mid] > x)
end = mid - 1;
else
return mid;
}
return -1;
}//O(logN)
我们利用下图理解一下:
我们在算数据结构的时间复杂度的时候。当遇到对数时,因为我们用键盘输入不了底数,所以我们经常把底数2省略,只写logN。但我们只省略2为底数的时候,当3(或者其他常数)为底数的时候,不省略。
// 计算阶乘递归Fac的时间复杂度?
long long Fac(size_t N)
{
if (1== N)
return 1;
return Fac(N - 1) * N;
}//O(N)
当我们在算递归的时候,时间复杂度的具体值我们可以理解为:一次递归算一次,这里一共N次所以一共N次。
我们将这个题目改一下再来算一下:
// 计算阶乘递归Fac的时间复杂度?
long long Fac(size_t N)
{
if (1== N)
return 1;
for (int i = 0; i < N; i++)
{
;
}
return Fac(N - 1) * N;
}//O(N^2)
这里我们要算一下它具体的时间复杂度:
当为N时,循环N次;当为N-1时,循环N-1次;.......;当为1时,执行1次;
累加后为:N+N-1+N-2+....+1+N(递归的次数)=0.5N^2+1.5N;
我们理解了这些例子再发过来理解一下规则:
大O符号(Big O notation):是用于描述函数渐进行为的数学符号。
推导大O阶方法:
1、用常数1取代运行时间中的所有加法常数。
2、在修改后的运行次数函数中,只保留最高阶项。
3、如果最高阶项存在且不是1,则去除与这个项目相乘的常数。得到的结果就是大O阶。
空间复杂度:
空间复杂度也是一个数学表达式,是对一个算法在运行过程中临时占用存储空间大小的量度 。空间复杂度不是程序占用了多少bytes的空间,因为这个也没太大意义,所以空间复杂度算的是变量的个数。空间复杂度计算规则基本跟时间复杂度类似,也使用大O渐进表示法。
注意:函数运行时所需要的栈空间(存储参数、局部变量、一些寄存器信息等)在编译期间已经确定好了,因此空间复杂度主要通过函数在运行时候显式申请的额外空间来确定。
这里指的是是在函数内部临时开辟的空间的个数。
重复定义的话也算一个。
递归一次也算一个。
我们通过以下例子来看一下:(不再讲解已将答案写在每个代码最后)
// 计算Func4的空间复杂度?
void Func4(int N)
{
int count = 0;
for (int k = 0; k < 100; ++k)
{
++count;
}
printf("%d\n", count);
}//O(1)
// 计算Fibonacci的空间复杂度?
// 返回斐波那契数列的前n项
long long* Fibonacci(size_t n)
{
if (n == 0)
return NULL;
long long* fibArray = (long long*)malloc((n + 1) * sizeof(long long));
fibArray[0] = 0;
fibArray[1] = 1;
for (int i = 2; i <= n; ++i)
{
fibArray[i] = fibArray[i - 1] + fibArray[i - 2];
}
return fibArray;
}//O(N)
// 计算阶乘递归Fac的空间复杂度?
long long Fac(size_t N)
{
if (N == 0)
return 1;
return Fac(N - 1) * N;
}//O(N)
常见复杂度对比:
【马里奥数据结构吃“金币”】时间复杂度和空间复杂度相关推荐
- 史上最强数据结构----算法的时间复杂度和空间复杂度
第二章 算法的时间复杂度和空间复杂度 1.算法效率 2 时间复杂度 2.1 时间复杂度的概念 2.2 大O的渐进表示法 2.3 时间复杂度的计算举例 2.3.1 实例1 2.3.2 实例2 2.3.3 ...
- 数据结构:递归算法时间复杂度与空间复杂度计算方法
Ⅰ.递归算法求时间复杂度步骤 1.步骤 ①先将这个递归算法分成两类,一类是满足递归条件时,一类为递归停止条件时 ②然后分别算出这两类的执行次数.注意!如果在满足递归条件这一类中,计算执行次数的时候,发 ...
- 数据结构 算法的时间复杂度与空间复杂度的计算(带有例题讲解)
时间复杂度 对于算法时间复杂度的分析需要牢记一句话:将算法中基本操作的执行次数作为算法时间复杂度的度量.时间复杂度并不是执行完一段程序的总时间,而是其中基本操作的总次数. 在考试的算法题目中你总能找到 ...
- 数据结构(02)— 时间复杂度与空间复杂度转换
1. 时间复杂度转化为空间复杂度 常用的降低时间复杂度的方法有递归.二分法.排序算法.动态规划等,降低空间复杂度的核心思路就是,能用低复杂度的数据结构能解决问题,就千万不要用高复杂度的数据结构. ...
- Python数据结构与算法笔记(一):时间复杂度与空间复杂度
学习内容来自清华计算机博士带你学习Python算法+数据结构.目前内容截止到树结构,后续的高级算法以后会补上. 算法概念简述 数据结构:数据存储 时间复杂度 每个电脑配置不一样.同一个程序执行的时间不 ...
- 浅淡数据结构时间复杂度和空间复杂度
文章目录 前言 1.时间复杂度和空间复杂度的相关介绍 1.为什么要引入时间复杂度和空间复杂度的概念 2.什么是时间复杂度和空间复杂度 2.具体示例分析 1.大O法只保留高阶项 2.一般情况关注的是算法 ...
- 【数据结构入门】算法的时间复杂度和空间复杂度详解
文章目录 (1)算法效率 (2)时间复杂度的计算 1)什么是时间复杂度 2)大O渐进表示法(估算) 3)时间复杂度计算实例 4)总结 5)一些思考 (3)空间复杂度的计算 (4)常见复杂度对比 本篇前 ...
- 【数据结构】— 「时间复杂度」与「空间复杂度」
꧁ 各位大佬们好!很荣幸能够得到您的访问,让我们一起在编程道路上任重道远!꧂ ☙ 博客专栏:[数据结构初阶]❧ ⛅ 本篇内容简介:数据结构初阶中的时间复杂度与空间复杂度的详解! ⭐ 了解作者:励 ...
- Java数据结构(1.1):数据结构入门+线性表、算法时间复杂度与空间复杂度、线性表、顺序表、单双链表实现、Java线性表、栈、队列、Java栈与队列。
数据结构与算法入门 问题1:为什么要学习数据结构 如果说学习语文的最终目的是写小说的话,那么能不能在识字.组词.造句后就直接写小说了,肯定是不行的, 中间还有一个必经的阶段:就是写作 ...
最新文章
- java解数独_java解数独
- paper 68 :MATLAB中取整函数(fix, floor, ceil, round)的使用
- PHP IPC函数介绍---共享内存
- PAT (Basic Level) Practice (中文)1008 数组元素循环右移问题 (20 分)
- Xcode的SVN提示The request timed out.的解决方案
- 用javascript实现一个stack overflow的例子
- 机器人点焊枪接线_用于焊接机器人焊枪工具点及工件坐标系标定装置及方法与流程...
- oracle的awr日志,oracle 导出awr信息
- 几万年前,有一只猴子大闹地府后删库跑路...
- 根据前序、中序构建二叉树
- 语音识别模块 LD3320
- 【软件测试】软件测试学习笔记(三)
- ubuntu下安装anjuta
- 台计算机结构看内存条位置,内存条正反怎么看
- 隐藏身份证中间几位工具类
- android imgView.setImageBitmap(bitmap) 空白图片
- 红利逐渐消失殆尽的互联网下半场,前路何方?
- 多租户Lesson 09. Miscellaneous
- 华为智慧屏看鸿蒙,AI加持的另类彩电之华为智慧屏带你体验鸿蒙
- ZIP文件的读取和写入