算法之八大排序算法

81 阅读2分钟

1.冒泡排序

function sort(arr) {
    let len = arr.length
    if (len < 2) {
        return
    }
    for (let i = 0; i < len; i++) {
        for (let j = 0; j < len - i - 1; j++) {
            if (arr[j] > arr[j + 1]) {
                let temp = arr[j]
                arr[j] = arr[j + 1]
                arr[j + 1] = temp
            }
        }
    }
}
let arr = [4, 3, 7, 5, 10, 9, 1, 6, 8, 2]
sort(arr)
console.log(arr)

2.快速排序

function fastSort(arr, low, high) {
    if (arr == null || arr.length == 0 || arr.length == 1) {
        return arr
    }
    if (low >= high) {
        return
    }
    let left = low
    let right = high
    let pvior = arr[left]//坑1(选择的基准)
    while (left < right) {
        while (left < right && arr[right] >= pvior) {
            right--
        }
        arr[left] = arr[right]//坑2,注意对换位置
        while (left < right && arr[left] <= pvior) {
            left++
        }
        arr[right] = arr[left]//坑3,注意对换位置
    }
    arr[left] = pvior//补坑位3
    fastSort(arr, low, left - 1)
    fastSort(arr, left + 1, high)//left为坑位(基准)
}

let arr = [4, 3, 7, 5, 10, 9, 1, 6, 8, 2]
fastSort(arr, 0, arr.length - 1)
console.log(arr)

3.直接插入排序

function innerSort(arr) {
    if (arr == null || arr.length == 1) {
        return arr
    }
    for (let i = 1; i < arr.length; i++) {
        let j = i - 1
        let temp = arr[i]
        while (j >= 0 && arr[j] > temp) {
            arr[j + 1] = arr[j]
            j--
        }
        arr[j + 1] = temp//此时j位元素小于arr[i],则将其插入在j后面
    }
}
let arr = [4, 3, 7, 5, 10, 9, 1, 6, 8, 2]
innerSort(arr)
console.log(arr)

4.希尔排序

function xierSort(arr = []) {
    let gap = Math.floor(arr.length / 2)//组长
    for (; gap > 0; gap = Math.floor(gap / 2)) {//排序趟数,一定要取整,否则永远运行不出
        for (let i = 0; i + gap < arr.length; i++) {//每一组
            for (let j = 0; j + gap < arr.length; j += gap) {//组内排序
                if (arr[j] > arr[j + gap]) {
                    let temp = arr[j]
                    arr[j] = arr[j + gap]
                    arr[j + gap] = temp
                }
            }
        }
    }
    return arr
}

let arr = [4, 3, 7, 5, 10, 9, 1, 6, 8, 2]
arr = xierSort(arr)
console.log(arr)

5.选择排序

function selectSort(arr = []) {
    let len = arr.length
    if (arr == null || len === 0) {
        return
    }
    for (let i = 0; i < len - 1; i++) {
        let min = i
        for (let j = i + 1; j < len; j++) {//选出之后待排序中值最小的位置
            if (arr[j] < arr[min]) {
                min = j
            }
        }
        if (min != i) {
            let temp = arr[i]
            arr[i] = arr[min]
            arr[min] = temp
        }
    }
}
let arr = [4, 3, 7, 5, 10, 9, 1, 6, 8, 2]
selectSort(arr)
console.log(arr)

6.归并排序

function mergeSort(arr = []) {
    //自上而下递归
    const len = arr.length;
    if (len < 2) {
        return arr;
    }
    let middle = Math.floor(len / 2),
        left = arr.slice(0, middle),
        right = arr.slice(middle); // 拆分
    return merge(mergeSort(left), mergeSort(right));
};

function merge(left, right){
    const result = [];
    while (left.length && right.length) {
        // 注意: 判断的条件是如果只是小于,那么排序将不稳定.
        if (left[0] <= right[0]) {
            result.push(left.shift());
        } else {
            result.push(right.shift());
        }
    }
    while (left.length) result.push(left.shift());
    while (right.length) result.push(right.shift());
    return result;
};
// 测试
const arr = [4, 3, 7, 5, 10, 9, 1, 6, 8, 2];
console.log(mergeSort(arr));

7.堆排序

function heapSort(array) {
    // 初始化大顶堆,从第一个非叶子结点开始
    for (let i = Math.floor(array.length / 2 - 1); i >= 0; i--) {
        heap(array, i, array.length);
    }
    //构造堆
    for (let i = Math.floor(array.length - 1); i > 0; i--) {
        // 根节点与最后一个节点交换
        swap(array, 0, i);
        // 从根节点开始调整,并且最后一个结点已经为当前最大值,不需要再参与比较,所以第三个参数为 i,即比较到最后一个结点前一个即可
        heap(array, 0, i);
    }
    return array;
};

// 交换两个节点
const swap = (array, i, j) => {
    let temp = array[i];
    array[i] = array[j];
    array[j] = temp;
};

  • 将 i 结点以下的堆整理为大顶堆,注意这一步实现的基础实际上是:假设结点 i 以下的子堆已经是一个大顶堆,heap 函数实现的功能是实际上是:找到结点 i 在包括结点 i 的堆中的正确位置。
  • 后面将写一个 for 循环,从第一个非叶子结点开始,对每一个非叶子结点都执行 heap 操作,所以就满足了结点 i 以下的子堆已经是一大顶堆
const heap = (array, i, length) => {
    let temp = array[i]; // 当前父节点
    // j < length 的目的是对结点 i 以下的结点全部做顺序调整
    for (let j = 2 * i + 1; j < length; j = 2 * j + 1) {
        temp = array[i]; // 相当于找到 array[i] 应处于的位置
        if (j + 1 < length && array[j] < array[j + 1]) {
            j++; //两个孩子中较大的一个与父节点比较
        }
        if (temp < array[j]) {
            swap(array, i, j); //父节点小于子节点:交换
            i = j; // 交换后,temp 的下标变为 j
        } else {
            break;
        }
    }
};
// 测试
const arr = [4, 3, 7, 5, 10, 9, 1, 6, 8, 2];
console.log(heapSort(arr));