js实现常见排序算法

电脑配置
CPU:AMD X4 640
内存: 宏想 DDR3 1600MHz 8g
主板:华擎 980DE3/U3S3 R2.0
浏览器:chrome 79.0.3945.88(正式版本) (64 位)

时间测试函数

        function testRunTime(fn) {
            let start = new Date();
            let end = null;
            fn();
            end = new Date();
            console.log(`运行时间: ${(end - start) / 1000}秒`);
        }

1.冒泡排序
2.选择排序
3.插入排序
4.希尔排序
5.归并排序
6.快速排序
7.计数排序
8.堆排序
9.二分法排序 每插入一个新元素,就对其进行排序

冒泡排序

排序思想:判断两个相邻元素,大于则交换位置
复杂度:O(n^2)
例子:[2 4 5 3 1] > [2 4 3 1 5] > [2 3 1 4 5] > 2 1 3 4 5] > [1 2 3 4 5]

// 冒泡排序
function bubbleSort(arr) {
    let len = arr.length-1;
    for (let i=0; i<len; i++) {
        for (let j=0; j<len-i; j++) {
            if (arr[j] > arr[j+1]) { // 大于则交换两个的位置
                let temp = arr[j];
                arr[j] = arr[j+1];
                arr[j+1] = temp;
            }
        }
    }
    return arr;
}

2.选择排序

排序思想: 每次判断,拿到最小值,交换位置
复杂度:O(n^2)
例子:[2 4 5 3 1] > [1 3 5 3 2] > [1 2 5 3 4] > [1 2 3 5 4] > [1 2 3 4 5]

// 选择排序
function selectionSort(arr) {
    let len = arr.length;
    let minIndex, temp;
    for (let i=0; i<len; i++) {
        minIndex = i;
        for (let j=i+1; j<len; j++) {
            if (arr[minIndex] > arr[j]) {
                minIndex = j; // 保存最小值索引
            }
        }
        // 进行互换位置
        temp = arr[minIndex];
        arr[minIndex] = arr[i];
        arr[i] = temp;
    }
    return arr;
}

3. 插入排序

适用与规模小、有序的数据3w-
排序思想:将数组分成两个,一个是已排序好的,一个是待排序的,将待排序的元素和已排序好的元素进行比较,插入适当位置。
复杂度:O(n^2) 有序程度越高,越快
例子:[2] [4 5 3 1] > [2 4] [5 3 1] > [2 4 5] [3 1] > [2 3 4 5] [1] > [1 2 3 4 5]

// 插入排序
function insertionSort(arr) {
    let len = arr.length;
    let prev, cur;

    for (let i = 1; i < len; i++) {
        prev = i - 1;
        cur = arr[i];
        while (prev>=0 && arr[prev]>cur) {
            arr[prev+1] = arr[prev];
            prev--;
        }
        arr[prev+1] = cur;
    }
    return arr;
}

4. 希尔排序

适用于中等规模的数据10万+
排序思想:将数组拆分成不同的间隔,对每个间隔进行插入排序,最后将全部进行一次插入排序
复杂度:O(n^1.5) 有序程度越高,越快

            let len = arr.length;
            let h = Math.floor(len/2);
            // while (h < len / 3) { h = 3 * h + 1 };
            while (h >= 1) {
                for (let i = h; i < len; i++) {
                    for (let j = i; j >= h && arr[j] < arr[j - h]; j -= h) {
                        let t = arr[j];
                        arr[j] = arr[j - h];
                        arr[j - h] = t;
                    }
                }
                h = Math.round(h / 3);
            }
            return arr;

5. 归并排序

排序思想:将数组拆分成最小单元,进行比较插入
复杂度:O(nlogn)
例子:[ 2 4 5 3 1] > [2] [4] [5] [3] [1] > [2 4] [5] [3] [1] > [2 4 5] [3] [1] > [2 3 4 5] [1] > [1 2 3 4 5]。从左往右比较合并

// 归并排序
function mergeSort(arr) {
    if (arr.length < 2) {
        return arr;
    }
    let middle = Math.floor(arr.length/2);
    let left = arr.slice(0, middle);
    let right = arr.slice(middle);

    return merge(mergeSort(left), mergeSort(right));
}

