算法的时间及空间复杂度

简介:java系列技术分享(持续更新中…)
初衷:一起学习、一起进步、坚持不懈
如果文章内容有误与您的想法不一致,欢迎大家在评论区指正
希望这篇文章对你有所帮助,欢迎点赞 收藏 ⭐留言

更多文章请点击
在这里插入图片描述在这里插入图片描述

文章目录

  • 一、 什么是算法?
  • 二、 算法初体验
    • 案例1 计算1到100的和。
    • 案例2 计算10的阶乘
  • 三、 算法的复杂度分析
    • 3.1 时间复杂度分析
      • 3.1.1 案例 计算1到100的和,逐行解析
      • 3.1.2 算法时间复杂度
        • 3.1.2.1 大O记法
        • 3.1.2.2. 最坏情况
    • 3.2 空间复杂度分析

一、 什么是算法?

  • 能够对一定规范的输入,在有限时间内获得所要求的输出
  • 不同的算法可能用不同的时间、空间或效率来完成同样的任务。
  • 一个算法的优劣可以用空间复杂度时间复杂度来衡量。

二、 算法初体验

一个优秀的算法追求以下两个目标:

  1. 花最少的时间完成需求
  2. 占用最少的内存空间完成需求

案例1 计算1到100的和。

第一种解法

public static void main(String[] args) { 
    int sum = 0;
    int n=100;
    for (int i = 1; i <= n; i++) {
        sum += i;
    }  
    System.out.println("sum=" + sum);
}

第二种解法

 public static void main(String[] args) {
        int sum = 0;
        int n=100;
        sum = (n+1)*n/2;
        System.out.println("sum="+sum);
}

很明显,第二种算法完成需求,花费的时间更少一些。

案例2 计算10的阶乘

第一种解法

public class Test {
    public static void main(String[] args) {
        //测试,计算10的阶乘
        long result = fun1(10);
        System.out.println(result);
    }
    //计算n的阶乘
    public static long fun1(long n){
        if (n==1){
            return 1;
        }
        return n*fun1(n-1);
    }
}

第二种解法

public class Test {
    public static void main(String[] args) {
        //测试,计算10的阶乘
        long result = fun2(10);
        System.out.println(result);
    }
    //计算n的阶乘
    public static long fun2(long n){
        int result=1;
        for (long i = 1; i <= n; i++) {
            result*=i;
        }
        return result;
    }
}

第一种解法,使用递归完成需求,fun1方法会执行10次,并且第一次执行未完毕,调用第二次执行…最终,最多的时候,需要在栈内存同时开辟10块内存分别执行10个fun1方法。

第二种解法,使用for循环完成需求,fun2方法只会执行一次,最终,只需要在栈内存开辟一块内存执行fun2方法即可。

很明显,第二种算法完成需求,占用的内存空间更小。

三、 算法的复杂度分析

3.1 时间复杂度分析

事后分析估算方法:
这种方法有很大的缺陷:必须依据算法实现编制好的测试程序,通常要花费大量时间和精力,测试完了如果发现测试的是非常糟糕的算法,那么之前所做的事情就全部白费了,并且不同的测试环境(硬件环境)的差别导致测试的结果差异也很大。
事前分析估算方法:
在计算机程序编写前,依据统计方法对算法进行估算,这包括对算法的时间复杂度进行分析,以了解算法随问题规模n的变化情况并确定其数量级。这种分析可以帮助程序员在编写代码之前预测代码的运行时间,从而更好地优化代码和数据结构,提高代码运行效率。

3.1.1 案例 计算1到100的和,逐行解析

第一种
如果输入量n为1亿,则需要计算1亿次;

public static void main(String[] args) {
    int sum = 0;//执行1次
    int n=100;//执行1次
    for (int i = 1; i <= n; i++) {//执行了n+1次
        sum += i;//执行了n次
    }
    System.out.println("sum=" + sum);
}

第二种
如果输入量n为1亿,则需要计算1次;

public static void main(String[] args) {
        int sum = 0;//执行1次
        int n=100;//执行1次
        sum = (n+1)*n/2;//执行1次
        System.out.println("sum="+sum);
}

