javascript 快速排序

概述

快排就是找一个基数用来比较
把比他大的放他前面,比他小的放他后面
然后把前后两部分重复此方法排序

通俗易懂版本

let list = [2, 3, 1, 9, 5, 6, 4, 7, 8];

let quick =  function(arr) {
    if (arr.length < 1) {
        return arr;
    }
    let base = arr[0], left = [], right = [];
    for (let i = 1; i < arr.length; i++) {
        if (arr[i] < base) {
            left.push(arr[i])
        } else {
            right.push(arr[i])
        }
    }

    return arguments.callee(left).concat(base, quick(right))
}

let result = quick(list);
console.log(result)

这个方法比较简单,直接创建数组,把比基数小的放前面数组,大的放后面数组。然后利用数组合并就是排序后的数组。但是重复创建了很多数组对象,加上递归的原因,这里对性能是一种严重的浪费。

抽象版本

let quickSort = function(arr, startIndex, endIndex) {
    if (startIndex > endIndex) {
        return;
    }

    let left = startIndex, right = endIndex, base = list[startIndex];

    while (left !== right) {
        while (right > left && arr[right] >= base) {
            right--;
        }
        while (left < right && arr[left] <= base) {
            left++;
        }
        if (left < right) {
            let temp = arr[left];
            arr[left] = arr[right];
            arr[right] = temp;
        }
    }

    arr[startIndex] = arr[right];
    arr[right] = base;

    arguments.callee(arr, startIndex, left - 1);
    arguments.callee(arr, left + 1, endIndex)
}

quickSort(list, 0, list.length - 1);

console.log(list)
  • 这里就不是利用创建数组归类的方式了,而是直接修改原数组,避免了不必要的创建数组对象。缺点是看起来不是那么明朗。
  • 首先缺点一个用来比较的基数(不一定是第一个数)
  • 从数组最后向前找比基数小的数,找到一个就停下,此时right指向右边第一个比基数小的数。
  • 从数组左边向后找比基数大的数,找到一个就停下,此时left指向左边第一个比基数大的数。
  • 互换这两个数,这就保证了基数两边,左边是小的,右边是大的。
  • rightleft碰头时,停止。因为此时left遍历过的都是比基数小的,right遍历过的都是比基数大的,没必要在找下去。
  • 能让right指针停下来的数肯定是比基数小的数,因为这里基数是第一个,所以基数要与比它小的数换位置。
  • 注:left停下的时候指向的是大于基数的数,要这个数没用,因为基数已经在第一个了,left指向的数肯定在它后面,已经是正确的情况。如果我们取得基数是中间的某个值,这时候就得判断指针位置和数值大小再确定换不换位置。由于外层循环结束时right位置使我们需要的位置,所以应该先从右往左开始找小的。如果先由左往右,left指向一个比基数大的数停下了,这时候right也与left相遇了,但这时指向的数是比基数大的数,显然不是我们需要的。先从右开始就不一样了,right锁定的是比基数小的,left撞上right时指向的数就是比基数小的数。
  • 换一种说法:先从右找的原因是要找一个比基数小的跟基数换位,实现小的在基数前面。但是这样不能保证基数前面都比他小。所以还需要从前面找找比基数大的,找到了就和已经找到的小的数互换,找不到就是rightleft相遇,循环结束,将基数与right指向的数换位。
  • 最后把基数两边的数重复上面步骤。

猜你喜欢

转载自www.cnblogs.com/wayshon/p/9275013.html
今日推荐