Java 关于时间复杂度和空间复杂度的深度刨析

目录
  • 1.算法效率
  • 2.时间复杂度
    • 2.1时间复杂度的概念
    • 2.2大O的渐进表示法
    • 2.3常见时间复杂度计算
      • 2.3.1常用的时间复杂度量级
      • 2.3.2常见示例举例
      • 2.3.2示例答案及分析
  • 3.空间复杂度

1.算法效率

算法效率分析分为两种:第一种是时间效率,第二种是空间效率。时间效率被称为时间复杂度,而空间效率被称作空间复杂度。

时间复杂度主要衡量的是一个算法的运行速度,而空间复杂度主要衡量一个算法所需要的额外空间

如今我们更关注的是时间复杂度,而对空间复杂度已不再关注。

2.时间复杂度

2.1时间复杂度的概念

时间复杂度的定义:在计算机科学中,算法的时间复杂度是一个函数,它定量描述了该算法的运行时间。

一个算法所花费的时间与其中语句的执行次数成正比例,因此算法中的基本操作的执行次数,为算法的时间复杂度

2.2大O的渐进表示法

请看如下代码:

// 请计算一下func1基本操作执行了多少次?
void func1(int N){
   int count = 0;
   for (int i = 0; i < N ; i++) {
       for (int j = 0; j < N ; j++) {//N^2次
           count++;
       }
   }
   for (int k = 0; k < 2 * N ; k++) {//2N次
       count++;
   }
   int M = 10;
   while ((M--) > 0){//10次
       count++;
   }
    System.out.println(count);
}

F(N) = N^2 + 2N + 10
Func1 执行的基本操作次数 :
N = 10 , F(N) = 130
N = 100 , F(N) = 10210
N = 1000 , F(N) = 1002010

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

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

推导大O阶方法:

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

使用大O的渐进表示法以后,Func1的时间复杂度为 O(N^2)

另外有些算法的时间复杂度存在最好、平均和最坏情况:
最坏情况:任意输入规模的最大运行次数(上限)
平均情况:任意输入规模的期望运行次数
最好情况:任意输入规模的最小运行次数

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

2.3常见时间复杂度计算

2.3.1常用的时间复杂度量级

2.3.2常见示例举例

2.3.1.1计算 bubbleSort 的时间复杂度

// 计算bubbleSort的时间复杂度?
void bubbleSort(int[] array){
   for (int end = array.length; end > 0; end--){
       boolean sorted = true;
       for (int i = 1; i < end; i++){
           if (array[i - 1] > array[i]){
               Swap(array, i - 1, i);
               sorted = false;
           }
       }
       if (sorted == true){
           break;
       }
   }
}

2.3.1.2计算 binarySearch 的时间复杂度

// 计算binarySearch的时间复杂度?
int binarySearch(int[] array, int value) {
   int begin = 0;
   int end = array.length - 1;
   while (begin <= end) {
       int mid = begin + ((end-begin) / 2);
       if (array[mid] < value)
           begin = mid + 1;
       else if (array[mid] > value)
           end = mid - 1;
       else
           return mid;
   }
   return -1; }

2.3.1.3计算阶乘递归 factorial 的时间复杂度

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

2.3.1.4计算斐波那契递归 fibonacci 的时间复杂度

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

2.3.2示例答案及分析

2.3.2.1 bubbleSort 的时间复杂度

实例4基本操作执行最好N次,最坏执行了(N*(N-1))/2次,通过推导大O阶方法+时间复杂度一般看最坏,时间复杂度为 O(N^2)

2.3.2.2 binarySearch 的时间复杂度

实例5基本操作执行最好1次,最坏O(logN)次,时间复杂度为 O(logN) ps:logN在算法分析中表示是底数为2,对数为N。有些地方会写成lgN。(建议通过折半查找的方式讲解logN是怎么计算出来的)(因为二分查找每次排除掉一半的不适合值,一次二分剩下:n/2/2=4)

2.3.2.3 阶乘递归 factorial 的时间复杂度

递归的时间复杂度=递归的次数*每次递归的次数

实例6通过计算分析发现基本操作递归了N次,时间复杂度为O(N)