function merge(left, right) {
    let result = [];
    while (left.length && right.length) {
        if (left[0] <= right[0]) {
            result.push(left.shift());
        } else {
            result.push(right.shift());
        }
    }

    // 不管添加哪个,留下来的就是最大的
    while (left.length) {
        result.push(left.shift());
    }
    while (right.length) {
        result.push(right.shift());
    }
    return result;
}

6.快速排序

排序思想:取一个基准值,比基准值小的在左边,大的在右边;左右在继续这样的操作,最后合并。
复杂度:O(nlogn)
例子:[ 2 4 3 5 1 ] > [ 2 1]+[ 3 ]+[ 4 5 ] > [ 1 ]+[ 2 ]+[ 3 ]+[ 4 ]+[ 5 ]

// 快速排序
function quickSort (arr) {
    if (arr.length < 2) { // 数组元素只有一个的时候
        return arr;
    }
    let pivotIndex = Math.floor(arr.length/2);
    let pivot = arr.splice(pivotIndex,1)[0]; // 基准值
    let left = [], // 存放比基准值小的
        right = []; // 存放比基准值大的
    arr.forEach(item=>{
        if (item <= pivot) {
            left.push(item);
        } else {
            right.push(item);
        }
    })
    return quickSort(left).concat([pivot], quickSort(right));
}

7. 计数排序

排序思想:将数组的值当另一个数组的索引,再取出来。典型的空间换时间。
复杂度:O(n+m) m为元素最大值
例子

function countingSort(arr) {
    let bucket = [],
        sortedIndex = 0;
        arrLen = arr.length;

    for (let i = 0; i < arrLen; i++) { // 拿到数组的值当索引
        if (!bucket[arr[i]]) {
            bucket[arr[i]] = 0;
        }
        bucket[arr[i]]++;
    }

    for (let i = 0,len=bucket.length; i < len; i++) {
        while(bucket[i] > 0) { // 拿到索引填充到数组中
            arr[sortedIndex] = i;
            sortedIndex++;
            bucket[i]--;
        }
    }

    return arr;
}

8.堆排序

排序思想:先构建一个最大堆,然后循环数组,依次将最大的元素放到末尾
复杂度:O(nlogn)

            function heapSort(arr) {
                let len = arr.length;
                function maxHeapify(i) {
                    let left = 2 * i + 1;
                    let right = 2 * i + 2;
                    let largest = i;

                    if (left < len && arr[left] > arr[largest]) {
                        largest = left;
                    }
                    if (right < len && arr[right] > arr[largest]) {
                        largest = right;
                    }
                    if (largest != i) {
                        swap(i, largest);
                        maxHeapify(largest);
                    }
                }
                function swap(i, j) {
                    let t = arr[i];
                    arr[i] = arr[j];
                    arr[j] = t;
                }
                // 构建堆
                for (let i = Math.floor(len/2) - 1; i >= 0; i--) {
                    maxHeapify(i);
                }
              // 大-> 小
                for (let i = arr.length - 1; i > 0; i--) {
                    swap(0, i);
                    len--;
                    maxHeapify(0);
                }
                /* 小->大
                for (let i = 0; i < len; i++) {
                    maxHeapify(i);
                }
              */
                return arr;
            }

9.二分法排序

排序思想:插入元素时进行排序,因为之前的元素是有序的,所以可以使用二分法,到最后,小于中间值的插入中间值前面,大于或等于中间值的插入后面
复杂度:nlog2^n

        function binarySort(arr, val) {
            let begin = 0;
            let end = arr.length - 1;
            let middle = Math.floor(end / 2);
            while (begin < end && arr[middle] != val) { // 二分排序法
                if (arr[middle] > val) {
                    end = middle - 1;
                } else if (arr[middle] < val) {
                    begin = middle + 1;
                }
                middle = Math.floor(begin + (end - begin) / 2);
            }
            if (arr[middle] > val) { // 最后找到的中间值,只有两种结果
                arr.splice(middle, 0, val);
            } else {
                arr.splice(middle + 1, 0, val);
            }
            return arr;
        }
        testRunTime(() => {
            let arr = [];
            for (let i = 0; i < 100000; i++) {
                let num = Math.floor(Math.random() * 10000);
                arr = binarySort(arr,num);
            };
        });
posted @ 2019-12-19 17:01  魂之王  阅读(874)  评论(0编辑  收藏  举报