经过一系列的研究,通过函数渐近增长分析,这里将结论总结如下:

比较算法随着输入规模的增长量时,可以有以下规则:

1.算法函数中的常数可以忽略;

2.算法函数中最高次幂的常数因子可以忽略;

3.算法函数中最高次幂越小,算法效率越高。

3.1.2 算法时间复杂度

3.1.2.1 大O记法

​在进行算法分析时,语句总的执行次数T(n)是关于问题规模n的函数,进而分析T(n)随着n的变化情况并确定T(n)的量级。算法的时间复杂度,就是算法的时间量度,记作:T(n)=O(f(n))。它表示随着问题规模n的增大,算法执行时间的增长率和f(n)的增长率相同,称作算法的渐近时间复杂度,简称时间复杂度,其中f(n)是问题规模n的某个函数。
用大写O()来体现算法时间复杂度的记法,我们称之为大O记法。一般情况下,随着输入规模n的增大,T(n)增长最慢的算法为最优算法。

下面我们使用大O表示法来表示一些求和算法的时间复杂度:
如果忽略判断条件的执行次数和输出语句的执行次数,那么当输入规模为n时,以上算法执行的次数分别为:
​算法一:3次
算法二:n+3次
​算法三:n^2+2次

如果用大O记法表示上述每个算法的时间复杂度,应该如何表示呢?基于我们对函数渐近增长的分析,推导大O阶的表示法有以下几个规则可以使用:

  1. 用常数1取代运行时间中的所有加法常数;

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

  3. 如果最高阶项存在,且常数因子不为1,则去除与这个项相乘的常数;

所以,上述算法的大O记法分别为:

​ 算法一:O(1)
​ 算法二:O(n)
​ 算法三:O(n^2)

3.1.2.2. 最坏情况

有一个存储了n个随机数字的数组,请从中查找出指定的数字。

public int search(int num){
    int[] arr={11,10,8,9,7,22,23,0};
    for (int i = 0; i < arr.length; i++) {
        if (num==arr[i]){
            return i;
        }
    }
    return -1;
}

最好情况:

​ 查找的第一个数字就是期望的数字,那么算法的时间复杂度为O(1)

最坏情况:

​ 查找的最后一个数字,才是期望的数字,那么算法的时间复杂度为O(n)

平均情况:

​ 任何数字查找的平均成本是O(n/2)

最坏情况是一种保证,在应用中,这是一种最基本的保障,即使在最坏情况下,也能够正常提供服务,所以,除非特别指定,我们提到的运行时间都指的是最坏情况下的运行时间。

3.2 空间复杂度分析

计算机的软硬件都经历了一个比较漫长的演变史,作为为运算提供环境的内存,更是如此,从早些时候的512k,经历了1M,2M,4M…等,发展到现在的8G,甚至16G和32G,所以早期,算法在运行过程中对内存的占用情况也是一个经常需要考虑的问题。我么可以用算法的空间复杂度来描述算法对内存的占用。

1.基本数据类型内存占用情况:

数据类型 内存占用字节数
byte 1
short 2
int 4
long 8
float 4
double 8
boolean 1
char 2
  • 由于现在的计算机设备内存一般都比较大,基本上个人计算机都是4G起步,大的可以达到32G,所以内存占用一般情况下并不是我们算法的瓶颈
  • 注意空间复杂度是衡量算法在运行过程中使用的内存大小,而不是指程序代码本身的大小。因此,在分析空间复杂度时,需要考虑算法在执行过程中所创建的临时变量、数据结构以及其他相关的内存使用情况。
  • 普通情况下直接说复杂度,默认为算法的时间复杂度。
  • 但是,如果你做的程序是嵌入式开发,尤其是一些传感器设备上的内置程序,由于这些设备的内存很小,一般为几kb,这个时候对算法的空间复杂度就有要求了,但是一般做java开发的,基本上都是服务器开发,一般不存在这样的问题。

后续持续更新............................

在这里插入图片描述在这里插入图片描述

你可能感兴趣的:(数据结构与算法,算法,java,开发语言)