2.3.2.4 斐波那契递归 fibonacci 的时间复杂度

实例7通过计算分析发现基本操作递归了2^N次 ,时间复杂度为 O(2^N)

3.空间复杂度

空间复杂度是对一个算法在运行过程中临时占用存储空间大小的量度。空间复杂度不是程序占用了多少bytes的空间,因为这个也没太大意义,所以空间复杂度算的是变量的个数。空间复杂度计算规则基本跟实践复杂度类似,也使用大O渐进表示法。

示例1:计算 bubbleSort 的空间复杂度?

// 计算bubbleSort的空间复杂度?
void bubbleSort(int[] array) {
    for (int end = array.length; end > 0; end--) {
        boolean sorted = true;
        for (int i = 1; i < end; i++) {
           if (array[i - 1] > array[i]) {
              Swap(array, i - 1, i);
              sorted = false;
           }
         }
     if (sorted == true) {
         break;
     }
 }
}

实例1使用了常数个额外空间,所以空间复杂度为 O(1)
示例2:

// 计算fibonacci的空间复杂度?
int[] fibonacci(int n) {
    long[] fibArray = new long[n + 1];
    fibArray[0] = 0;
    fibArray[1] = 1;
    for (int i = 2; i <= n ; i++) {
    fibArray[i] = fibArray[i - 1] + fibArray [i - 2];
    }
return fibArray;
}

实例2动态开辟了N个空间,空间复杂度为 O(N)
示例3:

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

实例3递归调用了N次,开辟了N个栈帧,每个栈帧使用常数的空间,空间复杂度为 O(N)

以上就是Java 关于时间复杂度和空间复杂度的深度刨析的详细内容,更多关于Java 时间复杂度和空间复杂度的资料请关注我们其它相关文章!

(0)

