1. 程式人生 > >基礎算法系列之排序演算法-5. 快速排序

基礎算法系列之排序演算法-5. 快速排序

我們之前學習了氣泡排序演算法,我們知道,在氣泡排序過程中,只對相鄰的兩個元素進行比較,因此每次交換兩個相鄰的元素時只能消除一個逆序。如果能通過兩個(不相鄰)元素的一次交換,消除多個逆序,則會大大加快排序的速度。而這就是本篇文章講述的另一種基本排序演算法——快速排序演算法。

快速排序

 快速排序是通過氣泡排序改進得來的,氣泡排序每次元素的交換隻能消除一個逆序,而快速排序的一次元素交換可以消除多個逆序,從而大大提高排序的效率。

快速排序的演算法思想

 通過一次元素的交換消除多個逆序,以提高排序的效率。

快速排序的實現過程

     在待排序的n個元素中任取一個元素(通常取第一個元素)作為樞軸,記錄它在序列中位置為pivotkey,記錄待排序元素的第一個元素的位置為low,最後一個元素的位置為high。通過一次排序之後,比樞軸小的元素全部排列在起左側,比樞軸大的元素全部在其右側,然後通過樞軸作為分界線,將原數列一分為二(一個子列從low到pivotkey-1,另一個子列從pivotkey+1到high),對兩個新生成的子列重複上述過程,直到所有新生成的子列只有一個元素,則排序完成。

   是不是有點抽象,有點難理解,沒事~我們舉個例子,來演示一下這個過程。

   例如:我們要對數列[49,38,65,97,76,13,27,49]進行快速排序。則記錄low與pivotkey為0(陣列的第一元素位置),high為7(陣列的最後一個元素位置),我們從數列最"右"側(a[high])開始,逐個與樞軸處的值(即a[pivotkey],在這個例子中為49,已用紅色標明)進行比較,若元素的值大於等於樞軸值(49),則high自減(high--)。直到將第一個比樞軸處值要小的元素與樞軸值交換,則交換之後數列變為[27,38,65,97,76,13,49,49]。在從數列的最"左"側(a[low])開始,逐個(即a[low])與a[pivotkey]比較,若元素值小於等於樞軸值,則low自增(low++)。直到將第一個比a[pivotkey]要大的元素與樞軸值交換,則交換後的數列變為[27,38,49,97,76,13,65,49]。重複上述一右一左的過程,直到low>=high。經過這樣一次排序之後,數列變為了[27,38,13,49,76,97,65,49]。再對新生成的子列[27,38,13],[76,97,65,49]重複上述過程。

   示意圖:

程式碼實現

public static void quickSort(int[] a,int start,int end){
		if( (end - start) <= 0){  //區間長度小於等於1,則排序結束
			return;
		}
		int pivotkey =start;  //定義樞軸
		int low=start;    //定義low,high的位置
		int high=end;
		while(low<high){
		while(low<high && a[high] >=a[pivotkey]){  //從最右側開始,如果a[high]的值>=樞軸的值,則high--
			high--;
		}
		a[high] = (a[high] + a[pivotkey]) - (a[pivotkey] = a[high]);//交換a[high] 與 a[pivotkey]的值
		pivotkey  =high;  //更改樞軸的位置
		while(low<high && a[low] <=a[pivotkey]){ //從最左側開始,如果a[low]的值<=樞軸的值,則low++
			low++;
		}
		a[low] = (a[low] + a[pivotkey]) - (a[pivotkey] = a[low]);  //交換a[low] 與 a[pivotkey]的值
		pivotkey=low;   //更改樞軸的位置
		}
		quickSort(a,start,pivotkey-1);  //對分割成的兩個子表在次快排
		quickSort(a, pivotkey+1, end);
	}

 讓我們來測試一下演算法吧

public static void main(String[] args) {
		int[] a = new int[]{2,8,4,6,13,9,12,6};
		quickSort(a, 0, a.length-1);
		for(int i : a){
			System.out.print(i+"  ");
		}

	}

既然學習了快速排序,老規矩,上題~

HDU 1157  Who's in the Middle

Problem Description

FJ is surveying his herd to find the most average cow. He wants to know how much milk this 'median' cow gives: half of the cows give as much or more than the median; half give as much or less. Given an odd number of cows N (1 <= N < 10,000) and their milk output (1..1,000,000), find the median amount of milk given such that at least half the cows give the same amount of milk or more and at least half give the same or less.

Input

* Line 1: A single integer N * Lines 2..N+1: Each line contains a single integer that is the milk output of one cow.

Output

* Line 1: A single integer that is the median milk output.

Sample Input

5 2 4 1 3 5

Sample Output

3

題意:有N(N為奇數)頭奶牛產奶,求這N頭奶牛產奶的中位數。

分析:可以先奶牛的產奶量進行快速排序,最後找到N/2位置處的數即為中位數

程式碼實現:

public static void main(String[] args) {
		System.out.println("請輸入奶牛的個數(奇數):");
		Scanner input = new Scanner(System.in);
		int n;   // 定義變數n儲存奶牛的數量
		do {    //如果n不能奇數,重新輸入
			n = input.nextInt();
			if (n % 2 != 0) {
				break;
			}
			else{
				System.out.println("輸入不為奇數,請重新輸入:");
			}
		} while (true);
		int[] a = new int[n]; // 每天奶牛的產奶量
		System.out.println("請輸入每頭奶牛的產奶量:");
		for (int i = 0; i < n; i++) {
			a[i] = input.nextInt();
		}
		quickSort(a, 0, a.length - 1); // 進行快排
		System.out.println("中位數:" + a[n / 2]); // 輸出結果
		input.close();
	}

	public static void quickSort(int[] a, int start, int end) {
		if ((end - start) <= 0) { // 區間長度小於等於1,則排序結束
			return;
		}
		int pivotkey = start; // 定義樞軸
		int low = start; // 定義low,high的位置
		int high = end;
		while (low < high) {
			while (low < high && a[high] >= a[pivotkey]) { // 從最右側開始,如果a[high]的值>=樞軸的值,則high--
				high--;
			}
			a[high] = (a[high] + a[pivotkey]) - (a[pivotkey] = a[high]);// 交換a[high]
																		// 與
																		// a[pivotkey]的值
			pivotkey = high; // 更改樞軸的位置
			while (low < high && a[low] <= a[pivotkey]) { // 從最左側開始,如果a[low]的值<=樞軸的值,則low++
				low++;
			}
			a[low] = (a[low] + a[pivotkey]) - (a[pivotkey] = a[low]); // 交換a[low]
																		// 與
																		// a[pivotkey]的值
			pivotkey = low; // 更改樞軸的位置
		}
		quickSort(a, start, pivotkey - 1); // 對分割成的兩個子表在次快排
		quickSort(a, pivotkey + 1, end);
	}

讓我們來測試一下我們的程式碼吧。

總述

 快速排序演算法是一種效率較高的排序演算法,它是在氣泡排序的基礎之上的進行改進得來的。你學會了嗎ヾ(◍°∇°◍)ノ゙

                                        關注我們,免費獲取海量java視訊學習資源