欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java算法之時間復雜度和空間復雜度的概念和計算

 更新時間:2021年05月06日 15:10:04   作者:愛敲代碼的三毛  
這篇文章主要介紹了Java算法之時間復雜度和空間復雜度的概念和計算,文中有非常詳細的代碼示例,對正在學習java的小伙伴們有非常好的幫助,需要的朋友可以參考下

一、算法效率

算法效率分析分為兩種:第一種是時間效率,第二種是空間效率。時間效率被稱為時間復雜度,而空間效率被稱作空間復雜度。 時間復雜度主要衡量的是一個算法的運行速度,而空間復雜度主要衡量一個算法所需要的額外空間。

在計算機發(fā)展的早期,計算機的存儲容量很小。所以對空間復雜度很是在乎。但是經過計算機行業(yè)的迅速發(fā)展,計算機的存儲容量已經達到了很高的程度。所以我們如今已經不需要再特別關注一個算法的空間復雜度。因為現在的內存不像以前那么貴,所以經常聽到過犧牲空間來換取時間的說法

二、時間復雜度

2.1 時間復雜度的概念

在計算機科學中,算法的時間復雜度是一個函數,它定量描述了該算法的運行時間。

算法中的基本操作的執(zhí)行次數,為算法的時間復雜度。從理論上說,是不能算出來的,只有你把你的程序放在機器上跑起來,才能知道。但是我們需要每個算法都上機測試嗎?是可以都上機測試,但是這很麻煩,所以才有了時間復雜度這個分析方式。

一個算法所花費的時間與其中語句的執(zhí)行次數成正比例,
算法中的基本操作的執(zhí)行次數,為算法的時間復雜度。

2.2 大O的漸進表示法

實際中我們計算時間復雜度時,我們其實并不一定要計算精確的執(zhí)行次數,而只需要大概執(zhí)行次數,那么這里我們使用大O的漸進表示法

大O符號(Big O notation):是用于描述函數漸進行為的數學符號

(1)推導大O階方法

用常數1取代運行時間中的所有加法常數。在修改后的運行次數函數中,只保留最高階項。如果最高階項存在且不是1,則去除與這個項目相乘的常數。得到的結果就是大O階

代碼如下(示例):

 void func(int N){
        int count = 0;//執(zhí)行1次
        for (int i = 0; i < N ; i++) {//執(zhí)行N*N次
            for (int j = 0; j < N ; j++) {
                count++;
            }
        }
        for (int k = 0; k < 2 * N ; k++) {//執(zhí)行2*N次
            count++;
        }
        int M = 10;//執(zhí)行1次
        while ((M--) > 0) {//執(zhí)行10次
            count++;
        }
        System.out.println(count);
    }

所以func方法的執(zhí)行次數為 1+N2+2*N+1+10

我看到func的執(zhí)行次數,如果當我們的N非常大時,假設N = 100,那么這里的+1和+10是不是可以忽略了,因為1002=10000,在一萬面前+1和+10可以說是微乎其微了,所以+1和+10沒什么區(qū)別。

這就用到了前面說了推導大O階方法,

用常數1取代運行時間中的所有加法常數。

就變成了 1+N2+2*N+1+1

再來看

    在修改后的運行次數函數中,只保留最高階項。

簡化后 N2

    如果最高階項存在且不是1,則去除與這個項目相乘的常數。得到的結果就是大O階

這里我們的最高階項是2,但前面沒有常數所以沒必要去除,如果N2前面還有個2就是2N2就要去除2變成 N2
所以使用大O的漸進表示法以后,Func的時間復雜度為 O(N2)

通過上面我們會發(fā)現大O的漸進表示法去掉了那些對結果影響不大的項,簡潔明了的表示出了執(zhí)行次數。時間復雜度是一個函數,只能大致估一下這個算法的時間復雜度。

2.3 時間復雜度的三種情況

另外有些算法的時間復雜度存在最好、平均和最壞情況。

(1) 最壞情況

最壞情況:任意輸入規(guī)模的最大運行次數(上界) 也就是 O(N)

這里的N代表的是問題的規(guī)模

(2)最好情況

任意輸入規(guī)模的最小運行次數(下界) 也就是 O(1)

