【数据结构与算法】时间复杂度

1 时间复杂度

算法中的基本操作的执行次数,为算法 的时间复杂度。

时间复杂度是一个数学意义上的函数。

2 嵌套循环时间复杂度

// 计算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);
}

在第一个循环中,i 每跑一次,j 跑 N 次,即 N*N

在第二个循环中,k 跑 2*N 次

在第三个循环中,M 跑10次

全部加起来,时间复杂度的表达式为: F(N) = N*N + 2*N + 10

a18dc4894c3c4fc684b9ae6256f9853d.png

F(N) = N^2

N = 10 F(N) = 100

N = 10 F(N) = 10000

N = 1000 F(N) = 1000000

我们会发现,N 越大,表达式的后两项对时间复杂度的影响越小。

所以,我们在计算时,采用估算,即大O的渐进表示法,例如上面的例子用大O的渐进表示法就是O(N) = N^2

3 双重循环时间复杂度的计算

// 计算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);
}

时间复杂度的表达式:O(N) 

// 计算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);
}

O(M+N)

一般情况下时间复杂度计算时未知数都是用的N

但是也可以是M K等

M远大于N -> O(M) 

N远大于M -> O(N)

M和N差不多大 -> O(M) O(N)

4 常数循环的时间复杂度

// 计算Func4的时间复杂度?
void Func4(int N)
{
    int count = 0;
    for (int k = 0; k < 100; ++ k)
    {
         ++count;
    }
    printf("%d\n", count);
}

O(1) 不是代表算法运行一次,而是常数次。

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

while(*str)
{
    if(*str = character)
        return str;
    else
        ++str;
}

strchar查找字符的库函数

例子:hello world

假设查找的是h  最好的情况  O(1)

假设查找的是w  平均的情况 O(N/2)

假设查找的是d  最坏的情况 O(N)

时间复杂度是悲观的预期,看的是最坏的情况。

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;
    }
}

第一趟:N - 1

第二趟:N - 2

第三趟:N - 3

……

最后一趟:1

精确:F(N) = N*(N-1)/2

大O:O(N^2)

总结:算时间复杂度不能只去看几层循环,而要去看它的思想

6 二分查找的时间复杂度

int BinarySearch(int* a, int n, int x)
{
    assert(a);
    int begin = 0;
    int end = n-1;
    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;
}

假设查找X次 N为数组的大小

1* 2* 2* 2* …… = N

2^X = N

X = log2 N

二分查找有多牛呢?

N个数中查找       大概查找次数

1000                    10

100w                    20

10亿                     30

二分查找的缺陷是,它需要提前进行排序。

 7 斐波那契的时间复杂度

// 计算阶乘递归Factorial的时间复杂度?
long long Factorial(size_t N)
{
    return N < 2 ? N : Factorial(N-1)*N;
}

时间复杂度表达式:O(N)

// 计算斐波那契递归Fibonacci的时间复杂度?
long long Fibonacci(size_t N)
{
    return N < 2 ? N : Fibonacci(N-1)+Fibonacci(N-2);
}

相当于等比数列求和

F(N) = (1- 2^N)/(1 - 2) = 2^N - 1

O(2^N)

以上是初步学习时间复杂度的练习,多动动手,多思考,简单题还是可以做出来的。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值