1. 程式人生 > 其它 >JS實現快速排序演算法

JS實現快速排序演算法

思想

快速排序的基本思想是選擇陣列中的一個元素作為關鍵字,通過一趟排序,把待排序的陣列分成兩個部分,其中左邊的部分比所有關鍵字小,右邊的部分比所有關鍵字大。然後再分別對左右兩邊的資料作此重複操作,直到所有元素都有序,就得到了一個完全有序的陣列。

來看一個例子,以陣列[4, 5, 2, 7, 3, 1, 6, 8]為例,我們選中陣列最左邊的元素為關鍵字pivot

第一步從右側開始,往左移動右指標,遇到8,6,都比4大,直到遇到1,比4小,故把1移動到最左邊。右指標保持不動,開始移動左指標。

移動左指標,發現5比關鍵字pivot 4大,所以把5移動到剛才記錄的右指標的位置,相當於把比pivot大的值都移動到右側。然後開始移動右指標。

移動右指標,發現3比pivot小,故把3移動到剛才左指標記錄的位置,開始移動左指標。

移動左指標,2比pivot小,再移動,發現7,7比pivot大,故把7放到右指標記錄的位置,再次開始移動右指標。

移動右指標,發現兩個指標重疊了,將pivot的值插入指標位置(相當於找到了pivot在排序完成後所在的確切位置)。此次排序結束。

一趟排序結束後,將重疊的指標位置記錄下來,分別對左右兩側的子陣列繼續上面的操作,直到分割成單個元素的陣列。所有操作完成之後,整個陣列也就變成有序陣列了。

動態圖如下,動態圖使用20個元素的無序陣列來演示。其中灰色背景為當前正在排序的子陣列,橙色為當前pivot,為方便演示,使用交換元素的方式體現指標位置。

js實現

程式碼如下:

const quickSort = (array)=>{
  quick(array, 0, array.length - 1)
}

const quick = (array, left, right)=>{
  if(left < right){
    let index = getIndex(array, left, right);
    quick(array, left, index-1)
    quick(array, index+1, right)
  }
}

const getIndex = (array, leftPoint, rightPoint)=>{
  let pivot = array[leftPoint];
  while(leftPoint < rightPoint){
    while(leftPoint < rightPoint && array[rightPoint] >= pivot) {
      rightPoint--;
    }
    array[leftPoint] = array[rightPoint]
    // swap(array, leftPoint, rightPoint) 			//使用swap,則與動態圖演示效果完全一致
    while(leftPoint < rightPoint && array[leftPoint] <= pivot) {
      leftPoint++;
    }
    array[rightPoint] = array[leftPoint]
    // swap(array, leftPoint, rightPoint)
  }
  array[leftPoint] = pivot
  return leftPoint;
}

const swap = (array, index1, index2)=>{
  var
aux = array[index1]; array.splice(index1, 1, array[index2]) array.splice(index2, 1, aux) } const createNonSortedArray = (size)=>{ var array = new Array(); for (var i = size; i > 0; i--) { //array.push(parseInt(Math.random()*100)); array.push(i*(100/size)); array.sort(function() { return (0.5-Math.random()); }); } return array; } var arr = createNonSortedArray(20); quickSort(arr) console.log(arr) //[5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100]

https://www.98891.com/article-93-1.html

時間複雜度

快速排序很明顯用了分治的思想,關鍵在於選擇的pivot,如果每次都能把資料平分成兩半,這樣遞迴樹的深度就是logN,這樣快排的時間複雜度為O(NlogN)。
而如果每次pivot把陣列分成一部分空,一部分為所有資料,那麼這時遞迴樹的深度就是n-1,這樣時間複雜度就變成了O(N^2)。

根據以上的時間複雜度分析,我們發現如果一個數據完全有序,那麼使用咱們上面的快速排序演算法就是最差的情況,所以怎麼選擇pivot就成了優化快速排序的重點了,如果繼續使用上面的演算法,那麼我們可以隨機選擇pivot來代替陣列首元素作為pivot的方式。