【数据结构】——时间复杂度、空间复杂度(下)

简介: 【数据结构】——时间复杂度、空间复杂度(下)

✨四、时间复杂度

1.时间复杂度表示

因为在不同的硬件电路中,同一个程序编译花费的时间是不同的,因此,计算时间复杂度不能直接计算程序运行花费的时间,而算法中的基本操作的执行次数,就是算法的时间复杂度。时间复杂度用大写字母O加上( )表示,即O( );

2.大O的渐进表示法

推导大O阶方法:

  1. 用常数1取代运行时间中的所有加法常数。
  2. 在修改后的运行次数函数中,只保留最高阶项。
  3. 如果最高阶项存在且不是1,则去除与这个项目相乘的常数。得到的结果就是大O阶。

请计算下列代码的时间复杂度:

//例1
void fun1(int n)
{
    int count = 0;
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < n; j++)
        {
        ++count;
        }
    }
    
    for (int i = 0; i < 2 * n; i++)
    {
        ++count;
    }
    
    int M = 10;
    while (M--)
    {
        ++count;
    }
    printf("%d", count);
}

Func1执行的基本操作次数 :

F(N)=N2+2∗N+10F(N)=N^2+2*N+10 F(N)=N2+2N+10

  • N = 10 F(N) = 130
  • N = 100 F(N) = 10210
  • N = 1000 F(N) = 1002010

通过上面我们会发现大O的渐进表示法去掉了那些对结果影响不大的项,简洁明了的表示出了执行次数。

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

O(N2)O(N^2) O(N2)


另外有些算法的时间复杂度存在最好、平均和最坏情况:

最坏情况:任意输入规模的最大运行次数(上界)
平均情况:任意输入规模的期望运行次数
最好情况:任意输入规模的最小运行次数(下界)

例如:在一个长度为N数组中搜索一个数据x
最好情况:1次找到
最坏情况:N次找到
平均情况:N/2次找到

在实际中一般情况关注的是算法的最坏运行情况,所以数组中搜索数据时间复杂度为O(N)


练习题

题目1:

//例1
void fun2(int n)
{
    int count = 0;
    for (int i = 0; i < 2 * n; i++)
    {
        ++count;
    }
    int M = 10;
    while (M--)
    {
        ++count;
    }
    printf("%d", count);
}

此时算法的执行次数是2N+10次,通过推导大O的渐进表示法 时间复杂度是O(N)


题目2

//例2
void fun3(int N,int M)
{
    int count = 0;
    for (int i = 0; i < N; i++)
    {
        ++count;
    }
    for (int i = 0; i < M; i++)
    {
        ++count;
    }
    printf("%d", count);
}

此时算法的执行次数是M+N次,有两个未知数,时间复杂度是O(M+N);
如果给了条件:

  1. M远大于N,时间复杂度是O(M);
  2. M,N大小差不多,时间复杂度是O(M)或O(N);

题目3:

//例3
void fun3(int N, int M)
{
    int count = 0;
    for (int i = 0; i < 100; i++)
    {
        ++count;
    }
    printf("%d", count);
}

执行次数为100次 为是常数,所以时间复杂度为O( 1 )


题目4

//例4
const char* strchr(const char* str, char character)
{
    while (*str != '\0')
    {
        if (*str == character)
            return str;

        ++str;
    }
    return NULL;
}

sttrchr是在一个字符串中查找一个字符,查找次数最好O(1),最坏O(2),根据大O的渐进表示法所以时间复杂度为O(N)


题目5

