冒泡排序、选择排序、插入排序、快速排序

冒泡排序

(最常用,也是是原理最简单的排序,但是他是三种排序算法中效率最低的, 适用于数据量很小的排序场景,因为冒泡原理简单)

时间复杂度O(n*n),可以从前向后,也可以从后向前进行排序.

avator

案例解析:每一轮把最大的数放到最后面

 //冒泡排序
    let arr = [2, 4, 1, 6, 3]
    function bubbled(arr) {
        for (let i = 0; i < arr.length - 1; i++) {
            //【!!注意】这里不是j=i,因为回回都必须重头遍历,才能不漏一个,不然会有BUG
            for (let j = 0; j < arr.length - 1; j++) {
                if (arr[j] > arr[j + 1]) {
                    let temp
                    temp = arr[j]
                    arr[j] = arr[j + 1]
                    arr[j + 1] = temp
                }
            }
        }
        return arr
    }
    console.log(bubbled(arr));  //[1,2,3,4,6]

选择排序

(复杂度O(n*n),但是他的数据交换时间复杂度仅为O(N),在数组排序过程中,数据的移动交换是比较耗时的,所以相对于冒泡排序而言,选择排序的效率大大提高。  适用于大多数排序场景,虽然他的对比次数较多,但是数据量大的时候,他的效率明显优于冒泡)

顾名思义,选择出来进行排序,最开始先遍历一遍数组,选择出来最小的值放在数组第一个位置,之后再对第二个元素之后的元素进行遍历,选择出来最小的值放在这个子无序序列的第一位,也就是数组的第二个元素,这样前两个数就排完了,以此类推,

avator

//选择排序(指挨个挨个遍历,`选择`右侧最小与之交换)
    let arr1 = [2, 4, 1, 6, 3]
    function select(arr1) {
        for (let i = 0; i < arr1.length - 1; i++) {
            let min = i    //保存右侧最小值的下标
            for (let j = i + 1; j < arr1.length; j++) {
                if (arr1[j] < arr1[min]) {
                    //【!!注意】:这里每次循环保存相对较小值的下标
                    min = j
                }
            }
            if (arr1[min] < arr1[i]) {
                let temp;
                temp = arr1[min]
                arr1[min] = arr1[i]
                arr1[i] = temp
            }
        }
        return arr1
    }
    console.log(select(arr1));  //[1,2,3,4,6]

插入排序

(插入排序适用于已有部分数据有序的情况,有序部分越大越好。)

插入排序复杂度也是O(n*n),涉及到了元素的移动。先把数组中的第一个元素看成有序数列,查找与这个有序数列相邻元素,与有序数列中的每个元素进行比较,插入到合适的位置,直至有序数列中的元素和原数组元素相等排序完成。

avator

 //插入排序
    let arr2 = [2, 4, 1, 6, 3]
    function Ins(arr2) {
        let temp  //专门用于保存作为比较的i项
        for (let i = 1; i < arr2.length; i++) {
            while (i > 0 && arr2[i] < arr2[i - 1]) {
                temp = arr2[i]     //先对后面的值保存一下,因为这个值还要跟前面做对比啊! 你看下一步就要把后面的值覆盖了
                arr2[i] = arr2[i - 1]

                arr2[i - 1] = temp
                i--;
            }
        }
        return arr2
    }
    console.log(Ins(arr2))  //[1,2,3,4,6]

 快速排序

(快速排序对于数组元素重复率高的不适用。)

快速排序要求选择的枢轴值两边子序列长度最好一致,快速排序的时间消耗上主要在对元素的划分上,元素数量为k的数组,共需要比较k-1次。快速排序主要在于选择基准,如果选择的基准刚好是最小的或者最大的元素,那么这时候时间复杂度最大为O(n*n),如果刚好选择的基准就是这个无序序列的中值,时间复杂度最小为O(nlgn),总的关键字比较次数:O(nlgn)

快速排序为社么快,这里要提到一个分治思想,分而治之,虽然用到的是递归,虽然也有最坏情况下和冒泡,选择排序相等的时间复杂度,但是,分治思想是关键,把一个大问题分成两个小问题,分别同时处理,这两个小问题再向下分,最后问题也就水落石出了,分治思想避免了做无用功,选择一个基准,大于他的数在他的右面,小于他的数在他的左面,在进行比较的时候,左面的数只在左面进行比较就可以,没有必要再去右面比较,这样节省了时间

let arr3 = [2, 4, 1, 6, 3]
    function fast(arr3) {
        if (arr3.length <= 1) return arr3; //【!!!注意】:这一句必须加上,因为有时候递归回来可能左边数组只有一个元素(或空数组),这时直接返回arr ,结束left递归,让它去递归right

        let left = [];
        let right = [];
        let pivot = arr3[0]
        for (let i = 1; i < arr3.length; i++) {
            if (arr3[i] < pivot) {
                left.push(arr3[i])
            } else {
                right.push(arr3[i])
            }
        }
        return fast(left).concat([pivot], fast(right))
    }
    console.log(fast(arr3));   //[1,2,3,4,6]

测试时可采用我前期博文调试前端console.time和console.timeEnd_如花菇凉的博客-CSDN博客来监测对比性能时间度

以上参考文献


【总结】:大厂面试常考手撕代码 —— JavaScript排序算法(冒泡排序、选择排序、插入排序、快速排序)_故里有长安丶丶的博客-CSDN博客
 

猜你喜欢

转载自blog.csdn.net/u012174809/article/details/123640096