- 資訊首頁(yè) > 開(kāi)發(fā)技術(shù) > 編程語(yǔ)言 >
- Java算法之時(shí)間復雜度和空間復雜度的概念和計算
算法效率分析分為兩種:第一種是時(shí)間效率,第二種是空間效率。時(shí)間效率被稱(chēng)為時(shí)間復雜度,而空間效率被稱(chēng)作空間復雜度。 時(shí)間復雜度主要衡量的是一個(gè)算法的運行速度,而空間復雜度主要衡量一個(gè)算法所需要的額外空間。
在計算機發(fā)展的早期,計算機的存儲容量很小。所以對空間復雜度很是在乎。但是經(jīng)過(guò)計算機行業(yè)的迅速發(fā)展,計算機的存儲容量已經(jīng)達到了很高的程度。所以我們如今已經(jīng)不需要再特別關(guān)注一個(gè)算法的空間復雜度。因為現在的內存不像以前那么貴,所以經(jīng)常聽(tīng)到過(guò)犧牲空間來(lái)?yè)Q取時(shí)間的說(shuō)法
在計算機科學(xué)中,算法的時(shí)間復雜度是一個(gè)函數,它定量描述了該算法的運行時(shí)間。
算法中的基本操作的執行次數,為算法的時(shí)間復雜度。從理論上說(shuō),是不能算出來(lái)的,只有你把你的程序放在機器上跑起來(lái),才能知道。但是我們需要每個(gè)算法都上機測試嗎?是可以都上機測試,但是這很麻煩,所以才有了時(shí)間復雜度這個(gè)分析方式。
一個(gè)算法所花費的時(shí)間與其中語(yǔ)句的執行次數成正比例,
算法中的基本操作的執行次數,為算法的時(shí)間復雜度。
實(shí)際中我們計算時(shí)間復雜度時(shí),我們其實(shí)并不一定要計算精確的執行次數,而只需要大概執行次數,那么這里我們使用大O的漸進(jìn)表示法
大O符號(Big O notation):是用于描述函數漸進(jìn)行為的數學(xué)符號
(1)推導大O階方法
用常數1取代運行時(shí)間中的所有加法常數。在修改后的運行次數函數中,只保留最高階項。如果最高階項存在且不是1,則去除與這個(gè)項目相乘的常數。得到的結果就是大O階
代碼如下(示例):
void func(int N){ int count = 0;//執行1次 for (int i = 0; i < N ; i++) {//執行N*N次 for (int j = 0; j < N ; j++) { count++; } } for (int k = 0; k < 2 * N ; k++) {//執行2*N次 count++; } int M = 10;//執行1次 while ((M--) > 0) {//執行10次 count++; } System.out.println(count); }
所以func方法的執行次數為 1+N2+2*N+1+10
我看到func的執行次數,如果當我們的N非常大時(shí),假設N = 100,那么這里的+1和+10是不是可以忽略了,因為1002=10000,在一萬(wàn)面前+1和+10可以說(shuō)是微乎其微了,所以+1和+10沒(méi)什么區別。
這就用到了前面說(shuō)了推導大O階方法,
用常數1取代運行時(shí)間中的所有加法常數。
就變成了 1+N2+2*N+1+1
再來(lái)看
在修改后的運行次數函數中,只保留最高階項。
簡(jiǎn)化后 N2
如果最高階項存在且不是1,則去除與這個(gè)項目相乘的常數。得到的結果就是大O階
這里我們的最高階項是2,但前面沒(méi)有常數所以沒(méi)必要去除,如果N2前面還有個(gè)2就是2N2就要去除2變成 N2
所以使用大O的漸進(jìn)表示法以后,Func的時(shí)間復雜度為 O(N2)
通過(guò)上面我們會(huì )發(fā)現大O的漸進(jìn)表示法去掉了那些對結果影響不大的項,簡(jiǎn)潔明了的表示出了執行次數。時(shí)間復雜度是一個(gè)函數,只能大致估一下這個(gè)算法的時(shí)間復雜度。
另外有些算法的時(shí)間復雜度存在最好、平均和最壞情況。
(1) 最壞情況
最壞情況:任意輸入規模的最大運行次數(上界) 也就是 O(N)
這里的N代表的是問(wèn)題的規模
(2)最好情況
任意輸入規模的最小運行次數(下界) 也就是 O(1)
(3)平均情況
任意輸入規模的期望運行次數
注意:這里的平均情況并不是最好和最壞情況相加的平均值,而是我們期望運行的次數,有時(shí)候平均情況可能和最好或者是最壞情況一樣。
在平常我們所說(shuō)的時(shí)間復雜度一般說(shuō)的都是算法的最壞情況
示例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 通過(guò)推導大O階方法后:時(shí)間復雜度為 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); }
時(shí)間復雜度為:O(M+N)
示例3:
void func4(int N) { int count = 0; for (int k = 0; k < 100; k++) {//用常數1取代運行時(shí)間中的所有加法常數 count++; } System.out.println(count); }
這里的時(shí)間復雜度為 O(1),因為傳進(jìn)來(lái)的N并沒(méi)有使用
示例4:
這是一個(gè)冒泡排序,我們來(lái)求一下它的最好最壞和平均情況的時(shí)間復雜度
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)
這是一個(gè)經(jīng)過(guò)優(yōu)化后的冒泡排序,最好的情況就是該組數據已經(jīng)是有序的了,所以只需走一遍就好了,也是是O(N).
而最壞的情況就把數組全部遍歷了一遍就是 N2
我們前面說(shuō)過(guò)平均情況就是我么個(gè)期望的情況,我們期望的當然就是O(N)
我們知道求時(shí)間復雜度一般求的都是最壞的情況,二分查找只有當我們找最旁邊那兩個(gè)個(gè)數時(shí)才是最壞情況,我們就假設我們要找的就是最邊邊的那個(gè)數。
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; }
所以二分查找的時(shí)間復雜度為 O(log2N)
遞歸的時(shí)間復雜度 = 遞歸的次數*每次遞歸執行的操作的次數
示例1:
long factorial(int N) { return N < 2 ? N : factorial(N-1) * N; }
這里的的遞歸次數為 N 次,這里沒(méi)有循環(huán),每次執行的是一個(gè)三目操作符相當于1次。所以為 N+1次,時(shí)間復雜度就是 O(N)。
示例2:
這是一個(gè)遞歸實(shí)現的斐波那契數列
public static int fib(int n){ if(n==1||n==2){ return 1; }else{ return fib(n-1)+fib(n-2); } }
斐波那契數列的遞歸次數其實(shí)就是一個(gè)等比數列求和,最后的執行次數為 (2n) - 1,通過(guò)通過(guò)推導大O階方法最后的時(shí)間復雜度為 O(2N)
時(shí)間復雜度只是一個(gè)大概的,當數字足夠大時(shí)這里缺失的部分并不影響我們時(shí)間復雜度的計算。
空間復雜度是對一個(gè)算法在運行過(guò)程中臨時(shí)(額外)占用存儲空間大小的量度
占用存儲空間大小的量度 。
空間復雜度不是程序占用了多少bytes的空間,因為這個(gè)也沒(méi)太大意義,所以空間復雜度算的是變量的個(gè)數。
空間復雜度計算規則基本跟實(shí)踐復雜度類(lèi)似,也使用大O漸進(jìn)表示法
(1) 冒泡排序
這個(gè)冒泡排序的空間復雜度為 O(1)
為什么呢?因為空間復雜度是為了解決一個(gè)問(wèn)題額外申請了其他變量,這里的array數組并不是額外的它是必須的,但這里的 sorted 是額外申請的,它每循環(huán)一次就定一次為什么不是O(N)呢?因為每循環(huán)一次這個(gè)變量是不是不要了呢?所以來(lái)來(lái)回回就是這一個(gè)變量。
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的斐波那契數列的代碼,為了解決這個(gè)問(wèn)題申請了一個(gè)額外的數組的空間,空間大小為 N+1。因為1是常數項,所以這個(gè)代碼的空間復雜度為 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)遞歸
這是一個(gè)求階層的遞歸,他的空間復雜度為 O(N)
因為遞歸在遞的過(guò)程中,每遞一次都會(huì )都會(huì )創(chuàng )建一個(gè)臨時(shí)變量。
long factorial(int N) { return N < 2 ? N : factorial(N-1)*N; }
1.在平常我們所說(shuō)的時(shí)間復雜度一般說(shuō)的都是算法的最壞情況
2.時(shí)間復雜度度是一個(gè)函數,這個(gè)函數只能大致估一下這個(gè)算法的時(shí)間復雜度
3.空間復雜度是個(gè)算法在運行過(guò)程中額外占用存儲空間大小的量度
到此這篇關(guān)于Java算法之時(shí)間復雜度和空間復雜度的概念和計算的文章就介紹到這了,更多相關(guān)Java時(shí)間復雜度和空間復雜度內容請搜索腳本之家以前的文章或繼續瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng )、來(lái)自本網(wǎng)站內容采集于網(wǎng)絡(luò )互聯(lián)網(wǎng)轉載等其它媒體和分享為主,內容觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如侵犯了原作者的版權,請告知一經(jīng)查實(shí),將立刻刪除涉嫌侵權內容,聯(lián)系我們QQ:712375056,同時(shí)歡迎投稿傳遞力量。
Copyright ? 2009-2022 56dr.com. All Rights Reserved. 特網(wǎng)科技 特網(wǎng)云 版權所有 特網(wǎng)科技 粵ICP備16109289號
域名注冊服務(wù)機構:阿里云計算有限公司(萬(wàn)網(wǎng)) 域名服務(wù)機構:煙臺帝思普網(wǎng)絡(luò )科技有限公司(DNSPod) CDN服務(wù):阿里云計算有限公司 百度云 中國互聯(lián)網(wǎng)舉報中心 增值電信業(yè)務(wù)經(jīng)營(yíng)許可證B2
建議您使用Chrome、Firefox、Edge、IE10及以上版本和360等主流瀏覽器瀏覽本網(wǎng)站