JavaScript數據結構與算法(排序算法)

比較排序算法通常有三個指標程序員

  • 時間複雜度, 算法執行完成所須要的時間
  • 空間複雜度, 算法執行完成所須要的空間
  • 穩定性,當二個元素的值相同的時候,排序以後二個元素的先後位置是否發生改變

如下的排序都爲升序面試

冒泡排序

冒泡排序是面試官最喜歡問新手程序員的.冒泡排序就像名字同樣,冒泡排序第一次冒出最大的,第二次冒出第二大的,第三次冒出第三大的.....直到冒出倒數第二大的.算法

const array = [12, 2, 3, 10, 8, 8, 9, 21]
function BubbleSort(array){
    let len = array.length;
    if (len == 0 || len == 1) {
        return array;
    }
    for (let i = 0; i < len-1; i++) {
        for (let j = 0; j < len-1-i; j++) {  // 減i是由於第0到第i大已經冒出來了 不須要再比較了
            if (array[j] > array[j+1]) {
                [array[j], array[j+1]] = [array[j+1], array[j]];
            }
        }
    }
    return array
}
BubbleSort(array)  //[2, 3, 8, 8, 9, 10, 12, 21]
複製代碼

時間複雜度爲O(n^2),空間複雜度爲O(1),穩定瀏覽器

僅僅面試考察,實際運用是不會用到的,由於冒泡排序是很是沒效率的,由於不只時間複雜度高並且有O(n^2)的交換,交換所耗的性能遠大於比較bash

選擇排序

選擇排序是第一位找到最小的,第二位找到第二小的,第三位找到第三小的.....post

const array = [12, 2, 3, 10, 8, 8, 9, 21]
function SelectionSort(array){
    let len = array.length;
    if (len == 0 || len == 1) {
        return array;
    }
    for (let i = 0; i < len-1; i++) {
        let min = i;
        for (let j = i+1; j < len-1-i; j++) {
            if (array[j] < array[min]) {
                min = j
            }
        }
        [array[i], array[min]] = [array[min], array[i]];
    }
    return array 
}
SelectionSort(array)  //[2, 3, 8, 8, 9, 10, 12, 21]

複製代碼

時間複雜度爲O(n^2),空間複雜度爲O(1),穩定性能

僅僅面試考察,實際運用跟冒泡同樣,也不會用到,由於效率也很是低. 可是比冒泡好點,由於元素若是再正確的位置上不會交換。ui

插入排序

就是,對於未排序數據,在已排序序列中從後向前掃描,找到相應位置並插入this

const array = [12, 2, 3, 10, 8, 8, 9, 21]
function InsertionSort(array){
        let len = array.length;
        if (len == 0 || len == 1) {
            return array;
        }
        for (let i = 1; i < len; i++) {
            for (let j = 0; j < i; j++) {        // 查找的部分能夠使用二分查找
                if (array[j] > array[i]) {
                    this.splice(j, 0, array[i]); // 插入進來
                    this.splice(i+1, 1);         // 刪除已插入的元素 
                    break;
                }
            }
        }
        return array;
    }
InsertionSort(array)  //[2, 3, 8, 8, 9, 10, 12, 21]
複製代碼

時間複雜度爲O(n^2),空間複雜度爲O(1),不穩定spa

效率也不高,一般也不會使用,可是若是數據接近線性排列.那麼使用二分查找插入排序是一個很是好的選擇

快速排序

這個也是常常被問到,是遞歸算法的經典使用場景

const array = [12, 2, 3, 10, 8, 8, 9, 21]
function quickSort(array){
    let len = array.length;
    if (len == 0 || len == 1) {
        return array;
    }
    let mid = array[0],
        left =[],
        right = [];
    for (let i = 1; i < len; i++) {
        if (array[i] < mid) {
            left.push(array[i])
        } else {
            right.push(array[i])
        }
    }
    return quickSort(left).concat(mid, quickSort(right))
}
quickSort(array)  //[2, 3, 8, 8, 9, 10, 12, 21]
複製代碼

時間複雜度爲O(nlogn),空間複雜度爲O(n),不穩定

平均時間複雜度低 ,佔用空間小,快速排序是使用得最多得排序算法

歸併排序

歸併排序是分治算法得經典應用,歸併算法得核心是將兩個已經排序的序列合併成一個序列.

const array = [12, 2, 3, 10, 8, 8, 9, 21]
function mergeSort(array){
    let len = array.length;
    if (len == 0 || len == 1) {
        return array;
    }
    function merge(left, right) {
        let final = [];
        while (left.length && right.length) {
            final.push(left[0] <= right[0] ? left.shift() : right.shift());
        }
		return final.concat(left.concat(right));
    }
    let mid = Math.floor(len-1/2);
    let left = array.slice(0, mid)
    let right = array.slice(mid);
    return merge(mergeSort(left), mergeSort(right))
}
mergeSort(array)  //[2, 3, 8, 8, 9, 10, 12, 21]

複製代碼

時間複雜度爲O(nlogn),空間複雜度爲O(n),不穩定

時間複雜度和空間複雜度與快速排序是同樣的,其實二個性能是至關的,畢竟二種排序都出如今瀏覽器內核中。爲何要快速排序使用較大,可能快速排序在各類數據量下表現得更爲穩定吧. 可是若是數據呈分段有序時,使用歸併排序效率更高

堆排序

具體如何實現,在這一章已經講過,我直接貼上代碼了

// 最大堆調整
  function maxHeapfiy(array, i, heapSize){
        let left = 2*i+1,
            right = 2*i+2,
            mid = i;
        if (left < heapSize && array[left] > array[mid]) {
            mid = left;
        }
        if (right < heapSize && array[right] > array[mid]) {
            mid = right;
        }
        if (mid != i) {
            [array[i], array[mid]] = [array[mid], array[i]]
            maxHeapfiy(array, mid, heapSize)
        }
    }  
    // 構建最大堆
    const buildMaxHeapfiy = (array, heapSize) => {
        let parent = Math.floor(heapSize/2)
        for (parent; parent >= 0; parent--) {
            maxHeapfiy(array, parent, heapSize)
        }
    }
    
    // 堆排序
    const array = [12, 2, 3, 10, 8, 8, 9, 21];
    let heapSize = array.length;
    buildMaxHeapfiy(array, heapSize)
    for (let i = heapSize-1; i >=0; i--) {
        [array[0], array[i]] = [array[i], array[0]];
        this.maxHeapfiy(array, 0, i);
    }
    // [2, 3, 8, 8, 9, 10, 12, 21]

複製代碼

時間複雜度爲O(nlogn),空間複雜度爲O(n),不穩定

堆排序雖然,時間複雜度和空間複雜度都較低,可是堆排序的有個缺點在於當堆中的一個數據發生改變,都須要進行堆調整來維護最大堆(最小堆),須要額外的維護開銷,因爲在實際運用中,數據變更是很頻繁的,因此實際上堆排序不是很適合實際的運用。

相關文章
相關標籤/搜索