1. 程式人生 > >快速排序演算法及優化

快速排序演算法及優化

基本思想:

1)選擇一個基準元素,通常選擇第一個元素或者最後一個元素,

2)通過一趟排序講待排序的記錄分割成獨立的兩部分,其中一部分記錄的元素值均比基準元素值小。另一部分記錄的 元素值比基準值大。

3)此時基準元素在其排好序後的正確位置

4)然後分別對這兩部分記錄用同樣的方法繼續進行排序,直到整個序列有序。

快速排序的示例:

(a)一趟排序的過程:

(b)排序的全過程


演算法的實現:

 遞迴實現:

import java.util.Arrays;

public class QuickSort {
	public static void main(String[] args) {
		int[] data = { 5, 1, 9, 3, 7, 4, 8, 6, 2 };
		System.out.println("排序前:" + Arrays.toString(data));
		quickSort(data, 0, data.length - 1);
		System.out.println("排序後:" + Arrays.toString(data));

	}

	private static void quickSort(int[] data, int low, int high) {
		int base;
		if (low < high) {
			base = partition(data, low, high);
			quickSort(data, low, base - 1);
			quickSort(data, base + 1, high);
		}
	}

	private static int partition(int[] data, int i, int j) {
		int base = data[i];// 選定第一個數為基準 (可以優化為三數取中,即取左右中三個數的中間數)

		while (i < j) {
			while (i < j && data[j] > base)
				j--;
			if (i < j) // 如果不加此比較,swap兩個相同位置的記錄,結果是0
				swap(data, i, j); // 將比樞軸記錄小的交換到低端

			while (i < j && data[i] < base)
				i++;
			if (i < j)
				swap(data, i, j); // 將比樞軸記錄大的交換到高階
		}
		return i;
	}

	private static void swap(int[] a, int i, int j) {

		a[i] = a[i] + a[j];
		a[j] = a[i] - a[j];
		a[i] = a[i] - a[j];
	}

	// 優化演算法 優化遞迴操作及小陣列時的排序方案
	private static void quickSort1(int[] data, int low, int high) {
		int base;
		int max_length_insert_sort = 9;// 當high-low大於常數時用快速排序
		if ((high - low) > max_length_insert_sort) {
			while (low < high) {
				base = partition1(data, low, high);
				quickSort1(data, low, base - 1);//對低子表遞迴排序
				low = base + 1;//尾遞迴
			}
		} else
			new StraightInsertionSort().insertionSort2(data);// 否則用插入排序
	}

	// 優化不必要的交換
	private static int partition1(int[] data, int i, int j) {
		int base = data[i];// 選定第一個數為基準
		int temp = base; // 備份樞軸
		while (i < j) {
			while (i < j && data[j] > base)
				j--;
			data[i] = data[j];// 採用替換而不是交換的方式進行操作

			while (i < j && data[i] < base)
				i++;
			data[j] = data[i];// 採用替換而不是交換的方式進行操作
		}
		data[i] = temp;// 將樞軸值替換回來
		return i;
	}

	// 三數取中 :即取三個關鍵字先進行排序,將中間數作為樞軸,一般取左端、右端、中間三個數。
	public int getMiddle(int[] data, int i, int j) {

		int m = i + (j - i) / 2;
		if (data[i] < data[j])
			swap(data, i, j);
		if (data[m] > data[j])
			swap(data, m, j);
		if (data[m] > data[i])
			swap(data, m, i);

		return data[i];

	}
}

通常我們在進行快速排序時,關鍵資料(即基準元素)一般選取序列的第一個元素,但在序列大部分有序時,這會致使最壞時間複雜度O(n^2)的出現,為了避免這種情況的發生,我們可以選擇以下幾種方法對其進行優化:

  • 三數取中;
  • 優化遞迴操作;
  • 使用並行或多執行緒處理子序列;
  • 隨機選擇關鍵資料進行快排,可以使用rand()方法;
  • 當待排序序列的長度分割到一定大小後,使用插入排序;
  • 在一次分割結束後,可以把與 Key 相等的元素聚在一起,繼續下次分割時,不用再對與 key 相等元素分割。

