[路飞]排序数组

145 阅读1分钟

记录 1 道算法题

排序数组

leetcode-cn.com/problems/so…


要求:将数组升序排列。

排序老生常谈的问题了,主要有 4 种方法。

  1. 冒泡

冒泡的性能不好,加上一般会使用 api,所以一般不使用,但是是一种刚接触代码的时候都会碰到的解法。

    function sortArray(nums) {
        for(let i = 0; i < nums.length; i++) {
            // 每次循环后都会确定数组的最后一个位置的数
            for(let j = 0; j < nums.lenth - i - 1; j++) {
                // 相邻的两个数进行比较
                if(nums[j] > nums[j + 1]) {
                    const t = nums[j]
                    nums[j] = nums[j + 1]
                    nums[j + 1] = t
                }
            }
        }
        
        return nums
    }
  1. 快排

快排是每个人都会的一种排序算法。作为一种分治算法,但不算稳定,他是基于一个基准值划分左右,当随机的基准值划分的左边或右边只有一个的时候,递归的层数也挺深的,基本等于数组长度。

    function sortArray(nums) {
        fastSort(nums, 0, nums.length - 1)
        return nums
    }
    
    function fastSort(arr, start, end) {
        if (start >= end) return
        // 这里拿了第一个为基准值,采用随机会更好
        let p = arr[start]
        let s = start + 1
        
        for(let i = start + 1; i <= end; i++) {
            if (arr[i] < p) {
                swap(arr, i, s)
                s++
            }
        }
        // 将基准值交换到中间
        swap(arr, start, s - 1)
        // 由于不做减枝,而是排序整个数组,所以直接递归
        // 基准值的位置是对的,所以只需要对左右两边递归排序
        fastSort(arr, start, s - 2)
        fastSort(arr, s, end)
    }

堆是只关心堆顶是数字在堆中是什么关系,其他位置的数字存放时符合一个树状结构,但是乱序的。一般是大顶堆和小顶堆,大顶堆就是堆顶数字是堆内最大的。小顶堆则相反。

只要将数组里的数都放进堆中,然后再一直取堆顶的数就可以了。由于我们需要升序排列,所以我们使用小顶堆,就可以使用 push,添加到数组里。

堆的实现可以看这篇文章

    function sortArray(nums) {
        const heap = new Heap((a, b) => a - b)
        while(nums.length) {
            heap.push(nums.pop())
        }
        
        while(heap.size()) {
            nums.push(heap.pop())
        }
        
        return nums
    }
  1. 归并

归并可以将有序数组进行合并,常见有由上至下的递归写法和由下至上的循环写法。本质上是通过将数组划分成更小的数组,然后实现升序,比如 n 个长度为 1 的数组,他们自己是有序的。他们两两一组组成了 Math.sqrt(n) 个长度为 2 的数组,他们仍然是可以实现有序。依次组合,最后就实现了有序排列。

排序链表思路类似。不同的地方在于递归做法中,数组可以直接取到中间,进行砍半。不用斩断链表。