(3)平均情況

任意輸入規(guī)模的期望運行次數

注意:這里的平均情況并不是最好和最壞情況相加的平均值,而是我們期望運行的次數,有時候平均情況可能和最好或者是最壞情況一樣。

在平常我們所說的時間復雜度一般說的都是算法的最壞情況

2.4 常見時間復雜度計算舉例

2.4.1 例子

示例1:

void func2(int N) {
	int count = 0;//1
	for (int k = 0; k < 2 * N ; k++) { //2*N
	   count++;
	}
	int M = 10;//1
	while ((M--) > 0) {//10
	   count++;
	}
	System.out.println(count);
}

1+2*N+1+10 通過推導大O階方法后:時間復雜度為 O(N)

示例2:

void func3(int N, int M) {
int count = 0;//常數可以不加
for (int k = 0; k < M; k++) {//M
   count++;
}
for (int k = 0; k < N ; k++) {//N
   count++;
}
System.out.println(count);
}

時間復雜度為:O(M+N)

示例3:

void func4(int N) {
int count = 0;
for (int k = 0; k < 100; k++) {//用常數1取代運行時間中的所有加法常數
   count++;
}
System.out.println(count);
}

這里的時間復雜度為 O(1),因為傳進來的N并沒有使用

2.4.2 冒泡排序時間復雜度

示例4:

這是一個冒泡排序,我們來求一下它的最好最壞和平均情況的時間復雜度

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

最好:O(N)
最壞:O(N2)
平均:O(N)

這是一個經過優(yōu)化后的冒泡排序,最好的情況就是該組數據已經是有序的了,所以只需走一遍就好了,也是是O(N).
而最壞的情況就把數組全部遍歷了一遍就是 N2
我們前面說過平均情況就是我么個期望的情況,我們期望的當然就是O(N)

2.4.3 二分查找的時間復雜度

我們知道求時間復雜度一般求的都是最壞的情況,二分查找只有當我們找最旁邊那兩個個數時才是最壞情況,我們就假設我們要找的就是最邊邊的那個數。

public static int binarySearch(int[] arr,int x){
            int left = 0;
            int right = arr.length-1;
            int mid = 0;//中間下標

            while(left <= right){
                mid = left+(right-left)/2;
                if(arr[mid] > x){
                    right = mid - 1;
                }else if(arr[mid] < x){
                    left = mid+1;
                }else{
                    return mid;
                }
            }

            return -1;
  }

在這里插入圖片描述

所以二分查找的時間復雜度為 O(log2N)

2.4.4 遞歸的時間復雜度

遞歸的時間復雜度 = 遞歸的次數*每次遞歸執(zhí)行的操作的次數

示例1:

long factorial(int N) {
 return N < 2 ? N : factorial(N-1) * N;
}

這里的的遞歸次數為 N 次,這里沒有循環(huán),每次執(zhí)行的是一個三目操作符相當于1次。所以為 N+1次,時間復雜度就是 O(N)。

示例2:

這是一個遞歸實現的斐波那契數列

public static int fib(int n){
        if(n==1||n==2){
            return 1;
        }else{
            return fib(n-1)+fib(n-2);
        }
}

斐波那契數列的遞歸次數其實就是一個等比數列求和,最后的執(zhí)行次數為 (2n) - 1,通過通過推導大O階方法最后的時間復雜度為 O(2N)

在這里插入圖片描述

時間復雜度只是一個大概的,當數字足夠大時這里缺失的部分并不影響我們時間復雜度的計算。

三、空間復雜度

3.1 空間復雜度概念

空間復雜度是對一個算法在運行過程中臨時(額外)占用存儲空間大小的量度
占用存儲空間大小的量度 。
空間復雜度不是程序占用了多少bytes的空間,因為這個也沒太大意義,所以空間復雜度算的是變量的個數。
空間復雜度計算規(guī)則基本跟實踐復雜度類似,也使用大O漸進表示法

3.2 空間復雜度的計算

(1) 冒泡排序

這個冒泡排序的空間復雜度為 O(1)