演算法分析:
快速排序的時間複雜度與關鍵字初始序列有關。
最壞時間複雜度:O(n^2):
以第一個數或最後一個數為基準時,當初始序列整體或區域性有序時,快速排序的效能會下降。若整體有序,此時,每次劃分只能分出一個元素,具有最壞時間複雜度,快速排序將退化成氣泡排序。

最好時間複雜度:O(n*以2為底n的對數) (平均)
每次選取的基準關鍵字都是待排序列的中間值,也就是說每次劃分可以將序列劃分為長度相等的兩個序列。快速排序的遞迴過程可以用一棵二叉樹來表示,遞迴樹的高度是2為底的對數,每層需要比較的次數是n/2,所以最好時間複雜度是O(n*以2為底n的對數),因為很多時候輸入序列都是亂序的,所以最好時間複雜度也是平均時間複雜度。

不穩定!

相關推薦

快速排序演算法優化

基本思想: 1)選擇一個基準元素,通常選擇第一個元素或者最後一個元素, 2)通過一趟排序講待排序的記錄分割成獨立的兩部分,其中一部分記錄的元素值均比基準元素值小。另一部分記錄的 元素值比基準值大。 3)此時基準元素在其排好序後的正確位置 4)然後分別對這兩部分記錄

雙路快速排序演算法三路快速排序演算法視覺化

雙路快速排序演算法 工具類 import java.awt.*; import java.awt.geom.Ellipse2D; import java.awt.geom.Rectangle2D; import java.lang.Interrup

【手寫排序演算法優化】氣泡排序

c++程式碼 #include<iostream.h> void Print(int A[],int len) {for(int i=0;i<len;i++){cout<<A[i]<<" ";}cout<<endl;

快速排序演算法得到陣列中任意第K大的數

1 快速排序的圖解 假設我們現在對6 1 2 7 9 3 4 5 10 8這個10個數進行排序。首先在這個序列中隨便找一個數作為基準數(不要被這個名詞嚇到了,就是一個用來參照的數,待會你就知道它用來做啥的了)。為了方便,就讓第一個數6作為基準數吧。接下來,需要將這個序列中所有比基準數大的

快速排序演算法時間複雜度分析(原地in-place分割槽版本)

快速排序演算法一般來說是採用遞迴來實現,其最關鍵的函式是partition分割函式,其功能是將陣列劃分為兩部分,一部分小於選定的pivot,另一部分大於選定的pivot。我們將重點放在該函式上面。 partition函式總體思路是自從一邊查詢,找到小於pivot的元素,則將

快速排序演算法(QSort,快排)C語言實現

上節介紹瞭如何使用起泡排序的思想對無序表中的記錄按照一定的規則進行排序,本節再介紹一種排序演算法——快速排序演算法(Quick Sort)。 C語言中自帶函式庫中就有快速排序——qsort函式 ,包含在 <stdlib.h> 標頭檔案中。 快速排序演算法是在起泡排序的基礎上進行改進的一種演算

