通过JS实现快速排序

快速排序基本思路:

  • 确立一个基准两个哨兵,两个哨兵分别从前后往中间寻找。
  • 通过和基准比较找到需要改变位置的数,使基准数左侧的子数组都比基准数小,右侧的子数组都比基准数大。
  • 然后两侧部分子数组分别按此方法进行排序。
  • 以此类推,最后直到每个子数组的长度为1,排序结束。

以下是快速排序的两种方式:

  1. 第一种常规的快速排序(效率更高)
    步骤如下:

    1. 取第一个数 15 为基准,再分别以数组第一位和最后一位确立两个哨兵 i 和 j。此时 i = 0,j = 9,先 j-- 从后往前找小于基准的数,然后 i++ 从前往后找大于基准的数。
      [15,3,83,10,18,99,4,63,28,47]
    2. 此时 i = 2,j = 6,83 > 15,4 < 15, arr[2] 与 arr[6] 交换。然后继续上一步的做法。
      [15,3,4,10,18,99,83,63,28,47]
    3. 当 j = 3 时,10 < 15,j-- 找到小于基准的数,i++ 只能向右走到 i = 3,两哨兵相遇,则基准数和 arr[3] 交换位置,第一趟排序完成。
      [10,3,4,15,18,99,83,63,28,47]
    4. 此时以 arr[3] = 15 为界分为左右两个子数组。左边的子数组都比15小,右边的子数组都比15大。
    5. 接着在左右两个子数组中重复上面的排序过程,直到每个子数组的长度为1,排序结束!
    6. 注意代码中的注释,一定要哨兵 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);
    
  2. 第二种快速排序(效率低于第一种)
    步骤如下:

    1. 取第一个数 15 为基准,再分别以数组第一位和最后一位确立两个哨兵 i 和 j。此时 i = 0, j = 9,i 先不变,j-- 从后往前找小于基准的数。
      [15,3,83,10,18,99,4,63,28,47]
    2. i = 0, j = 6 时,4 < 15,arr[0] 换成 4。接着调换顺序从前往后找比基准大的数(i++,j 不变)。
      [4,3,83,10,18,99,4,63,28,47]
    3. i = 2 ,j = 6 时 ,83 > 15,arr[6] 换成 83。接着调换顺序从后往前找比基准小的数。
      [4,3,83,10,18,99,83,63,28,47]
    4. i = 2,j = 3 时,10 < 15,arr[2] 换成 10。反向查找。
      [4,3,10,10,18,99,83,63,28,47]
    5. 当i = j = 3 时,两哨兵相遇,则把 arr[3] 换成基准数15,第一趟排序完成。
      [4,3,10,15,18,99,83,63,28,47]
    6. 此时以 arr[3] = 15 为界分为左右两个子数组。左边的子数组都比15小,右边的子数组都比15大。
    7. 接着在左右两个子数组中重复上面的排序过程,直到每个子数组的长度为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);
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值