当前位置:   article > 正文

数据结构——时间复杂度(详解,详解,详解)_数据结构时间复杂度总结

数据结构时间复杂度总结

1.1时间复杂度的概念

时间复杂度的定义:在计算机科学中,算法的时间复杂度是一个函数,它定量描述了该算法的运行时间。一个算法执行所耗费的时间,从理论上说,是不能算出来的,只有你把你的程序放在机器上跑起来,才能知道。但是我们需要每个算法都上机测试吗?是可以都上机测试,但是这很麻烦,所以才有了时间复杂度这个分析方式。一个算法所花费的时间与其中语句的执行次数成正比例,算法中的基本操作的执行次数,为算法的时间复杂度。

即:找到某条基本语句与问题规模N之间的数学表达式,就是算出了该算法的时间复杂度
 

  1. // 请计算一下Func1中++count语句总共执行了多少次?
  2. void Func1(int N)
  3. {
  4. int count = 0;
  5. for (int i = 0; i < N ; ++ i)
  6. {
  7. for (int j = 0; j < N ; ++ j)
  8. {
  9. ++count;
  10. }
  11. }
  12. for (int k = 0; k < 2 * N ; ++ k)
  13. {
  14. ++count;
  15. }
  16. int M = 10;
  17. while (M--)
  18. {
  19. ++count;
  20. }
  21. printf("%d\n", count);
  22. }

Func1 执行的基本操作次数 :
Func1=N^2 + 2*N + 10

实际中我们计算时间复杂度时,我们其实并不一定要计算精确的执行次数,而只需要大概执行次数,那么这里我们使用大O的渐进表示法


 1.2 大O的渐进表示法

大O符号(Big O notation):是用于描述函数渐进行为的数学符号

推导大O阶方法:
1、用常数1取代运行时间中的所有加法常数。
2、在修改后的运行次数函数中,只保留最高阶项。
3、如果最高阶项存在且不是1,则去除与这个项目相乘的常数。得到的结果就是大O阶。
使用大O的渐进表示法以后,Func1的时间复杂度为:
N = 10 F(N) = 100
N = 100 F(N) = 10000
N = 1000 F(N) = 1000000
通过上面我们会发现大O的渐进表示法去掉了那些对结果影响不大的项,简洁明了的表示出了执行次数。
另外有些算法的时间复杂度存在最好、平均和最坏情况:
最坏情况:任意输入规模的最大运行次数(上界)
平均情况:任意输入规模的期望运行次数
最好情况:任意输入规模的最小运行次数(下界)
例如:在一个长度为N数组中搜索一个数据x
最好情况:1次找到
最坏情况:N次找到
平均情况:N/2次找到
在实际中一般情况关注的是算法的最坏运行情况,所以数组中搜索数据时间复杂度为O(N)

1.3常见时间复杂度计算举例

例一:

  1. // 计算Func2的时间复杂度?
  2. void Func2(int N)
  3. {
  4. int count = 0;
  5. for (int k = 0; k < 2 * N ; ++ k)
  6. {
  7. ++count;
  8. }
  9. int M = 10;
  10. while (M--)
  11. {
  12. ++count;
  13. }
  14. printf("%d\n", count);
  15. }

时间复杂度:O(N)

我们在计算时只要计算出大概就可以所以我们可以省略2和后面常数10

例二:

  1. // 计算Func3的时间复杂度?
  2. void Func3(int N, int M)
  3. {
  4. int count = 0;
  5. for (int k = 0; k < M; ++ k)
  6. {
  7. ++count;
  8. }
  9. for (int k = 0; k < N ; ++ k)
  10. {
  11. ++count;
  12. }
  13. printf("%d\n", count);
  14. }

时间复杂度:O(M+N)

这个函数里面M和N都是未知数,无法比较出谁大谁小

例三:

  1. // 计算Func4的时间复杂度?
  2. void Func4(int N)
  3. {
  4. int count = 0;
  5. for (int k = 0; k < 100; ++ k)
  6. {
  7. ++count;
  8. }
  9. printf("%d\n", count);
  10. }

 时间复杂度:O(1)

这里我们要注意一下,不论什么常数在这里我们都写成O(1)
 

例四:

  1. // 计算strchr的时间复杂度?
  2. const char * strchr ( const char * str, int character );

实例4基本操作执行最好1次,最坏N次,时间复杂度一般看最坏,时间复杂度为 O(N)
 

例五:冒泡语句

  1. // 计算BubbleSort的时间复杂度?
  2. void BubbleSort(int* a, int n)
  3. {
  4. assert(a);
  5. for (size_t end = n; end > 0; --end)
  6. {
  7. int exchange = 0;
  8. for (size_t i = 1; i < end; ++i)
  9. {
  10. if (a[i-1] > a[i])
  11. {
  12. Swap(&a[i-1], &a[i]);
  13. exchange = 1;
  14. }
  15. }
  16. if (exchange == 0)
  17. break;
  18. }
  19. }

时间复杂度:O(N^2)

这里我们可以看出函数是一个冒泡语句,是一个等差数列,我们在计算等差数列的时候基本操作执行最好N次,最坏执行了(N*(N+1)/2次,通过推导大O阶方法+时间复杂度一般看最坏,时间复杂度为 O(N^2)
 

例六:

  1. // 计算BinarySearch的时间复杂度?
  2. int BinarySearch(int* a, int n, int x)
  3. {
  4. assert(a);
  5. int begin = 0;
  6. int end = n-1;
  7. // [begin, end]:begin和end是左闭右闭区间,因此有=号
  8. while (begin <= end)
  9. {
  10. int mid = begin + ((end-begin)>>1);
  11. if (a[mid] < x)
  12. begin = mid+1;
  13. else if (a[mid] > x)
  14. end = mid-1;
  15. else
  16. return mid;
  17. }
  18. return -1;
  19. }

时间复杂度:O(lgN)

基本操作执行最好1次,最坏O(logN)次,时间复杂度为 O(logN) ps:logN在算法分析中表示是底数为2,对数为N。有些地方会写成lgN
 

例七:

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

时间复杂度:O(N)

这个我们可以知道为递归,在递归中,我们每一次递归都可以执行一次,所以我们可以认为多个1加在一起最后经过N次

例八:

  1. // 计算阶乘递归Fac的时间复杂度?
  2. long long Fac(size_t N)
  3. {
  4. if(0 == N)
  5. return 1;
  6. for(int i=0; i<N; i++)
  7. {
  8. ~
  9. )
  10. return Fac(N-1)*N;
  11. }

时间复杂度:O(N^2)

这题我们可以发现又有递归,而在递归里面还有循环,所以我们可知N随着循环,利用次数会依次减少所以我们本质是一个等差数列,而等差数列在遵循准则的情况下可以化简为N^2


以上就是本次时间复杂度的分享,喜欢的话请三连支持一下哦,感谢您的观看


声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/木道寻08/article/detail/842083
推荐阅读
相关标签
  

闽ICP备14008679号