相关推荐

  • Java算法之时间复杂度和空间复杂度的概念和计算

    一.算法效率 算法效率分析分为两种:第一种是时间效率,第二种是空间效率.时间效率被称为时间复杂度,而空间效率被称作空间复杂度. 时间复杂度主要衡量的是一个算法的运行速度,而空间复杂度主要衡量一个算法所需要的额外空间. 在计算机发展的早期,计算机的存储容量很小.所以对空间复杂度很是在乎.但是经过计算机行业的迅速发展,计算机的存储容量已经达到了很高的程度.所以我们如今已经不需要再特别关注一个算法的空间复杂度.因为现在的内存不像以前那么贵,所以经常听到过牺牲空间来换取时间的说法 二.时间复杂度 2.1

  • Java 数据结构之时间复杂度与空间复杂度详解

    目录 算法效率 时间复杂度 什么是时间复杂度 推导大 O 阶的方法 算法情况 计算冒泡排序的时间复杂度 计算二分查找的时间复杂度 计算阶乘递归的时间复杂度 计算斐波那契递归的时间复杂度 空间复杂度 计算冒泡排序的空间复杂度 计算斐波那契数列的空间复杂度(非递归) 计算阶乘递归Factorial的时间复杂度 算法效率 在使用当中,算法效率分为两种,一是时间效率(时间复杂度),二是空间效率(空间复杂度).时间复杂度是指程序运行的速度.空间复杂度是指一个算法所需要的额外的空间. 时间复杂度 什么是时间

  • Java时间复杂度、空间复杂度的深入详解

    目录 算法效率 时间复杂度 什么是时间复杂度 推导大 O 阶的方法 算法情况 计算冒泡排序的时间复杂度 计算二分查找的时间复杂度 计算阶乘递归的时间复杂度 计算斐波那契递归的时间复杂度 空间复杂度 计算冒泡排序的空间复杂度 计算斐波那契数列的空间复杂度(非递归) 计算阶乘递归Factorial的时间复杂度 总结 算法效率 在使用当中,算法效率分为两种,一是时间效率(时间复杂度),二是空间效率(空间复杂度).时间复杂度是指程序运行的速度.空间复杂度是指一个算法所需要的额外的空间. 时间复杂度 什么

  • Java 关于时间复杂度和空间复杂度的深度刨析

    目录 1.算法效率 2.时间复杂度 2.1时间复杂度的概念 2.2大O的渐进表示法 2.3常见时间复杂度计算 2.3.1常用的时间复杂度量级 2.3.2常见示例举例 2.3.2示例答案及分析 3.空间复杂度 1.算法效率 算法效率分析分为两种:第一种是时间效率,第二种是空间效率.时间效率被称为时间复杂度,而空间效率被称作空间复杂度. 时间复杂度主要衡量的是一个算法的运行速度,而空间复杂度主要衡量一个算法所需要的额外空间 如今我们更关注的是时间复杂度,而对空间复杂度已不再关注. 2.时间复杂度 2

  • Java项目工程代码深度刨析总结

    目录 一.背景 二.衡量代码好环的原则 2.1 评判代码指标 2.2 指导理论 三.代码实现技巧 3.1 抽像能力 3.2 组合/聚合复用原则 四.总结 一.背景   最近我们团队有幸接了两个0到1的项目,一期项目很紧急,团队成员也是加班加点,从开始编码到完成仅用了一星期多一点点,期间还不断反复斟酌代码如何抽象代码,如何写得更优雅,一遍又一遍的调整,我也是一次又次的阅读每个团队成员的代码,虽然还有些不如意,但整体来说还算是满意,参与项目的成员经过不断琢磨,对一些功能不断抽像,团队进步也是非常明显

  • Java 十大排序算法之归并排序刨析

    目录 归并排序原理 归并排序API设计 归并排序代码实现 归并排序的时间复杂度分析 归并排序原理 1.尽可能的一组数据拆分成两个元素相等的子组,并对每一个子组继续拆分,直到拆分后的每个子组的元素个数是1为止. ⒉将相邻的两个子组进行合并成一个有序的大组. 3.不断的重复步骤2,直到最终只有一个组为止. 归并排序API设计 类名 Merge 构造方法 Merge():创建Merge对象 成员方法 1.public static void sort(Comparable[] a):对数组内的元素进行

  • Java 十大排序算法之冒泡排序刨析

    目录 冒泡排序原理 冒泡排序API设计 冒泡排序的代码实现 冒泡排序的时间复杂度分析 冒泡排序原理 ①比较相邻的元素,如果前一个元素比后一个元素大,则交换这两个元素的位置 ②对每一对相邻的元素循环上面的步骤,最终最后面的元素就是最大值 冒泡排序API设计 类名 Bubble 构造方法 Bubble:创建Bubble对象 成员方法 1.public static void sort(Comparable[] a):对数组内元素进行排序 2.private static void greater(C

  • Java 十大排序算法之插入排序刨析

    目录 插入排序原理 插入排序API设计 插入排序代码实现 插入排序的时间复杂度分析 插入排序原理 ①把所有元素分成已排序和未排序两组 ②找到未排序组的第一个元素,向已经排序的组中进行插入 ③倒序遍历已经排好的元素,依次和待插入的元素进行比较,直到找到一个元素小于等于待插入元素,那么就把待插入元素放到这个位置,其他元素向后移动一位 插入排序API设计 类名 Insertion 构造方法 Insertion():创建Insertion对象 成员方法 1.public static void sort

  • Java 十大排序算法之堆排序刨析

    二叉堆是完全二叉树或者是近似完全二叉树. 二叉堆满足二个特性︰ 1.父结点的键值总是大于或等于(小于或等于)任何一个子节点的键值. 2.每个结点的左子树和右子树都是一个二叉堆(都是最大堆或最小堆). 任意节点的值都大于其子节点的值--大顶堆(最后输出从小到大排) 任意节点的值都小于其子节点的值---小顶堆(最后输出从大到小排) 堆排序步骤 1.堆化,反向调整使得每个子树都是大顶或者小顶堆(建堆) 2.按序输出元素∶把堆顶和最末元素对调,然后调整堆顶元素(排序) 堆排序代码实现(大顶堆) publ

  • Java 逻辑结构与方法函数详解刨析

    ⭐前言⭐ 本文主要介绍JavaSE的逻辑结构和方法. 对一门编程语言逻辑结构和方法的理解是站在C语言之上的,建议配套C语言版本的分析一起食用 链接直达:

随机推荐