為什么呢?因為空間復雜度是為了解決一個問題額外申請了其他變量,這里的array數組并不是額外的它是必須的,但這里的 sorted 是額外申請的,它每循環(huán)一次就定一次為什么不是O(N)呢?因為每循環(huán)一次這個變量是不是不要了呢?所以來來回回就是這一個變量。

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) 斐波那契數列

這里的空間復雜度為 O(N)
這里為了求第1~N的斐波那契數列的代碼,為了解決這個問題申請了一個額外的數組的空間,空間大小為 N+1。因為1是常數項,所以這個代碼的空間復雜度為 O(N)

public static long[] 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;
    }

(3)遞歸

這是一個求階層的遞歸,他的空間復雜度為 O(N)
因為遞歸在遞的過程中,每遞一次都會都會創(chuàng)建一個臨時變量。

long factorial(int N) {
 return N < 2 ? N : factorial(N-1)*N;
}

四、總結

1.在平常我們所說的時間復雜度一般說的都是算法的最壞情況
2.時間復雜度度是一個函數,這個函數只能大致估一下這個算法的時間復雜度
3.空間復雜度是個算法在運行過程中額外占用存儲空間大小的量度

到此這篇關于Java算法之時間復雜度和空間復雜度的概念和計算的文章就介紹到這了,更多相關Java時間復雜度和空間復雜度內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • Spring Data Jpa 復合主鍵的實現

    Spring Data Jpa 復合主鍵的實現

    這篇文章主要介紹了Spring Data Jpa 復合主鍵的實現,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-04-04
  • Java中的異常和處理機制實例詳解

    Java中的異常和處理機制實例詳解

    這篇文章主要介紹了Java中的異常和處理機制,結合實例形式詳細分析了Java異常與處理機制的相關概念、原理、用法及操作注意事項,需要的朋友可以參考下
    2019-05-05
  • Java大數據處理的核心技術MapReduce框架

    Java大數據處理的核心技術MapReduce框架

    MapReduce是一種分布式計算框架,適用于大規(guī)模的數據處理。它將大數據分成多個小數據塊,通過Map和Reduce兩個階段對數據進行處理和分析。MapReduce框架具有可靠、高效、可擴展等特點,已經成為大數據處理的核心技術
    2023-05-05
  • Java終止循環(huán)體的具體實現

    Java終止循環(huán)體的具體實現

    這篇文章主要介紹了Java終止循環(huán)體的具體實現,需要的朋友可以參考下
    2014-02-02
  • Springboot整合Mybatis傳值的常用方式總結

    Springboot整合Mybatis傳值的常用方式總結

    今天給大家?guī)淼氖顷P于Springboot的相關知識,文章圍繞著Springboot整合Mybatis傳值的常用方式展開,文中有非常詳細的介紹及代碼示例,需要的朋友可以參考下
    2021-06-06
  • 詳解springboot設置默認參數Springboot.setDefaultProperties(map)不生效解決

    詳解springboot設置默認參數Springboot.setDefaultProperties(map)不生效解決

    這篇文章主要介紹了詳解springboot設置默認參數Springboot.setDefaultProperties(map)不生效解決,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-07-07
  • Spring Boot集成Druid查看配置是否生效的方法

    Spring Boot集成Druid查看配置是否生效的方法

    本文主要介紹了Spring Boot集成Druid查看配置是否生效的方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-06-06
  • springmvc整合freemarker配置的詳細步驟

    springmvc整合freemarker配置的詳細步驟

    本篇文章主要介紹了springmvc整合freemarker的詳細步驟,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-05-05
  • 使用Mybatis生成樹形菜單的方法詳解

    使用Mybatis生成樹形菜單的方法詳解

    開發(fā)中我們難免會遇到各種樹形結構展示的場景,比如用戶登錄系統(tǒng)后菜單的展示等,本文為大家整理了使用Mybatis生成樹形菜單的方法,感興趣的小伙伴可以了解一下
    2023-06-06
  • java?WebSocket?服務端實現代碼

    java?WebSocket?服務端實現代碼

    WebSocket協(xié)議是基于TCP的一種新的網絡協(xié)議。它實現了瀏覽器與服務器全雙工(full-duplex)通信——允許服務器主動發(fā)送信息給客戶端,這篇文章主要介紹了java?WebSocket?服務端代碼,代碼簡單易懂,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-02-02

最新評論