八大排序-快速排序(搞定面試之手寫快排)

概要

快速排序由C. A. R. Hoare在1960年提出,是八大排序算法中最經常使用的經典排序算法之一。其普遍應用的主要緣由是高效,核心算法思想是分而治之。快速排序常常會被做爲面試題進行考察,一般的考察思路是快排思想、編碼實踐之手寫快排以及進一步對快排的優化。事實上在Java標準庫中Arrays類的sort方法裏源碼也正是使用了優化後的快速排序(具體源碼以及優化分析後續會推文講解),掌握快排算法對於數據結構與算法入門極爲重要。java

原理

快速排序的核心思想是分治:選擇數組中某個數做爲基數,經過一趟排序將要排序的數據分割成獨立的兩部分,其中一部分的全部數都比基數小,另一部分的全部數都都比基數大,而後再按此方法對這兩部分數據分別進行快速排序,循環遞歸,最終使整個數組變成有序。面試

基數選擇

因爲快速排序須要選定一個基數進行劃分排序,關於基數選擇有不少方式,而基數選擇直接關係到快排的效率。事實上,選取基準元素應該遵循平衡子問題的原則:即便得劃分後的兩個子序列的長度儘可能相同本篇以待排序數組首元素做爲基數進行說明。本篇以最多見的使用數組首元素做爲基數進行快速排序原理說明。算法

一趟排序

以數組int n[] = { 6, 5, 2, 7, 3, 9, 8, 4, 10, 1 }爲例: 數組

以第一個數字6做爲基數,使用雙指針i,j進行雙向遍歷:

  • 一、i從左往右尋找第一位大於基數(6)的數字,j從右往左尋找第一位小於基數(6)的數字;bash

  • 二、找到後將兩個數字進行交換。繼續循環交換直到i>=j結束循環;數據結構

  • 三、最終指針i=j,此時交換基數和i(j)指向的數字便可將數組劃分爲小於基數(6)/基數(6)/大於基數(6)的三部分,即完成一趟快排;學習

僞代碼

見編碼註釋優化

編碼實踐

public class Test {

	public static void main(String[] args) {
		int n[] = { 6, 5, 2, 7, 3, 9, 8, 4, 10, 1 };
		quicksort(n);
		System.out.print("快排結果:");
		for (int m : n) {
			System.out.print(m + " ");
		}
	}

	public static void quicksort(int n[]) {
		sort(n, 0, n.length - 1);
	}

	public static void sort(int n[], int l, int r) {
		if (l < r) {
			// 一趟快排,並返回交換後基數的下標
			int index = patition(n, l, r);
			// 遞歸排序基數左邊的數組
			sort(n, l, index - 1);
			// 遞歸排序基數右邊的數組
			sort(n, index + 1, r);
		}

	}

	public static int patition(int n[], int l, int r) {
		// p爲基數,即待排序數組的第一個數
		int p = n[l];
		int i = l;
		int j = r;
		while (i < j) {
			// 從右往左找第一個小於基數的數
			while (n[j] >= p && i < j) {
				j--;
			}
			// 從左往右找第一個大於基數的數
			while (n[i] <= p && i < j) {
				i++;
			}
			// 找到後交換兩個數
			swap(n, i, j);
		}
		// 使劃分好的數分佈在基數兩側
		swap(n, l, i);
		return i;
	}

	private static void swap(int n[], int i, int j) {
		int temp = n[i];
		n[i] = n[j];
		n[j] = temp;
	}

}
複製代碼
  • 結果
快排結果:1 2 3 4 5 6 7 8 9 10 
複製代碼

結語

本篇以最簡單的形式講解八大排序之一的快速排序的核心思想和具體實現,快速排序是相對其餘排序出現頻率最高的排序算法。關於8大排序算法,建議的0基礎學習路線是先理解算法思想再進行編碼實踐。最後,若是以爲本篇對你有所啓發或幫助,不妨關注一波0.0ui

Alt

關注訂閱號 獲取更多幹貨~
相關文章
相關標籤/搜索