几种排序算法

148 阅读2分钟

这篇文章主要记录下几种常见的排序算法,以递归实现为主:

1、选择排序

选择排序(Selection sort)是一种简单直观的排序算法。它的工作原理是:第一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,然后再从剩余的未排序元素中寻找到最小(大)元素,然后放到已排序的序列的末尾。以此类推,直到全部待排序的数据元素的个数为零。

时间复杂度:O(n^2)

//递归实现方式
let sort = (numbers) => {
    if (numbers.lenght > 2) {
        let index = minIndex(numbers)        
        let min = numbers[index]
        numbers.splice(index, 1)
        return [min].concat(sort(numbers))
    } else {
        return numbers[0] > numbers[1] ? numbers.reverse() : numbers    
}
}

let minIndex = (numbers) => indexOf(min(numbers)) //获取最小下标函数
let min = (numbers) => {    if (numbers.lengh > 2) {        return min([numbers[0], min(numbers.slice(1))])    } else {        return Math.min.apply(null, numbers)    }}

//循环实现方式
let sort = (numbers) => {    if (numbers.length > 2) {        let index = minIndex(numbers)        let min = numbers[index]        numbers.splice(index, 1)        return [min].concat(sort(numbers))    } else {        return numbers[0] > numbers[1] ? numbers.reverse() : numbers    }}let swap = (numbers, a, b) => {  //定义一个调换下标的函数swap    c = numbers[a]    numbers[a] = numbers[b]    numbers[b] = c}

2、快速排序

打个比方:想象你是一个体育委员,你面对着一群学号不一致的同学,这个时候你喊“以某同学为基准,小的去前面,大的前后面,只要重复这句话,就可以排序。

快速排序的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。

时间复杂度:O(n log2n)

let quickSort = (arr) => {
    if (arr.lenght <= 1) {
        return arr
    } else {
        let minddlenumber = Math.floor(arr.length / 2)            //选定排序基准
        let middle = arr[minddlenumber]
        let left = []                               //部署两个数列,用于添加排序项
        let right = []  
        arr.splice(minddlenumber, 1)
        for (let i = 0; i < arr.length; i++) {    //大于基准项的去右边,小的去左边
            if (arr[i] < middle) {
                left.push(arr[i])
            } else {
                right.push(arr[i])
            }
        }
        return quickSort(left).concat([middle], quickSort(right))
    }    //返回数组,并将两边的数组继续进行quicksort排序递归,直到只剩一项直接返回

3、归并排序

归并排序比较难以理解,重点在于merge算法将排序数组内的每一项都拆分出来进行排序,

已有序的子序列合并,得到完全有序的序列;

时间复杂度:O(n log2n)

let mergeSort = arr => {
    let k = arr.length
    if (k === 1) { return arr }
    let left = arr.slice(0, Math.floor(k / 2))
    let right = arr.slice(Math.floor(k / 2))
    return merge(mergeSort(left), mergeSort(right))
 }
}let merge = (a, b) => {
    if (a.length === 0) return b
    if (b.length === 0) return a
    return a[0] > b[0] ? [b[0]].concat(merge(a, b.slice(1))) : [a[0]].concat(merge(a.slice(1), b)
)}

4、计数排序

计数排序引入了一个数据结构哈希表,用其做记录,大致思路为发现数字N就记为N:1,如果再次发现N就加1,最后把哈希表的key全部打出来,假设N:m,那么n需要打印m次

let countSort = arr => {    let hashTable = {},        max = 0,        result = []    for (let i = 0; i < arr.length; i++) { // 遍历数组        if (!(arr[i] in hashTable)) {             hashTable[arr[i]] = 1        } else {            hashTable[arr[i]] += 1        }        if (arr[i] > max) { max = arr[i] }    }    for (let j = 0; j <= max; j++) { // 遍历哈希表        if (j in hashTable) {            for (let i = 0; i < hashTable[j]; i++) {                result.push(j)            }        }    }    return result}

它的优势在于在对一定范围内的整数排序时,它的复杂度为Ο(n+k)(其中k是整数的范围),快于任何比较排序算法。 当然这是一种牺牲空间换取时间的做法。

时间复杂度:Ο(n+k)

5、冒泡排序

它重复地走访过要排序的元素列,依次比较两个相邻的元素,如果顺序(如从大到小、首字母从Z到A)错误就把他们交换过来。走访元素的工作是重复地进行直到没有相邻元素需要交换,也就是说该元素列已经排序完成。 这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端(升序或降序排列),就如同碳酸饮料中二氧化碳的气泡最终会上浮到顶端一样,故名“冒泡排序”。

时间复杂度:Ο(n^2)

function bubbleSort(arr) {    var i = arr.length,        j;    var tempExchangVal;    while (i > 0) {        for (j = 0; j < i - 1; j++) {            if (arr[j] > arr[j + 1]) {                tempExchangVal = arr[j];                arr[j] = arr[j + 1];                arr[j + 1] = tempExchangVal;            }        }        i--;    }    return arr;}

还有堆排序等较复杂的排序算法没有介绍,后面会在更新一篇。

                 ———— 部分信息来自饥人谷、网络公开资料