排序算法

330 阅读4分钟

学习5种排序算法:

  • 1:快速排序
  • 2:归并排序
  • 3:堆排序
  • 4:冒泡排序
  • 5:选择排序

总结

算法 时间复杂度 空间复杂度 稳定 步骤 应用 原地
快速排序 O(nlogn)/最坏 O(n2) 开辟新数组法O(n)/原地 O(logn) 不稳定 分治法,选取基数,将数组分成两部分,递归进行此操作 in-place/out-place
归并排序 O(nlogn) O(n) 稳定 分治法,先将数组分割,然后排序,进而集成在一起 速度仅次于快速排序,一般用于总体无序,但是各子项相对有序的数列 out-place
选择排序 O(n2) O(1) 不稳定 每次遍历找到最小值,放入左侧,依次对未排序的部分重复此操作 不占用额外空间,对空间复杂度要求较高,并且数据规模不大时候可以使用 in-place
冒泡排序 O(n2) O(1) 稳定 比较相邻元素,如果第一个比第二个大,就交换位置,一直到最后,第二遍重复此操作(除了最后一个) 对空间复杂度要求较高,并且数据规模不大时候,需要稳定排序可以使用 in-place
堆排序 建堆O(n),总体O(nlog n) O(1) 不稳定 接住数据结构堆,堆是一个近似完全二叉树的结构,堆具有子节点均比父节点大/小的性质,1:建立大顶堆。2:拿出堆顶元素,将堆末尾元素拿到堆顶3:调整堆,4:重复2,3步 时间复杂度同快速排序、归并排序,特长是使用很少空间,适合相对有序的序列排序 in-place

上面 table 居然还需要滚动。。。给个图吧,方便点

1.归并排序

// 排序 并 合并
function merge (leftArr, rightArr) {
    let result = [];
    while (leftArr.length > 0 && rightArr.length > 0) {
        if(leftArr[0]<=rightArr[0]){
            result.push(leftArr.shift());
        } else {
            result.push(rightArr.shift());
        }
    }
    if(leftArr[0] || rightArr[0]) {
        result.push(leftArr[0] || rightArr[0]);
    }
    return result;
}
// 分割
function mergeSort(arr) {
    // 边界判断
    if (arr.length < 2) {
        return arr;
    }
    // 进行分割,将数组从中间分割成两部分
    const middleIndex = Math.floor(arr.length / 2);
    let left = arr.slice(0, middleIndex);
    let right = arr.slice(middleIndex);
    return merge(mergeSort(left), mergeSort(right));
}

mergeSort([32,12,56,78,76,45,36]);

2.选择排序

// 选择排序
function selectSort(arr){
    for(let j=0; j<arr.length; j++){
        let max = arr[j];
        let maxIndex = j;
        for (let i = j; i < arr.length; i++) {
            if (arr[i] > max) {
                max = arr[i];
                maxIndex = i;
            }
        }
        const temp = arr[j];
        arr[j] = arr[maxIndex];
        arr[maxIndex] = temp;
    }
    return arr;
}
selectSort([32,12,56,78,76,45,36, 45]);

3.冒泡排序

function bubbleSort(arr) {
    for (let i = arr.length - 1; i >= 0; i--) {
        for (let j = 0; j < i + 1; j++) {
            if (arr[j] > arr[j + 1]) {
                let temp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = temp;
            }
        }
    }
    return arr;
}
bubbleSort([32,12,56,78,76,45,36, 45]);

4.快速排序

in-place

要点:最后一个元素作为 pivot, 需要记下分割的 storeIndex,并初始化为-1

// 快速排序  in-place法
function quickSortInPlace(arr, left=0, right= arr.length-1){
    if(left < right){
        let storeIndex = left - 1
        for(let i=left; i<=right; i++){
            // 最后一个元素作为 pivot
            if(arr[i]<=  arr[right]){
                storeIndex++
                let temp = arr[storeIndex]
                arr[storeIndex] = arr[i]
                arr[i] = temp
            }
        }
        quickSortInPlace(arr, left, storeIndex-1)
        quickSortInPlace(arr, storeIndex+1, right)
    }
    return arr
}
let test = [5,6,9,1,4,9,67,4,0];
quickSortInPlace(test)

开辟新数组法

// 快速排序  开辟新数组法
function quickSort(arr) {
    if (arr.length < 2) {
        return arr;
    }
    const pivotIndex = Math.floor(arr.length / 2);
    const pivot = arr.splice(pivotIndex, 1)[0];
    let left = [];
    let right = [];
    arr.forEach(item => {
        if (item < pivot) {
            left.push(item);
        } else {
            right.push(item);
        }
    });
    return quickSort(left).concat(pivot, quickSort(right));
}
let test = [5,6,9,1,4,9,67,4,0];
quickSort(test)

堆排序

利用堆这种数据结构来实现的一种排序算法;堆是一种近似完全二叉树的数据结构,并且具有子节点均大于(或者小于)父节点的性质

堆排序的步骤

  • 1.建立大顶堆
  • 2.堆顶元素放直最后,堆未元素放置堆顶
  • 3.调整堆
  • 4.重复2.3步骤
function heapSort(arr) {
  function sort() {
        // 构建大顶堆
        for (let i = Math.floor(arr.length / 2) - 1; i >= 0; i--) {
            heapify(i, arr.length - 1);
        }
        // 将堆顶元素放直最后,然后重新调整堆
        for (let j = arr.length - 1; j >= 0; j--) {
            // 将堆顶元素放直最后
            swap(0, j);
            // 调整堆,从第一个,调整到最后的 j
            heapify(0, j);
        }
        return arr;
    }
    function swap(i, j) {
        let tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
    }
    function heapify(start, end) {
        let dad = start;
        let leftSon = dad * 2 + 1;
        let rightSon = dad * 2 + 2;
        // 记录最大孩子的 index
        let maxSon = leftSon;
        // 没有子节点,无需调整
        if (leftSon >= end) {
            return;
        }
        // 找到最大孩子
        if (rightSon < end && arr[maxSon] < arr[rightSon]) {
            maxSon = rightSon;
        }
        // 最大孩子与 dad 比大小
        if (arr[maxSon] > arr[dad]) { // 如果孩子大,需要换位置
            swap(maxSon, dad);
            heapify(maxSon, end);
        }
    }
    sort();
}

let a = [3, 5, 3, 0, 8, 6, 1, 5, 8, 6, 2, 4, 9, 4, 7, 0, 1, 8, 9, 7, 3, 1, 2, 5, 9, 7, 4, 0, 2, 6];
heapSort(a);