快速排序1

理解:

  • 在调用分区函数之前,默认每次选择的比较标准都是某段数组的最后一个位置的值,这个比较标准越靠近这段数组的中位数,时间复杂度越低,否则时间复杂度越高。因此在这段数组中随机选取一个数与最后一个数交换,概率降低时间复杂度。
  • 分区函数可以根据比较标准将某段数组分成较小数区域靠前,相等数区域在中间,较大数区域靠后,那么此时可以确定相等数的位置就是整个数组有序后的位置,相等数的位置也就固定下来了,并返回相等数区域的左右边界。
  • 递归函数不断调用分区函数可以得到相等数区域的左右边界,以此得出较小数区域和较大数区域,继续递归较小数区域和较大数区域,就可以将每个相等数位置固定,最终让整个数组有序。

代码:

function quickSort(arr) {
    // 不用处理的数组直接返回
    if (arr == null || arr.length < 2) {
        return
    }
    // 开始递归     递归整个数组
    recursion(arr, 0, arr.length - 1)
}

// ------------------------4个函数-----------------------------------
// ------------------------4个函数-----------------------------------

// 递归函数     递归数组中的某一段
// 参数是数组某段的左右边界     arr[l...r]
function recursion(arr, l, r) {
    // 防止溢出???
    if (l < r) {
        // 固定选择每段数组的最后一个数作为比较标准   这个数越趋近于数组的中位数    时间复杂度越低
        // 因此随机选取某段数组arr[l...r]中的一个数与最后一个数进行交换     概率降低时间复杂度
        let ranInt = parseInt(Math.random()*(r - l + 1) + l) 
        swap(arr, ranInt, r)
        // 将某段数组进行分区后返回其中相等数的左右边界
        let p = partition(arr, l, r)
        // 递归较小数区域
        recursion(arr, l, p[0] - 1)
        // 递归较大数区域
        recursion(arr, p[1] + 1, r)   
    }
}

// ------------------------4个函数-----------------------------------
// ------------------------4个函数-----------------------------------

// 分区函数     将某段数组进行分区
// 参数是这段数组的左右边界arr[r...l]
// 这段数组按照比较标准进行分区后   较小数在前  相等数在中间    较大数在后
// arr[<...<, =...=, >...>]   
// 此时可以确定的是     相等数的位置就是整个数组有序后的位置
// 返回相等数的左右边界[=,=]
function partition(arr, l, r) {
    // 较小数和较大数区域的指针
    let low = l - 1, high = r
    // 此时左边界指针被当做查数指针     当前数指针
    // 右边界指针被当做标准数指针       保持不动
    // 按照这样的结构修改数组 arr[low...low,=...=,l.........,high...high,r]
    while (l < high) {
        // 当前数小于标准
        if (arr[l] < arr[r]) {
            // 当前数进入较小数区域   
            // 较小数区域向右推进     此时当前数指针指向了一个相等数,直接右移  
            swap(arr, l++, ++low)
            // 当前数大于标准
        }else if (arr[l] > arr[r]) {
            // 当前数进入较大数区域
            // 较大数区域向左扩展   此时当前数指针指向了一个未查看的数,不能右移,进入下一个循环
            swap(arr, l, --high)
        }else{
            // 当前数等于标准
            // 当前数指针直接右移
            l++
        }
    }
    // 将标准数与较大数区域的最前面一个数交换
    // arr[low...low,=...=,high...high,r]
    swap(arr, high, r)

    // 返回相等数的左右边界[=,=]
    return [low + 1, high]
}

// ------------------------4个函数-----------------------------------
// ------------------------4个函数-----------------------------------

function swap(arr, i, j) {
    let tmp = arr[i]
    arr[i] = arr[j]
    arr[j] = tmp
}

性能:

  • 时间复杂度:长期期望是O(N*log N)
  • 空间复杂度:O(log N)
  • 稳定性:无法保持,分区函数直接交换导致无法保持稳定性

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值