//例5 冒泡排序
void BUbbleSort(int* a, int n)
{
    assert(a);
    for (size_t end = n; end > 0; --end)
    {
        int exchange = 0;
        for (size_t i = n; 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…3,2,1反过来就是1,2,3,…,n-3,n-2,n-1规律就是一个等差数列根据等差数列求和公式(n^2+n)/2,

那么根据大O的渐进表示法就是O(N ^ 2)


题目6

//例6
//有序数组二分查找
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/2/2/2…=1,那么就可以变换为2^x=n,那么x就是log以2为底,n的次方,时间复杂度就是

O(log2N)O(log2^N) O(log2N)


题目7

//例7
//求阶乘递归
long long Factorial(size_t N)
{
    return N < 2 ? N : Factorial(N - 1) * N;
}

这题N是不是要递归到1才停止递归,那么就是递归N次。

这个题目求N阶层,那么算法的执行次数就是N,时间复杂度就是O(N)

递归复杂度=递归次数*每次递归函数次数


题目8:

//例8
//求斐波那契数列
long long Fibonacci(size_t N)
{
    return N < 2 ? N : Fibonacci(N - 1) + Fibonacci(N - 2);
}

大O的渐进表示法时间复杂度是O(2^N)

画图分析:

【数据结构】——时间复杂度、空间复杂度_时间复杂度_02

非递归算法 O(n)=n

//非递归写法
int fabio_for(int n)
{
    int f1=1;
    int f2=1;
    int f3=1;
    
    for(int i=2;i<n;i++)
    {
    f3=f1+f2;
    f1=f2;
    f2=f3;
    }
    return f3;
}

⌚五.空间复杂度

1.空间复杂度表示

空间复杂度是对一个算法在运行过程中临时占用存储空间大小的量度,即在函数中有几个临时变量

2.空间复杂度经典题目

题目1

void BUbbleSort(int* a, int n)
{
    assert(a);
    for (size_t end = n; end > 0; --end)
    {
        int exchange = 0;
        for (size_t i = n; i > end; ++i)
        {
            if (a[i - 1] > a[i])
            {
                Swap(&a[i - 1], &a[i]);
                exchange = 1;
            }
        }
        if (exchange == 0)
            break;
    }
}

使用了5个( 常数 )个额外空间,所以空间复杂度为 O(1)


题目2


// 计算Fibonacci的空间复杂度?
long long* Fibonacci(size_t n)
{
    if (n == 0)
        return NULL;
    //动态开辟了n+1个空间
    long long* fibArray =(long long*)malloc((n + 1) * sizeof(long long)); fibArray[0] = 0;
    
    fibArray[1] = 1; for (int i = 2; i <= n; ++i)
    {
        fibArray[i] = fibArray[i - 1] + fibArray[i - 2];
    }

    return fibArray;
}

这里动态开辟了n+1个空间,所以空间复杂度是O(N)。


题目3:

//求阶乘递归
long long Factorial(size_t N)
{
    return N < 2 ? N : Factorial(N - 1) * N;
}

里递归每次调用一次函数,就会开辟一次栈帧,每个栈帧使用了常数个空间,所以空间复杂度为O(N)


目录
相关文章
|
22天前
|
算法
数据结构:1、时间复杂度
数据结构:1、时间复杂度
16 1
|
2月前
|
算法
数据结构之时间复杂度
数据结构之时间复杂度
|
2月前
|
机器学习/深度学习 算法 搜索推荐
数据结构第一弹---时间复杂度
数据结构第一弹---时间复杂度
|
2月前
|
机器学习/深度学习 存储 缓存
数据结构从入门到精通——算法的时间复杂度和空间复杂度
算法的时间复杂度和空间复杂度是评估算法性能的两个重要指标。时间复杂度主要关注算法执行过程中所需的时间随输入规模的变化情况,而空间复杂度则关注算法执行过程中所需的最大存储空间或内存空间。
77 0
|
8天前
【数据结构】二叉树-堆(top-k问题,堆排序,时间复杂度)
【数据结构】二叉树-堆(top-k问题,堆排序,时间复杂度)
16 4
|
1月前
|
算法 数据处理 C语言
【数据结构与算法】快速排序(详解:快排的Hoare原版,挖坑法和双指针法|避免快排最坏时间复杂度的两种解决方案|小区间优化|非递归的快排)
【数据结构与算法】快速排序(详解:快排的Hoare原版,挖坑法和双指针法|避免快排最坏时间复杂度的两种解决方案|小区间优化|非递归的快排)
|
1月前
|
机器学习/深度学习 存储 算法
初阶数据结构之---导论,算法时间复杂度和空间复杂度(C语言)
初阶数据结构之---导论,算法时间复杂度和空间复杂度(C语言)
|
2月前
|
机器学习/深度学习 算法
【数据结构】算法的时间复杂度
【数据结构】算法的时间复杂度
11 2
|
2月前
|
机器学习/深度学习 存储 缓存
数据结构--算法的时间复杂度和空间复杂度
数据结构--算法的时间复杂度和空间复杂度
|
6天前
|
机器学习/深度学习 算法 测试技术
【单调栈】3113. 边界元素是最大值的子数组数目
【单调栈】3113. 边界元素是最大值的子数组数目