时间复杂度及其计算

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了时间复杂度及其计算相关的知识,希望对你有一定的参考价值。

参考技术A

算法是指解题方案的准确而完整的描述,是一系列解决问题的清晰指令,算法代表着 用系统的方法描述解决问题的策略机制 。对于同一个问题的解决,可能会存在着不同的算法,为了衡量一个算法的优劣,提出了<u>空间复杂度与时间复杂度</u>这两个概念。

一个算法是由 控制结构(顺序、分支和循环3种) 原操作(指固有数据类型的操作) 构成的,则算法时间取决于<u>两者的综合效果</u>。为了便于比较同一个问题的不同算法,通常的做法是:
<p>从算法中选取一种对于所研究的问题(或算法类型)来说是基本操作的原操作,以该基本操作的重复执行的次数作为算法的时间量度。</p>

参考文章: 算法的时间复杂度和空间复杂度-总结
时间复杂度,又称时间频度,即 一个算法执行所耗费的时间

<u>一个算法花费的时间与算法中语句的执行次数成正比例,哪个算法中语句执行次数多,它花费时间就多。</u>一个算法中的语句执行次数称为语句频度或时间频度。记为T(n)

n称为 问题的规模 ,当n不断变化时,时间频度T(n)也会不断变化。一般情况下,算法中基本操作重复执行的次数是问题规模n的某个函数,用T(n)表示,<i> 若有某个辅助函数f(n),使得当n趋近于无穷大时,*T(n)/f(n)的极限值为不等于零的常数,则称f(n)是T(n)的同数量级函数。记作T(n)=O(f(n)),称O(f(n)) 为算法的渐进时间复杂度,简称时间复杂度。简单来说,就是T(n)在n趋于正无穷时最大也就跟f(n)差不多大。</i>

算法中语句执行次数为一个常数,则时间复杂度为O(1)。常见的时间复杂度有:<p><b>常数阶O(1),对数阶O(log2n),线性阶O(n), 线性对数阶O(n log2n),平方阶O(n2),立方阶O(n3),...。</b></p>
<i><b>Log</b><u>2</u><b>8</b>:2为底N的对数,即2的几次方等于8,值为3</i>


常见的算法时间复杂度由小到大依次为:Ο(1)<Ο(log2n)<Ο(n)<Ο(n log2n)<Ο(n2)<Ο(n3)<…<Ο(2n)<Ο(n!)
即:常数阶 < 对数阶 < 线性阶 < 线性对数阶 < 平方阶 < 立方阶 < … < 指数阶 < 阶乘

如:

第一个for循环的时间复杂度为Ο(n),第二个for循环的时间复杂度为Ο(n2),则整个算法的时间复杂度为Ο(n1+n2+n3)=Ο(n3)。

Ο(1)表示基本语句的执行次数是一个常数,一般来说,只要算法中不存在循环语句,其时间复杂度就是Ο(1)。其中Ο(log2n)、Ο(n)、 Ο(nlog2n)、Ο(n2)和Ο(n3)称为多项式时间,而Ο(2n)和Ο(n!)称为指数时间。计算机科学家普遍认为前者(即多项式时间复杂度的算法)是有效算法。

<i>指数函数:y=ax,对数函数:y=logax,幂函数:y=xa
x为变量,a为常量</i>

二分查找算法的递归循环实现及其缺陷

关于二分查找法

      在学习算法的过程中,我们除了要了解某个算法的基本原理、实现方式,更重要的一个环节是分析算法的复杂度。在时间复杂度和空间复杂度之间,我们又会更注重时间复杂度,往往用牺牲空间换时间的方法提高时间效率。

时间复杂度按优劣排差不多集中在:

O(1), O(log n), O(n), O(n log n), O(n2), O(nk), O(2n)

二分查找法主要是解决在“一堆数中找出指定的数”这类问题,而想要应用二分查找法,这“一堆数”必须有一下特征:

  • 存储在数组中

  • 有序排列

所以如果是用链表存储的,就无法在其上应用二分查找法了。

至于是顺序递增排列还是递减排列,数组中是否存在相同的元素都不要紧。不过一般情况,我们还是希望并假设数组是递增排列,数组中的元素互不相同

二分查找程序实现:

#include<iostream>

using namespace std;


//while循环实现

int Binary_Search1(int array[], int n, int value)

int left = 0;

int right = n-1;

while (left <= right)//注意这里是"<="还是"=",若为"=",则循环里改为right = middle 

int middle = left + ((right - left) >> 2);//直接平均可能會溢位,所以用此算法

if (array[middle] > value)

right = middle - 1;

else if(array[middle] < value)

left = middle + 1;

else

return middle;

return -1;



//递归实现

int Binary_Search2(int array[], int left,int right, int value)

if (left > right)//二分查找要有序

return -1;

int middle = left + ((right - left) >> 2);//直接平均可能會溢位,所以用此算法

if (array[middle] > value)

return Binary_Search2(array, left, middle - 1, value);

else if (array[middle] < value)

return Binary_Search2(array, middle + 1, right, value);

else

return middle;



int main()

int array[10] = 1,2,3,5,7,8,9,11,13,45 ;

int n = 0, num = 0,ret=0;

n = sizeof(array);

/*int left = 0, right = n-1;*/

cin >> num;

ret = Binary_Search1(array, n, num);

/*ret = Binary_Search2(array, left,right, num);*/

if (ret == -1)

cout << "查找失败!"<< endl;

else

cout << num << "是第" << ret + 1 << "个数" << endl;

system("pause");

return 0;

运行结果1:

8

8是第6个数

请按任意键继续. . .


运行结果2:

17

查找失败!

请按任意键继续. . .


二分查找法的缺陷

二分查找法的O(log n)让它成为十分高效的算法。不过它的缺陷却也是那么明显的。就在它的限定之上:

     必有序,我们很难保证我们的数组都是有序的。当然可以在构建数组的时候进行排序,可是又落到了第二个瓶颈上:它必须是数组数组读取效率是O(1),可是它的插入和删除某个元素的效率却是O(n)。因而导致构建有序数组变成低效的事情。

       解决这些缺陷问题更好的方法应该是使用二叉查找树了,最好自然是自平衡二叉查找树了,高效的(O(n logn))构建有序元素集合,又能如同二分查找法一样快速(O(log n))的搜寻目标数。


本文出自 “岩枭” 博客,请务必保留此出处http://yaoyaolx.blog.51cto.com/10732111/1775691

以上是关于时间复杂度及其计算的主要内容,如果未能解决你的问题,请参考以下文章

算法课笔记系列——NP问题及其计算复杂性

冒泡排序及其时间空间复杂度

整理常见排序算法及其时间复杂度总结

二分查找算法的递归循环实现及其缺陷

二分查找算法的递归循环实现及其缺陷

数据结构之顺序表的插入删除操作(静态分配实现)及其时间复杂度分析