常用的几种排序有哪些?快来看看吧

1,095 阅读1分钟

 本文正在参加「金石计划 . 瓜分6万现金大奖」 

数据结构:数据的存储方式,算法:同一问题的不同解决方法!

1. 冒泡

const arr = [5, 4, 3, 1, 2]

for (let i = 0; i < arr.length - 1; i++) {
    let flag = true
    for (let j = 0; j < arr.length - 1 - i; j++) {
        if (arr[j] > arr[j + 1]) {
            flag = false
            ;[arr[j], arr[j + 1]] = [arr[j + 1], arr[j]]
        }
    }
    if (flag) break // 代表未曾进去过,说明已经排好了
    console.log('次数测试')
}

console.log(arr)

1. 洗牌

原理:遍历数组元素,将当前元素与以后随机位置的元素进行交换!

const arr = [9, 1, 10, 2, 7, 0, 4, 5, 6, 3, 8]
const shuffle = (arr) => {
    let i = arr.length
    while (i) {
        const j = Math.floor(Math.random() * i--)
        ;[arr[j], arr[i]] = [arr[i], arr[j]]
    }
}

shuffle(arr)
console.log(arr)

2. 选择

每次找到最大或最小的索引与当前外层索引交换位置!与冒泡不同的是它不是每比较就交换,而是一轮比较完毕再交换!

const arr = [3, 5, 4, 1, 2]

for (let i = 0; i < arr.length; i++) {
    let min = i // 假设最小索引

    // 检查是否还有更小的索引
    for (j = i + 1; j < arr.length; j++) {
        // 这里必须是 arr[min],而不能是 arr[i],因为 min 是会变化的,i 是不会变化的
        if (arr[j] < arr[min]) {
            min = j
        }
    }
    // 假设失败,则交换位置
    if (min !== i) {
        ;[arr[i], arr[min]] = [arr[min], arr[i]]
    }
}

console.log(arr)

3. 快排

找中间数,比中间数小的放左数组,大的放右数组,递归 return fn(leftArr).concat(cenValue, fn(rightArr));

const arr = [5, 3, 4, 1, 2]

function fn(arr) {
    // #1 条件
    if (arr.length <= 1) return arr

    // #2 中数
    // 从 start 开始,删除 1 个,返回的是一个数组,影响原数组
    let cenValue = arr.splice(Math.floor(arr.length / 2), 1)[0]

    // #3 和中数比较
    let leftArr = []
    let rightArr = []
    for (let i = 0; i < arr.length; i++) {
        if (arr[i] < cenValue) {
            leftArr.push(arr[i])
        } else {
            rightArr.push(arr[i])
        }
    }

    // #4 返回
    return fn(leftArr).concat(cenValue, fn(rightArr))
}

console.log(fn(arr))

4. 归并

先拆分再比较再合并

image.png

    const arr = [38, 27, 43, 3, 9, 82, 10]

    const marge = (before = [], after = []) => {
        console.log(before, after, 'start')
        const temp = []
        // 当两个数组都有元素时候才进行循环比较 循环移除 标记最小值
        while (before.length && after.length) {
            // 取出首位
            const [m] = before
            const [n] = after
            // 首位做比较 取最小值临时存储 且将最小值从源数组中移除
            temp.push(m > n ? after.shift() : before.shift())
        }
        console.log(before, after, 'end', temp)
        // 将其余位放到最小位后面(合并)
        return temp.concat(before).concat(after)
    }


    const sort = (arr = []) => {
        if (!Array.isArray(arr)) throw new Error('arg is not an Array')
        if (arr.length <= 1) return arr

        // 递归二分数组 直到数组中的元素个数小于等于1 (拆分)
        const splitIndex = Math.floor(arr.length / 2)
        const before = arr.slice(0, splitIndex)
        const after = arr.slice(splitIndex)
        return marge(sort(before), sort(after))
    }

    console.log(sort(arr))