开鲁网站seo,网络直播网站开发,做网站横幅用什么软件好,易安卓开发app稳定吗文章主题#xff1a;复杂度详解#x1f331;所属专栏#xff1a;深入理解数据结构#x1f4d8;作者简介#xff1a;更新有关深入理解数据结构知识的博主一枚#xff0c;记录分享自己对数据结构的深入解读。#x1f604;个人主页#xff1a;[₽]的个人主页#x1f525;… 文章主题复杂度详解所属专栏深入理解数据结构作者简介更新有关深入理解数据结构知识的博主一枚记录分享自己对数据结构的深入解读。个人主页[₽]的个人主页 复杂度详解 前言算法效率如何分析一个算法的好坏算法的复杂度复杂度在校招中的考察 时间复杂度时间复杂度的概念大O的渐进表示法常见时间复杂度计算举例 空间复杂度常见复杂度对比结语 前言
复杂度是计算机领域表示所需资源达到某个大小量级的量度源自计算复杂性理论1 主要分为时间复杂度与空间复杂度等通常复杂度会被用来综合分析一个算法的好坏以下是我对复杂度的详细解释。 算法效率
如何分析一个算法的好坏
如何衡量一个算法的好坏呢比如对于以下斐波那契数列
long long Fib(int N)
{if(N 3)return 1;return Fib(N-1) Fib(N-2);
}斐波那契数列的递归实现方式非常简洁但简洁一定好吗那该如何衡量其好与坏呢
算法的复杂度
算法在编写成可执行程序后运行时需要耗费时间资源和空间(内存)资源等 。因此衡量一个算法的好坏一般是从时间和空间两个维度来衡量的即时间复杂度和空间复杂度。 时间复杂度主要衡量一个算法的运行快慢而空间复杂度主要衡量一个算法运行所需要的额外空间。在计算机发展的早期计算机的存储容量很小。所以对空间复杂度很是在乎。但是经过计算机行业的迅速发展计算机的存储容量已经达到了很高的程度。所以我们如今已经不需要再特别关注一个算法的空间复杂度。
复杂度在校招中的考察 时间复杂度
时间复杂度的概念
时间复杂度的定义在计算机科学中算法的时间复杂度是一个函数它定量描述了该算法的运行时间。一个算法执行所耗费的时间从理论上说是不能算出来的只有你把你的程序放在机器上跑起来才能知道。但是我们需要每个算法都上机测试吗是可以都上机测试但是这很麻烦所以才有了时间复杂度这个分析方式。一个算法所花费的时间与其中语句的执行次数成正比虽然每个语句的执行时间不同相同语句每次的执行时间也不同但是每次的差距不会很大语句的执行次数的多少能够大体地反映出一个程序所需要耗费的时间量级该算法所需的时间在多大的一个时间量级中一个时间量级能够反映算法运行的一个大概大小的时间区间算法中的基本操作的执行次数为算法的时间复杂度。 即找到一个算法中基本语句出现次数与问题规模N之间的数学表达式就是算出了该算法的时间复杂度。
// 请计算一下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);
}Func1执行的基本操作次数 F ( N ) N 2 2 ∗ N 10 F(N) N^2 2*N 10 F(N)N22∗N10
N 10 F(N) 130N 100 F(N) 10210N 1000 F(N) 1002010 实际中我们计算时间复杂度时我们其实并不一定要计算精确的执行次数而只需要大概执行次数那么这里我们使用大O的渐进表示法。
大O的渐进表示法
大O符号Big O notation是用于描述函数渐进行为的数学符号。 推导大O阶方法 1、用常数1取代运行时间中的所有加法常数。 2、在修改后的运行次数函数中只保留最高阶项比一定狭隘地指谁的次方项最高因为完全有可能项不是单纯的次方项的初等函数不能化简的表达形式最高阶项可直接简单地理解成是画函数图象时谁在正半轴上图象大部分时候比另一函数大谁就是复杂度大O的表示法当中的“最高次项”这里的最高次项是一种更加广义的、自由的、开阔的、凭一点感觉的、稍稍没有那么自由的表示方法这里的命名方法是根据初等函数的种类以及幂函数的次方项的多少来命名的这几种情况出现频率最高当然如果对数的底数不同以及真数的表达式不同也能够用来命名但一般这种情况出现的频率少就不做讨论了阶的分类根据表达式的初等函数的类型不同以及各初等函数的数据不同是可以分成很多种情况的一般复杂度的化简规则是都可以又能力将表达式化成一个单一的初等函数的形式的一般复杂度化简后表达式都会变成单一的一项不同项同阶的会被合并初等函数中的某一类型的两项各数据完全相同才叫同阶不同阶就按上述的简单万能判别方法谁在上多一些对整个表达式的结果影响大一些就会去选择两项或多项中的在输入规模的范围即各函数的定义域中居于上部最多分布的那一项去表达不同的输入规模的范围比较相同的几个不同阶的函数也可能会得到不同结果的最高阶项函数乘积形式时就会是两个初等函数相乘约不掉。 3、如果最高阶项存在且不是1则去除与这个项目相乘的常数。得到的结果就是大O阶。 使用大O的渐进表示法以后Func1的时间复杂度为 O ( N 2 ) O(N^2) O(N2)
N 10 F(N) 100N 100 F(N) 10000N 1000 F(N) 1000000 通过上面我们会发现大O的渐进表示法去掉了那些对结果影响不大的项简洁明了地表示出了执行次数。
4、另外有些算法的时间复杂度存在最好、平均和最坏情况 最坏情况任意输入规模的最大运行次数(上界) 平均情况任意输入规模的期望运行次数 最好情况任意输入规模的最小运行次数(下界) 例如在一个长度为N数组中搜索一个数据x 最好情况1次找到 最坏情况N次找到 平均情况N/2次找到 在实际中一般情况关注的是算法的最坏运行情况大O渐进表示法是为确保其准确性表达方式是考虑最坏情况的严谨表示法所以数组中搜索数据时间复杂度为O(N)
常见时间复杂度计算举例
实例1
// 计算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);
}实例2
// 计算Func3的时间复杂度
void Func3(int N, int M)
{int count 0;for (int k 0; k M; k){count;}for (int k 0; k N ; k){count;}printf(%d\n, count);
}实例3
// 计算Func4的时间复杂度
void Func4(int N)
{int count 0;for (int k 0; k 100; k){count;}printf(%d\n, count);
}实例4
// 计算strchr的时间复杂度
const char * strchr ( const char * str, int character );实例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;}
}实例6
// 计算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 mid1;else if (a[mid] x)end mid-1;elsereturn mid;}return -1;
}实例7
// 计算阶乘递归Fac的时间复杂度
long long Fac(size_t N)
{if(0 N)return 1;return Fac(N-1)*N;
}实例8
// 计算斐波那契递归Fib的时间复杂度
long long Fib(size_t N)
{if(N 3)return 1;return Fib(N-1) Fib(N-2);
}实例答案及分析
实例1基本操作执行了2N10次通过推导大O阶方法知道时间复杂度为 O(N)实例2基本操作执行了MN次有两个未知数M和N时间复杂度为 O(NM)实例3基本操作执行了10次通过推导大O阶方法时间复杂度为 O(1)实例4基本操作执行最好1次最坏N次时间复杂度一般看最坏时间复杂度为O(N)实例5基本操作执行最好N次最坏执行了(N*(N1)/2次通过推导大O阶方法时间复杂度一般看最坏时间复杂度为 O(N2)实例6基本操作执行最好1次最坏O(logN)次时间复杂度为 O(logN) pslogN在算法分析中表示是底数任意的N的对数有些地方会写成lgN数学中的lgN单纯只指底数为2的N的对数但是在时间复杂度中其代表底数任意的N的对数的logN的缩写形式的缩写本质是因为计算机中不好写出底数且时间复杂度本就是估算的形式所以就可以直接将任意底数的只有一个任意输入规模的输入规模表达式的对数形式全都缩写成logF(N)的形式方便表达的同时也符合了大O的渐进表达法表达时间复杂度的去掉影响不大的项简洁明了地表示出执行次数估算的特点。实例7通过计算分析发现基本操作递归了N次时间复杂度为O(N)。实例8通过计算分析发现基本操作递归了2N次时间复杂度为O(2N)。 空间复杂度
空间复杂度也是一个数学表达式是对一个算法在运行过程中临时占用存储空间大小的量度 。 空间复杂度不是程序占用了多少bytes的空间因为这个也没太大意义所以空间复杂度算的是变量的个数。空间复杂度计算规则基本跟时间复杂度类似一般也直接使用大O的渐进表示法。 注意函数运行时所需要的栈空间(存储参数、局部变量、一些寄存器信息等)在编译期间已经确定好了因此空间复杂度主要通过函数在运行时候显式申请的额外空间来确定即空间复杂度会忽略已经在编译时就确定好的函数参数运行时申请的实参空间一些早就会确定好的函数运行所必要的局部变量以及一些函数运行时所必不可少的也是在编译时就确定好的寄存器的大小而只考虑那些不是在编译时就确定好的必要的内存大小而是运行时才考虑的主要存在与函数体当中的只参与函数运行原理的那些额外创造的空间可将其简单地理解为就是函数运行时才会创造的函数体当中的那些局部变量。当然一般我们是直接根据算法的思想来确定所开创空间的大小的而算法思想本质上就是分析的函数运行时的状态就和只分析函数运行时的函数体中所创造的局部变量的个数的效果本质上是如出一辙的不管时间还是空间复杂度只要单纯地根据算法的思想去简单地分析结果就一定会吻合运行时所消耗的时间与开创的额外空间因为是运行时才开创的有些甚至情况不同时都不会开创所以将运行时创建的空间叫作额外空间结果就一定不会出错。 实例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;}
}实例2
// 计算Fibonacci的空间复杂度
// 返回斐波那契数列的前n项
long long* Fibonacci(size_t n)
{if(n0)return NULL;long long * fibArray (long long *)malloc((n1) * 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;
}实例3
// 计算阶乘递归Fac的空间复杂度
long long Fac(size_t N)
{if(N 0)return 1;return Fac(N-1)*N;
}实例答案及分析
实例1使用了常数个额外空间所以空间复杂度为 O(1)实例2动态开辟了N个空间空间复杂度为 O(N)实例3递归调用了N次开辟了N个栈帧每个栈帧使用了常数个空间。空间复杂度为O(N) 常见复杂度对比
一般算法常见的复杂度如下
真实表达式大O的渐进表示法阶 5201314 5201314 5201314 O ( 1 ) O(1) O(1)常数阶 3 n 4 3n4 3n4 O ( n ) O(n) O(n)线性阶 3 n 4 n 5 3^n 4n 5 3n4n5 O ( n 2 ) O(n^2) O(n2)平方阶 3 l o g 2 n 4 3log_2n 4 3log2n4 O ( l o g n ) O(logn) O(logn)对数阶 2 n 3 n l o g 2 n 14 2n 3nlog_2n 14 2n3nlog2n14 O ( n l o g n ) O(nlogn) O(nlogn)nlogn阶 n 3 2 n 2 4 n 6 n^3 2n^2 4n 6 n32n24n6 O ( n 3 ) O(n^3) O(n3)立方阶 2 n 2^n 2n O ( 2 n ) O(2^n) O(2n)指数阶 结语
以上就是博主对复杂度的详解希望对你的数据结构的学习有所帮助看都看到这了点个小小的赞或者关注一下吧当然三连也可以~你的支持就是博主更新最大的动力让我们一起成长共同进步 计算复杂性理论Computational complexity theory是理论计算机科学和数学的一个分支它致力于将可计算问题根据它们本身的复杂性分类以及将这些类别联系起来。一个可计算问题被认为是一个原则上可以用计算机解决的问题亦即这个问题可以用一系列机械的数学步骤解决例如算法。 ↩︎