快速排序基本思路:
- 确立一个基准两个哨兵,两个哨兵分别从前后往中间寻找。
- 通过和基准比较找到需要改变位置的数,使基准数左侧的子数组都比基准数小,右侧的子数组都比基准数大。
- 然后两侧部分子数组分别按此方法进行排序。
- 以此类推,最后直到每个子数组的长度为1,排序结束。
以下是快速排序的两种方式:
-
第一种常规的快速排序(效率更高)
步骤如下:- 取第一个数 15 为基准,再分别以数组第一位和最后一位确立两个哨兵 i 和 j。此时 i = 0,j = 9,先 j-- 从后往前找小于基准的数,然后 i++ 从前往后找大于基准的数。
[15,3,83,10,18,99,4,63,28,47] - 此时 i = 2,j = 6,83 > 15,4 < 15, arr[2] 与 arr[6] 交换。然后继续上一步的做法。
[15,3,4,10,18,99,83,63,28,47] - 当 j = 3 时,10 < 15,j-- 找到小于基准的数,i++ 只能向右走到 i = 3,两哨兵相遇,则基准数和 arr[3] 交换位置,第一趟排序完成。
[10,3,4,15,18,99,83,63,28,47] - 此时以 arr[3] = 15 为界分为左右两个子数组。左边的子数组都比15小,右边的子数组都比15大。
- 接着在左右两个子数组中重复上面的排序过程,直到每个子数组的长度为1,排序结束!
- 注意代码中的注释,一定要哨兵 j 先动!
function quickSort(arr,from,to){ var i = from; var j = to; var pivot = arr[from]; if(from >= to){ return; } while(i < j){ while(arr[j] >= pivot && i < j){ j--; /*一定要让哨兵 j 先动。 原因就是哨兵 j 停留的位置一定比基准数小, 如上述步骤 3,如果让 i 先走, i 和 j 就会在比基准数大的位置相遇, 这时交换基准数和相遇位置就会出错。*/ } while(arr[i] <= pivot && i < j){ i++; } if(i < j){ var temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; } } arr[from] = arr[i] arr[i] = pivot; quickSort(arr,from,i-1); quickSort(arr,i+1,to); return arr; } var arr = [15,3,83,10,18,99,4,63,28,47]; quickSort(arr,0,arr.length-1);
- 取第一个数 15 为基准,再分别以数组第一位和最后一位确立两个哨兵 i 和 j。此时 i = 0,j = 9,先 j-- 从后往前找小于基准的数,然后 i++ 从前往后找大于基准的数。
-
第二种快速排序(效率低于第一种)
步骤如下:- 取第一个数 15 为基准,再分别以数组第一位和最后一位确立两个哨兵 i 和 j。此时 i = 0, j = 9,i 先不变,j-- 从后往前找小于基准的数。
[15,3,83,10,18,99,4,63,28,47] - i = 0, j = 6 时,4 < 15,arr[0] 换成 4。接着调换顺序从前往后找比基准大的数(i++,j 不变)。
[4,3,83,10,18,99,4,63,28,47] - i = 2 ,j = 6 时 ,83 > 15,arr[6] 换成 83。接着调换顺序从后往前找比基准小的数。
[4,3,83,10,18,99,83,63,28,47] - i = 2,j = 3 时,10 < 15,arr[2] 换成 10。反向查找。
[4,3,10,10,18,99,83,63,28,47] - 当i = j = 3 时,两哨兵相遇,则把 arr[3] 换成基准数15,第一趟排序完成。
[4,3,10,15,18,99,83,63,28,47] - 此时以 arr[3] = 15 为界分为左右两个子数组。左边的子数组都比15小,右边的子数组都比15大。
- 接着在左右两个子数组中重复上面的排序过程,直到每个子数组的长度为1,排序结束!
function quickSort(arr, i, j) { if(i < j) { let left = i; let right = j; let pivot = arr[left]; while(i < j) { while(arr[j] >= pivot && i < j) { // 从后往前找比基准小的数 j--; } if(i < j) { arr[i] = arr[j]; } while(arr[i] <= pivot && i < j) { // 从前往后找比基准大的数 i++; } if(i < j) { arr[j] = arr[i]; } } arr[i] = pivot; quickSort(arr, left, i-1); quickSort(arr, i+1, right); return arr; } } var arr=[15,3,83,10,18,99,4,63,28,47]; quickSort(arr, 0 , arr.length-1);
- 取第一个数 15 为基准,再分别以数组第一位和最后一位确立两个哨兵 i 和 j。此时 i = 0, j = 9,i 先不变,j-- 从后往前找小于基准的数。