文章目录
时间复杂度
概念
首先我们看一下百度百科给出的理解:
百度百科解释:
在计算机科学中,时间复杂性,又称时间复杂度,算法的时间复杂度是一个函数,它定性描述该算法的运行时间。这是一个代表算法输入值的字符串的长度的函数。时间复杂度常用大O符号表述,不包括这个函数的低阶项和首项系数。使用这种方式时,时间复杂度可被称为是渐近的,亦即考察输入值大小趋近无穷时的情况。
下面给出自己的理解
- 首先,
时间复杂度
是顾名思义就能知道是表示一个算法的运行时间,但是一定要记住这里的表示并不是指的精确表示而是估算。 - 其次需要知道的是我们
时间复杂度
用T(n)=O(f(n));其中f(n)就是程序执行所需要的时间函数;下面会具体解释。既然是函数就有高阶项、首项系数和常数的概念,其次时间复杂度可被称为是渐近的,亦即考察输入值大小趋近无穷时的情况 这句话的意思就是时间复杂度表示的是一个算法输入值趋近无穷时的情况,当函数表达式中未知数趋于无穷大的时候,我的理解其中低阶项、常数的影响就会显得很小,因此时间复杂度就不会包括高阶项、常数;其中渐进的概念我的理解就是耗费时间跟算法输入值成正比,值越大耗费时间越长
算法约定:- 1.去掉运行时间中的所有加法常数。
- 2.只保留最高阶项。
- 3.如果最高阶项存在且不是1,去掉与这个最高阶相乘的常数得到时间复杂度
在了解概念之后下面给出示例,明白如何去计算时间复杂度,概念不清楚的也可以先看实例后回头再看看这些概念也就明白了
示例
示例一、小明有一支10cm的铅笔,每3天就会写完1cm,请问小明写完这支铅笔共需要多少天
答案:是10*3=30天;
如果这支铅笔有n厘米,那么就会需要n*3天
所以时间复杂度函数f(n) = 3n;
所以这次的时间复杂度就表示为T(n) = O(3n);
除去系数后:T(n) = O(n)
示例二、小明有一支铅笔,每3天就会写完钢笔,请问小明写完这支钢笔共需要多少天
答案:是3;
这里并没有描述铅笔的长度,所以不用关系铅笔的长度,不管多长也是3天写完,所以时间复杂度函数f(n) = 3;所以这次的时间复杂度就表示为T(n) = O(3);
除去系数后:T(n) = O(1)
示例三、小明有一支16cm的铅笔,每3天就会写完铅笔剩余长度一半,请问小明写到这支钢笔只剩1cm共需要多少天
答案:第一次写完8cm剩下8cm;第二次写完4cm剩下4cm;第三次写完2cm剩下2cm;第四次写完1cm剩下1cm;所以需要4*3=12天;
这个问题翻译一下,就是数字16不断地除以2,除几次以后的结果等于1?这里要涉及到数学当中的对数,以2位底,16的对数,可以简写为3log16。
如果这支铅笔有n厘米,那么就会需要3log n;所以时间复杂度函数f(n) =3log n
除去系数后:T(n) =O( log n);
示例四、小明有一支10cm的铅笔,写完铅笔的第一厘米需要1天,写完铅笔的第二厘米需要2天,写完铅笔的第三厘米需要3天,一次类推,每多写完一厘米,就会多花费1天时间,请问小明写完这支铅笔共需要多少天
答案:1+2+3+4+5+6+7+8+9+10=55天。
如果这支铅笔有n厘米,那么就会需要1+2+3+……+n = 0.5n^2 + 0.5n 天,所以时间复杂度函数f(n) =0.5n^2 + 0.5n
除去系数后:T(n) =O(n^2);
总结
- 在程序代码中没步代码执行所耗费的时间我们假设为time是固定一个值,那么总耗费时间就是总执行步骤*time;所以时间复杂度个人理解也可以认为算法程序代码的执行步骤总数,因为耗费时间也是跟执行步骤成正比的,因为其中个别不因为输入值而影响的步骤也就是复杂度为O(1),在估算的时候我们可以不计算在内,只计算因为输入值而影响的步骤;除了上面的示例其实还有很多复杂度O(nlogn), O(n^3), O(m*n),O(2^n),O(n!)……
- 上面四种时间复杂度执行比对
大O标记法 | 计算10个元素 | 计算100个元素 | 计算1000个元素 |
---|---|---|---|
O(1) | 1 | 1 | 1 |
O(log N) | 3 | 6 | 9 |
O(log N) | 10 | 100 | 1000 |
O(N^2) | 100 | 10000 | 1000000 |
- 上面四种时间复杂度执行长度比较,自行思考原因
O(1)< O(logn)< O(n)< O(n^2)
冒泡排序时间复杂度解析
首先我们看一下冒泡排序的代码:
/**
*冒泡排序
*@param arry 需要排序的int数组
*@return 排序后的数组
*/
public static int[] bubbleSort(int[] arry) {
for (int i = 0; i < arry.length; i++) {
for (int j = i + 1; j < arry.length; j++) {
if (arry[j] < arry[i]) {
int tmp = arry[j];
arry[j] = arry[i];
arry[i] = tmp;
}
}
}
return arry;
}
由代码可以看出,第一个for循环的时间复杂度函数为f(n) = n;第二个for循环,①最优情况为第二个for循环内部的if内一直走不到,就是该序列就是升序排列好的,所以第二个for循环的时间复杂度函数为f(n) = 1;②最差情况为第二个for循环内部的if内每次都能走到,就是该序列就是降序排列;所以第二个for循环的时间复杂度函数为f(n) = n-1;所以第二个for循环的平均复杂度为(1+(n-1))/2=n/2;
综上所述冒泡排序的时间复杂度为:
- 最佳情况:T(n)=O(n*1)=O(n)
- 最差情况:T(n)=O(n*(n-1)=O(n^2)
- 平均情况:T(n)=O(n*n/2))=O(n^2)
最后说明下冒泡排序的时间复杂度是相对比较容易计算的,更复杂的可能就得需要点数学功底及算法逻辑;自行掌握,谢谢!
空间复杂度
概念
与时间复杂度一样首先我们看一下百度百科给出的解释
百度百科解释:
空间复杂度(Space Complexity)是对一个算法在运行过程中临时占用存储空间大小的量度,记做S(n)=O(f(n))。比如直接插入排序的时间复杂度是O(n^2),空间复杂度是O(1) 。而一般的递归算法就要有O(n)的空间复杂度了,因为每次递归都要存储返回信息。一个算法的优劣主要从算法的执行时间和所需要占用的存储空间两个方面衡量。
- 由上面及对时间复杂度的理解可以知道:空间复杂度是估算一个算法运行所需要的存储空间,这里的存储空间通常是指内存空间。包括存储算法本身所占用的存储空间,算法的输入输出数据所占用的存储空间和算法在运行过程中临时占用的存储空间这三个方面(百度百科给出的定义)
- 存储量包括:
- 1.程序本身所占空间。
- 2.输入数据所占空间。
- 3.辅助变量所占空间。
输入数据所占空间只取决于问题本身,和算法无关,则只需分析除输入和程序之外得辅助变量所占额外空间。空间复杂度是对一个算法在运行过程中临时占用得存储空间大小的量度,一般也作为问题规模n得函数,以数量级形式给出,记作: S(n) = O(g(n))
同样下面以示例说话(计算冒泡排序的空间复杂度)
同样首先我们看一下冒泡排序的代码:
/**
*冒泡排序
*@param arry 需要排序的int数组
*@return 排序后的数组
*/
public static int[] bubbleSort(int[] arry) {
for (int i = 0; i < arry.length; i++) {
for (int j = i + 1; j < arry.length; j++) {
if (arry[j] < arry[i]) {
int tmp = arry[j];
arry[j] = arry[i];
arry[i] = tmp;
}
}
}
return arry;
}
由上面代码可以看出辅助变量为tmp,最优情况下该序列就是升序排列好的,及时间if条件走不到,所以最优情况下空间复杂度函数g(n) = 0;最差的空间复杂度就是开始元素逆序排序,每次都要借用一次内存,按照实际的循环次数n-1,;但是临时变量tmp只需要一个,临时变量所占空间不随处理数据n的大小改变而改变,所以空间复杂度为O(1)
这种计算方式主要也是看排序过程是使用到的临时变量是否与排序n有关系
最后就是时间复杂度与空间复杂度的关系,其实一句话大家都知道的“以空间换时间”;总之空间复杂度与时间复杂度都是一个估算的过程,大家记住常用的排序算法的复杂度就好了