java 快速排序 時間複雜度 空間複雜度 穩定性
1、快速排序的基本思想:
通過一趟排序將待排序記錄分割成獨立的兩部分,其中一部分記錄的關鍵字均比另一部分關鍵字小,則分別對這兩部分繼續進行排序,直到整個序列有序。
先看一下這幅圖:
把整個序列看做一個數組,把第零個位置看做中軸,和最後一個比,如果比它小交換,比它大不做任何處理;交換了以後再和小的那端比,比它小不交換,比他大交換。這樣迴圈往復,一趟排序完成,左邊就是比中軸小的,右邊就是比中軸大的,然後再用分治法,分別對這兩個獨立的陣列進行排序。
2、java程式碼:
</pre><pre name="code" class="java">package com.ynu.www.tool; public class QuickSort { public int getMiddle(int[] arrayInt, int low, int high) { int tmp = arrayInt[low]; while (low < high) { while (low < high && tmp < arrayInt[high]) { high--; } arrayInt[low] = arrayInt[high];// 比中軸小的記錄移到低端 while (low < high && arrayInt[low] < tmp) { low++; } arrayInt[high] = arrayInt[low]; } arrayInt[low] = tmp; return low; } public void quicksort(int[] arrayInt, int low, int high) { if (low < high) { int mid = getMiddle(arrayInt, low, high); quicksort(arrayInt, low, mid); quicksort(arrayInt, mid + 1, high); } } public static void main(String args[]) { QuickSort qs = new QuickSort(); int[] testArray = { 34, 3, 53, 2, 23, 7, 14, 10 }; qs.quicksort(testArray, 0, testArray.length - 1); for (int i = 0; i < testArray.length; i++) { System.out.print(testArray[i] + " "); } } }
3、演算法分析:
平均時間複雜度O(nlogn),最壞時間複雜度O(n*n),輔助空間O(logn)<每次都要分給一個額外空間,而總共有logn次>
每次分成兩段,那麼分的次數就是logn了,每一次處理需要n次計算,那麼時間複雜度就是nlogn了!
根據平均情況來說是O(nlogn),因為在資料分佈等概率的情況下對於單個數據來說在logn次移動後就會被放到正確的位置上了。
最壞是O(n^2).這種情況就是陣列剛好的倒序,然後每次去中間元的時候都是取最大或者最小。
穩定性:不穩定。
4、補充說明:
1、時間複雜度
(1)時間頻度 一個演算法執行所耗費的時間,從理論上是不能算出來的,必須上機執行測試才能知道。但我們不可能也沒有必要對每個演算法都上機測試,只需知道哪個演算法花費的時間多,哪個演算法花費的時間少就可以了。並且一個演算法花費的時間與演算法中語句的執行次數成正比例,哪個演算法中語句執行次數多,它花費時間就多。一個演算法中的語句執行次數稱為語句頻度或時間頻度。記為T(n)。
(2)時間複雜度 在剛才提到的時間頻度中,n稱為問題的規模,當n不斷變化時,時間頻度T(n)也會不斷變化。但有時我們想知道它變化時呈現什麼規律。為此,我們引入時間複雜度概念。 一般情況下,演算法中基本操作重複執行的次數是問題規模n的某個函式,用T(n)表示,若有某個輔助函式f(n),使得當n趨近於無窮大時,T(n)/f(n)的極限值為不等於零的常數,則稱f(n)是T(n)的同數量級函式。記作T(n)=O(f(n)),稱O(f(n)) 為演算法的漸進時間複雜度,簡稱時間複雜度。
在各種不同演算法中,若演算法中語句執行次數為一個常數,則時間複雜度為O(1),
(3)漸進時間複雜度評價演算法時間效能 主要用演算法時間複雜度的數量級(即演算法的漸近時間複雜度)評價一個演算法的時間效能。
2、類似於時間複雜度的討論,一個演算法的空間複雜度(Space Complexity)S(n)定義為該演算法所耗費的儲存空間,它也是問題規模n的函式。漸近空間複雜度也常常簡稱為空間複雜度。
空間複雜度(Space Complexity)是對一個演算法在執行過程中臨時佔用儲存空間大小的量度。一個演算法在計算機儲存器上所佔用的儲存空間,包括儲存演算法本身所佔用的儲存空間,演算法的輸入輸出資料所佔用的儲存空間和演算法在執行過程中臨時佔用的儲存空間這三個方面。演算法的輸入輸出資料所佔用的儲存空間是由要解決的問題決定的,是通過引數表由呼叫函式傳遞而來的,它不隨本演算法的不同而改變。儲存演算法本身所佔用的儲存空間與演算法書寫的長短成正比,要壓縮這方面的儲存空間,就必須編寫出較短的演算法。演算法在執行過程中臨時佔用的儲存空間隨演算法的不同而異,有的演算法只需要佔用少量的臨時工作單元,而且不隨問題規模的大小而改變,我們稱這種演算法是“就地/"進行的,是節省儲存的演算法,如這一節介紹過的幾個演算法都是如此;有的演算法需要佔用的臨時工作單元數與解決問題的規模n有關,它隨著n的增大而增大,當n較大時,將佔用較多的儲存單元,例如將在第九章介紹的快速排序和歸併排序演算法就屬於這種情況。
如當一個演算法的空間複雜度為一個常量,即不隨被處理資料量n的大小而改變時,可表示為O(1);當一個演算法的空間複雜度與以2為底的n的對數成正比時,可表示為0(10g2n);當一個演算法的空I司複雜度與n成線性比例關係時,可表示為0(n).若形參為陣列,則只需要為它分配一個儲存由實參傳送來的一個地址指標的空間,即一個機器字長空間;若形參為引用方式,則也只需要為其分配儲存一個地址的空間,用它來儲存對應實參變數的地址,以便由系統自動引用實參變數。