排序和搜索算法学习之并归排序与快速排序

501 阅读3分钟

来了广东就是靓仔!!但是 --- 不学习和咸鱼有什么分别?

此文 是 讲排序算法中的并归排序和快速排序

并归排序

  • 并归排序是应该是第一个被实际应用的排序算法,其复杂度是O(nlogn的次方)。
  • 并归排序是一种分治算法,将原始的数组切分成小数组,直到每个数组只有一个元素,接着再将小数组并归成较大的数组,直到只有一个排序完成的大数组。
  • 👉Tip: Firefox 中的Array.prototype.sort就是使用了并归排序作为实现。
  • 此处沿用上上篇 冒泡排序中的辅助函数。👉 排序和搜索算法学习之冒泡
    // 此处沿用上篇 冒泡中的辅助函数 
    function ArrayList() {
        var array = [];
        this.insert  = function(element) {
            array.push(element);
        } 
        this.toString = function() {
            return array.join();
        }
    }
    
    // 并归算法 也是使用了递归。
    this.mergeSort = function() {
        array = mergeSortRec(array)
    }

    var mergeSortRec = function(array) {
        var length = array.length;
        if (length === 1) {
            return array
        }
        var mid = Math.floor(length / 2);
        var left = array.slice(0, mid);
        var right = array.slice(mid, length);
        const res = merge(mergeSortRec(left), mergeSortRec(right))
        console.log('merge result', res)
        return res
    }

    var merge = function(left, right) {
        console.log('left', left)
        console.log('right', right)
        var result = [];
        var iLeft = 0, iRight = 0;
        while(iLeft < left.length && iRight < right.length) {
            if (left[iLeft] < right[iRight]) {
                result.push(left[iLeft])
                iLeft++
            } else {
                result.push(right[iRight])
                iRight++
            }
        }
        while(iLeft < left.length) {
            result.push(left[iLeft])
            iLeft++
        }
        while(iRight < right.length) {
            result.push(right[iRight])
            iRight++
        }
        return result
    }

测试代码

    function createNotSortedArray(size) {
        var array = new ArrayList();
        for (var i = size; i > 0; i--) {
            array.insert(i)
        }
        return array;
    }

    console.time('array 5') // 10,9,8,7,6,5,4,3,2,1
    var array5 = createNotSortedArray(10);
    console.log(array5.toString());
    array5.mergeSort();
    console.log('sorted', array5.toString());
    console.timeEnd('array 5') // 7.0478515625ms
    
    -> left [10]
    -> right [9]
    -> merge result [9, 10]
    -> left [7]
    -> right [6]
    -> merge result [6, 7]
    -> 8 left [8]
    -> right [6, 7]
    -> merge result [6, 7, 8]
    ->  left [9, 10]
    -> right [6, 7, 8]
    -> merge result [6, 7, 8, 9, 10]
    -> left [5]
    -> right [4]
    -> merge result [4, 5]
    -> left [2]
    -> right [1]
    -> merge result [1, 2]
    -> left [3]
    -> right [1, 2]
    -> merge result [1, 2, 3]
    -> left [4, 5]
    -> right [1, 2, 3]
    -> merge result [1, 2, 3, 4, 5]
    -> left [6, 7, 8, 9, 10]
    -> right [1, 2, 3, 4, 5]
    -> merge result [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    -> sorted 1,2,3,4,5,6,7,8,9,10
    -> array 5: 7.0478515625ms
  • 从测试输出结果可能清楚的看出,并归排序将大数组拆分小数组的过程以及重新并归至一个大数组的过程。在并归中完成排序

快速排序

  • 快速排序应该是最常用的排序算法之一了,其复杂度为O(nlogn的次方),且实验表明,它的性能比其他复杂度为O(nlogn的次方)的排序算法要好。
  • 与并归排序一样,它同样也是采用了分治的方法。
  • (1) 首先选择数组的中间一项作为主元
  • (2) 创建两个指针,左边一个指向数组第一个元素,右边指向数组最后一个元素。移动左边指针直到找到一个比主元大的元素,接着移动右边指针直到找到一个比主元小的元素,然后进行交换,重复这个过程,直到左边指针超过右边指针。这个过程将使得所有比主元小的元素都移动至主元的左边,而比主元大的元素都在主元之后,这一步叫分划。
  • (3) 接着,算法对分划之后的小数组(主元左边的为一小组,右边为一小组),重复之前的两步,直至数组完成排序。

实现

    // 快速排序
    this.quickSort = function() {
        quick(array, 0, array.length - 1)
    }

    var quick = function(array, left, right) {
        var index;
        if (array.length > 1) {
            index = partition(array, left, right)
            if (left > index - 1) {
                quick(array, left, index -1)
            }
            if (index < right) {
                quick(array, index, right)
            }
        }
    }

    var partition = function(array, left, right) {
        var pivot = array[Math.floor((right + left) / 2)]; // 主元
        var i = left;
        var j = right;
        while(i <= j) {
            while(array[i] < pivot) {
                i++
            }
            while(array[j] > pivot) {
                j--;
            }
            if (i <= j) {
                swap(array, i, j);
                i++;
                j--;
            }
        }
        return i
    }
    
    // 交换函数
    var swap = function(array, index1, index2) {
        var aux = array[index1];
        array[index1] = array[index2];
        array[index2] = aux;
        // es6交换的方式 ---增强的对象属性
        // [array[index1], array[index2]] = [array[index2], array[index1]]
    }
  • 👉Tip: Chrome 中的Array.prototype.sort就是使用了快速排序作为实现。

测试

    console.time('array 6')
    var array6 = createNotSortedArray(10);
    console.log(array6.toString());  // 10,9,8,7,6,5,4,3,2,1
    array6.quickSort();
    console.log('sorted', array6.toString());  // sorted 1,2,3,4,5,6,7,8,9,10
    console.timeEnd('array 6') // array 6: 0.328125ms

Noted: Without a purpose, life is depressed.