快速排序演算法原理實現(單軸快速排序、三向切分快速排序、雙軸快速排序

歡迎探討,如有錯誤敬請指正 1. 單軸快速排序的基本原理 快速排序的基本思想就是從一個數組中任意挑選一個元素(通常來說會選擇最左邊的元素)作為中軸元素,將剩下的元素以中軸元素作為比較的標準,將小於等於中軸元素的放到中軸元素的左邊,將大於中軸元素的放到中軸元素的右邊,然後以當前中軸元素的位置為界,將左半部分子

【轉】三種快速排序演算法以及快速排序優化

一.  快速排序的基本思想 快速排序使用分治的思想,通過一趟排序將待排序列分割成兩部分,其中一部分記錄的關鍵字均比另一部分記錄的關鍵字小。之後分別對這兩部分記錄繼續進行排序,以達到整個序列有序的目的。 二.  快速排序的三個步驟 1) 選擇基準:在待排序列中,按照某種方式挑出一個元素,作為 “基準”(p

快速排序演算法思想實現

快速排序演算法是對氣泡排序演算法的一種改進,它的核心思想就是選取一個基準元素(通常已需要排序的陣列第一個數),然後通過一趟排序將比基準數大的放在右邊,比基準數小的放在左邊,接著對劃分好的兩個陣列再進行上述的排序。 例如對陣列5,4,1,7,3,9,21,-1進

排序演算法快速排序原理Java實現

1、基本思想: 快速排序是我們之前學習的氣泡排序的升級,他們都屬於交換類排序,都是採用不斷的比較和移動來實現排序的。快速排序是一種非常高效的排序演算法,它的實現,增大了記錄的比較和移動的距離,將關鍵字較大的記錄從前面直接移動到後面,關鍵字較小的記錄從後面直接移

快速排序演算法原理java遞迴實現

快速排序 對氣泡排序的一種改進,若初始記錄序列按關鍵字有序或基本有序,蛻化為氣泡排序。使用的是遞迴原理,在所有同數量級O(n longn) 的排序方法中,其平均效能最好。就平均時間而言,是目前被認為最好的一種內部排序方法基本思想是:通過一躺排序將要排序的資料分割成獨立的兩部

三種快速排序演算法以及快速排序優化

一.  快速排序的基本思想 快速排序使用分治的思想,通過一趟排序將待排序列分割成兩部分,其中一部分記錄的關鍵字均比另一部分記錄的關鍵字小。之後分別對這兩部分記錄繼續進行排序,以達到整個序列有序的目的。 二.  快速排序的三個步驟 1) 選擇基準:在待排序列中,按照某

冒泡演算法優化

原版冒泡 private static void sort(int array[]) { int tmp = 0; for(int i = 0; i < array.length; i++) { for(int j = 0; j < arra

Java快速排序演算法的實現

高快省的排序演算法 有沒有既不浪費空間又可以快一點的排序演算法呢?那就是“快速排序”啦!光聽這個名字是不是就覺得很高階呢。 假設我們現在對“6  1  2  7  9  3  4  5 10  8”這

氣泡排序優化

【7】在沒有資料交換的時候,提前退出氣泡排序。 氣泡排序:只操作相鄰的兩個資料。空間複雜度O(1),原地排序演算法。相鄰兩個元素大小相等時不做交換,是穩定的排序演算法。 最好時只進行一次冒泡操作,最好時間複雜度O(n),最壞時需進行n次冒泡操作,為O(n2)。平均時間複雜度是O(n2

C# 遞迴式快速排序演算法

1 static void Main(string[] args) 2 { 3 4 Console.WriteLine("************快速排序*****************"); 5 int[] lis

C++拾取——使用stl標準庫實現排序演算法評測

        今天看了一篇文章,講各種語言的優勢和劣勢。其中一個觀點:haskell非常適合寫演算法,因為使用者不用去關心具體的計算機實現,而只要關注於操作語義。這讓它在專心研究演算法的人中非常受歡迎。所以很多時候,語言的爭論沒有太多的意義,有意義的是它

氣泡排序、選擇排序、插入排序快速排序演算法耗時測試

import java.util.*; public class Test1 { public static void main(String[] args) throws Exception{ int[] arr1=new int[20000]; for(int i=0;i&l

#006# 快速排序 × 演算法導論(第三版)練習 7.1-1 ~ 7.1-4

快排採用經典的分治思想,具體如下↓ 分解:快排的核心步驟,其結果是陣列被分成以某個數為基準的左右兩個子陣列(可能為空),其中左邊的數都小於該基準數,右邊的數都大於該基準數。詳細步驟包括計算基準數下標,以及移動陣列內元素。 解決:通過遞迴呼叫快速排序,對兩個子陣列進行排序。 合併:因為是原址排序,快速排序

最常用的排序快速排序演算法

快速排序(QuickSort)是一種很高效的排序演算法,但實際操作過程中不容易寫出十分正確具有健壯性的程式碼,所以我想講清這個問題,也能使自己理解更加深刻 演算法思想 通過一趟排序將要排序的資料分割成獨立的兩部分,其中一部分的所有資料都比另外一部分的所有資料都要小,然後再按此