蔚来面试的一道排序

224 阅读3分钟

在前面的一些面试中遇到过一道简单的算法题,就是找出第n大的数。具体的题目找不到了,但是跟这个差不多。(414. 第三大的数 - 力扣(LeetCode))就是第三大改成第n大。

我当时看到这个就很兴奋了,这不很简单吗?夸夸夸就写完了,不就是直接给数组用sort排个序然后直接用下标n给他取出来就行了吗。当我写完这个之后,他就开始发难了,能不能不用自带的方法排序? 完了,这不是问到我的软肋了吗,挠头发挠了半天没挠出来,害。所以还是要好好整理下吧,我又翻出来我的数据结构这本书。

几种排序方法

  1. 冒泡排序
  2. 选择排序
  3. 插入排序
  4. 快速排序
  5. 希尔排序
  6. 堆排序

先慢慢一个一个来吧!

冒泡排序

冒泡排序的原理就是根据冒泡一样,我还记的老师说的,大的沉下去,小的浮上来。意思就是一次拿两个相邻的元素比较,如果前者大于后者就进行交换,然后再往后走,一直交换下去,直到不再需要交换为止。

举个例子:

一组数 [5, 1, 2, 6, 2, 8, 3]

第一轮 [1, 2, 5, 2, 6, 3, 8]

(1,5交换后,5,2也要交换,5,6不需要交换,6,2交换,6,8不需要交换,8,3交换)

第二轮 [1, 2, 2, 5, 3, 6, 8]

(同理)

第三轮 [1, 2, 2, 3, 5, 6, 8]

(同理)

第四轮 [1, 2, 2, 5, 3, 6, 8]

(不需要交换,结束!)

具体的代码实现如下:


function bubbleSort(arr) {
    let n = arr.length;
    let swapped;
    for (let i = 0; i < n - 1; i++) {
        swapped = false;  // 初始化标志位为 false
        for (let j = 0; j < n - 1 - i; j++) {
            if (arr[j] > arr[j + 1]) {
                // 交换元素
                let temp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = temp;
                swapped = true;  // 发生了交换,设置标志位为 true
            }
        }
        // 如果没有发生交换,说明数组已经有序,可以提前结束
        if (!swapped) {
            break;
        }
    }
    return arr;
}

外圈循环代表着排序的轮次,因为我们排序的时候两两对比,只需要进行n-1轮排序就够了。第二层循环是交换元素的位置(如果位置不对的话)在这里设置一个是否交换标志,如果整个一轮都没有进行交换说明顺序已经排好,就不需要进行下一轮了,可以提前结束。

它的复杂度最好的情况下就是O(n),最坏的情况那就是n的平方咯。

选择排序

选择排序就是每次在没有排序的部分选择最小的(最大的)值放在首位(尾部)。

还是拿刚才的例子举例:

一组数 [5, 1, 2, 6, 2, 8, 3]

第一轮 [1, 5, 2, 6, 2, 8, 3]

(找到最小的值1,让他与首位5进行交换)

第二轮 [1, 2, 5, 6, 2, 8, 3]

(同理,2和5交换位置)

第三轮 [1, 2, 2, 6, 5, 8, 3]

(同理,2和5交换位置)

第四轮 [1, 2, 2, 3, 5, 8, 6]

(3和6交换位置)

第五轮 [1, 2, 2, 3, 5, 8, 6]

(5不需要交换位置)

第六轮 [1, 2, 2, 3, 5, 6, 8]

(6和8交换位置)

具体的代码实现如下:

function selectionSort(arr) {
    let n = arr.length; 
    for (let i = 0; i < n - 1; i++) { 
        let minIndex = i;
        for (let j = i + 1; j < n; j++) {
            if (arr[j] < arr[minIndex]) { 
                minIndex = j; 
            } 
        }
        if (minIndex !== i) {
            // 交换元素 
            let temp = arr[i]; 
            arr[i] = arr[minIndex]; 
            arr[minIndex] = temp;
        } 
    } 
    return arr; 
}

每一轮都会找到未排序的最小值,如果最小值的索引不是未排序的第一个的话就需要进行交换。 选择排序我认为还是差点意思,但是还是比较简单的,它的时间复杂的位On的平方。

未完待续

今天就先写这两个排序吧,明天再看看写剩下的几个排序。