数据结构—1.时间复杂度

目录

前言

一、时间复杂度

二、大O表示法

三,实例介绍

例1:O(N^2)

例2:O(1)

例3:O(M +N)

(重点)例4:O(N)

例5:冒泡排序( O(N^2) )

例6:二分法查找(O(log2N))

例7:

(1)递归法(阶乘)O(N) | O(1)

(2)递归法(斐波那契数列)( O(2^N))

总结



前言

     本文介绍数据结构的入门——时间复杂度。将会对时间复杂度进行剖析,通过例题讲解时间复杂度的应用范围和注意事项。


一、时间复杂度


概念:算法的时间复杂度是一个函数:(是数学含义上的函数)数据里面带未知数的函数式。

含义:算法在机器中运行所消耗的时间。

实际意义:算法中基本操作的执行次数。

作用和理解:降低占用内存和减少运行时间,提高效率。

好的算法相当于拿着筷子吃饭,差的算法相当于拿着竹竿吃饭,又长又麻烦。


二、大O表示法

大O符号(Big O notation):用于描述函数渐进行为的数学符号(描述时间复杂度)

推导大O阶方法:

1,用常数1取代运行次数中的所有加法常数;

2,在修改后的运行次数函数中,只保留最高阶项;

3,如果最高阶项存在且不是1,则去除与这个项目相乘的常数。得到的结果就是大O阶;

含义:(保留最高阶的未知数,不保留常系数)。


三,实例介绍

例1:O(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     O(N^2)

  • N =10     F(N) = 130
  • N =100    F(N) =10210
  • N = 1000  F(N) =1002010
  • 随着N的变大,后两项的结果影响逐渐变小
  • 当N无限大的时候,后两项对结果的影响可以忽略不计。
  • 所以时间复杂度为O(N^2)。

例2:O(1)

代码如下:

void Func2(int N)
{
    int count =0;
    for(int i =0;i<100;++i)
    {      
              ++count;
   
    }

如果只是循环次数只是常数项的话者就直接是O(1)

例3:O(M +N)

代码如下:

void Func1(int N, int M)
{
    int count =0;
    for(int i =0;i<N;++i)
    {
         
              ++count;
    }
     for(int k = 0; k < M; ++k)
      { 
          ++count;
      }
 
        printf("%d\n",count);

虽然是不同的未知数,但是时间复杂度O只看阶数:所以为O(M)或O(N)

(重点)例4:O(N)

计算strchr的时间复杂度

const char* strchr(const char *str,int character);
whlie(*str)
{
      if(*str==chaeacter)
       return str;
       else
         ++str;
}
return NULL;

此类时间复杂度是通过输入进去的数组的元素个数确定。

  • 最好可以为1
  • 最坏可以为N
  • 但是时间复杂度一般取最坏的情况,所以此题的搜索数组数据的时间复杂度为O(N)
  • 有些算法的时间复杂度存在最好,平均,最坏情况:
  • 最坏情况:输入任意规模的最大运行次数(次数上限)
  • 平均情况:输入任意期望的运行次数
  • 最好情况:输入任意规模的最小运行次数(次数下限)

例5:冒泡排序( O(N^2) )

int Fib(int *a, int size_a)
{
   for (int i =0;i<size_a -1;i++)
   {
     for (int j = 0; j< size_a -1 -i;j++)
     {
        int temp;
        if( a[j] < a[j+1] )
       {
         temp = a[j];
         a[j] = a[j+1]
         a[j+1] = temp;
        }
      }
    }

}

例6:二分法查找(O(log2N))

我们要准确分析算法时间的复杂度,一定要去看思想,不能只去看程序是几层循环。

int BinarySearch(int*a, int n, int x)
{
    assert(a);     //排序
   
    int begin =0;
    int end =n;
    while (begin <end)
    {
        int mid = begin +((end-begin)>>1);
        if(a[mid] < x)
            begin = mid+1;
        else if(a[mid]> x)
            end = mid;
        else 
            return mid;
         }
           
       return -1;
}

 N(循环次数)X(查找次数)

 通常运算级的大小在初始基数特别大的时候比较有优势。


例7:

(1)递归法(阶乘)O(N) | O(1)

时间复杂度计算·

1,每次函数调用为O(1),那么就看他的递归次数

 2,每次函数调用不是O(1),那么就看他的递归调用中次数的累加

long  long Fac (size_t N)
{
  if(0 ==N)
     return 1;
 
   return Fac(N-1)*N;
}

(2)递归法(斐波那契数列)( O(2^N))

long long  Fib(size_t N)
{
    if(N < 3)
       return 1;
    return Fib(N-1) +Fib(N-2);
}
    

 递归法算斐波那契数列是比较占用内存的一种方法,运行次数随着设定值呈指数性增长。

总结

1.本次讲了时间复杂度的基本认识。

通过对7例不同的时间复杂度的分析,我们可以得出以下结论:

(1)时间复杂度不局限与循环有关,核心是与算法思想有关。

(2)时间复杂度主要取其最坏循环次数。

(3)通过对时间复杂度的认识,能更好的对我们的程序进行优化。

  • 3
    点赞
  • 55
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值