算法入門(二)快速排序及優化詳解

一、快速排序基礎

  快速排序也是一種較爲基礎的排序算法,其效率比上篇文章介紹的冒泡排序算法有大幅提升。因爲使用冒泡排序時,一趟只能選出一個最值,有n個元素最多就要執行n - 1趟比較。而使用快速排序時,一次可以將所有元素按大小分成兩堆,也就是平均情況下需要logn輪就可以完成排序。
  快速排序的思想是:每趟排序時選出一個基準值,然後將所有元素與該基準值比較,並按大小分成左右兩堆,然後遞歸執行該過程,直到所有元素都完成排序。
  快速排序的步驟如下:
   1>先從數列中取出一個數作爲基準數。
   2>分區過程,將比這個數大的數全放到它的右邊,小於或等於它的數全放到它的左邊。
   3>再對左右區間重複第二步,直到各區間只有一個數。

1.1 排序過程圖示

  假如有[4,7,2,8,1]五個元素,下面就以常見的“挖坑法”來演示一次快速排序的過程:
  首先選定基準元素key,並記住這個位置index,這個位置相當於一個“”。並且設置兩個指針left和right,指向數列的最左和最右兩個元素:
      
  接下來,從right指針開始,把指針所指向的元素和基準元素做比較。如果比key大,則right指針向左移動;如果比key小,則把right所指向的元素填入坑中。在當前數組元素中,1<4,所以把1填入基準元素所在位置,也就是坑的位置。這時候,元素1本來所在的位置成爲了新的坑。同時,left向右移動一位:
      
  接下來,我們切換到left指針進行比較。如果left指向的元素小於key,則left指針向右移動;如果元素大於key,則把left指向的元素填入坑中。在當前數列中,7>4,所以把7填入index的位置。這時候元素7本來的位置成爲了新的坑。同時,right向左移動一位。
      
  繼續上面的過程,8>4,元素位置不變,right左移:
      
  2<4,用2來填坑,left右移,切換到left:
      
  當left和right指針重合時,把之前的key元素,也就是4放到index的位置。此時數列左邊的元素都小於4,數列右邊的元素都大於4,這一輪交換終告結束:
      

1.2 快速排序實現

  用代碼來實現上述過程,示例如下:

	static void quickSort(int[] arr, int startIndex, int endIndex) {
		/*當startIndex大於等於endIndex時,不再遞歸*/
		if (startIndex >= endIndex) {
		    return;
		}
		/*得到基準元素位置*/
		int keyIndex = divide(arr, startIndex, endIndex);
		/*遞歸處理基準的左右兩部分*/
		quickSort(arr, startIndex, keyIndex - 1);
		quickSort(arr, keyIndex + 1, endIndex);
    }
	
	static int divide(int[] arr, int startIndex, int endIndex) {
		/*取第一個位置的元素作爲基準元素*/
		int key = arr[startIndex];
		int left = startIndex;
		int right = endIndex;
		/*坑的位置,初始等於key的位置*/
		int index = startIndex;
		
		/*當right大於等於left時,執行循環*/
		while (right >= left){
		   /*right指針從右向左進行比較*/
		   while (right >= left) {
		      if (arr[right] < key) {
		    	  /*最右邊的元素覆蓋原來坑中的值*/
		          arr[left] = arr[right];
		          /*坑的位置改變,變成最右邊元素對應的索引*/
		          index = right;
		          /*left索引右移,因爲原來的值已被right索引的值所覆蓋*/
	              left++;
		          break;
		      }
		      /*最右邊的元素參與比較,無論是否參與與坑中元素的交換,都左移,不再參與下一輪的比較*/
		      right--;
		   }
		   
		   /*left指針從左向右進行比較*/
		   while (right >= left) {
		      if (arr[left] > key) {
		         arr[right] = arr[left];
		         index = left;
		         right--;
		         break;
		      }
		      left++;
		   }
		}
		
		/*將基準元素放在index位置,也就是大小元素放在其前後的中間位置*/
		arr[index] = key;
		return index;
	}

二、快速排序優化

2.1 三數取中

  該方法指的是選取基準值時,不再取固定位置(如第一個元素、最後一個元素)的值,因爲這種固定取值的方式在面對隨機輸入的數組時,效率是非常高的。但是一旦輸入數據是有序的,使用固定位置取值,效率就會非常低。因此此時引入了三數取中,即在數組中隨機選出三個元素,然後取三者的中間值做爲基準值。

2.2 插入排序

  當待排序序列的長度分割到一定大小(如 < 10)後,使用插入排序。

2.3 相等元素聚集

  在一次分割結束後,可以把與Key相等的元素聚在一起,繼續下次分割時,不用再對與key相等元素分割。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章