【JS数据结构与算法】冒泡、选择、插入排序算法的实现

前言

前面已经对排序算法进行创建了一个列表类:【JS数据结构】排序算法列表的封装

下面一起来学习如何实现几个常见的排序算法!

正文

1、冒泡排序

最基础也是最简单的排序算法。

主要思路

  • 第一步,比较相邻的元素,如果左边的数比右边的数要大,那么就交换它们两个。
  • 第二步,向右移动,对每一对相邻元素进行第一步操作。直到列表的最后一对操作完毕,最终确定最后一个元素为最大值。
  • 第三部,重复第一和第二步的操作,依次减少右移的次数,直到没有任何一对元素需要比较。

对于下面一个无需列表,我们对它进行排序。
在这里插入图片描述
动画效果
在这里插入图片描述
代码实现
下面如果需要用到两数交换的话,就调用方法:

// 交换两个数
ArrayList.prototype.swap = function (a, b) {
    
    
    var temp = this.array[a];
    this.array[a] = this.array[b];
    this.array[b] = temp;
}

冒泡排序算法

// 冒泡排序
ArrayList.prototype.bubbleSort = function () {
    
    
    // 1.获取数组的长度
    var length = this.array.length;
    // 第一次: i = 0; 比较0 和1 的位置的两个数据,如果0位置的数据比1位置的数据大,则交换
    // 最后一次: i = length - 2 , 比较的是length - 2 和length - 1的两个数
    for (var i = length - 1; i > 0; i--) {
    
    
        for (var j = 0; j < i; j++) {
    
    
            if (this.array[j] > this.array[j + 1]) {
    
    
                // 2.交换两个数
                this.swap(j, j + 1);
            }
        }
    }
}

冒泡排序的效率
对于上面的例子,我们可以知道,在6个数据中,我们一共进行比较的次数为:
5+4+3+2+1 (次)
那么对于N个数,我们就可以推出:
(N - 1)+(N - 2)+(N - 3)+ … + 1 = N * (N + 1)/ 2(次)
那么在前面的大O表示法中,我们可以得出冒泡排序的大O表示法为O(N2)

时间复杂度为O(N2)

优化
冒泡排序一共需要比较N * (N + 1)/ 2(次) 次,最坏的情况下是需要交换 N * (N + 1)/ 2(次)的,这里考虑到,在最终位置确定之前,期间的位置交换其实是不必要的,因此需要减少 交换的次数。

2、选择排序

选择排序是对冒泡排序的改进,主要是为了减少要交换的次数,因为并不是每一次的交换都是必须的,它将交换的次数有 N2 减少到 N ,但是比较的次数依旧 N2 次。

主要思路

  • 第一步,在整个列表中遍历一遍,从中提取最大(或者最小)的元素放到未排序列表的首部;
  • 第二步,再在剩下的未排序列表中提取最大(或者最小)的元素放到已排序列表的尾部。
  • 第三部,重复第二步的操作,依次减少提取最值的范围,直到未排序列表中的最后一位。

冒泡排序
在这里插入图片描述
选择排序算法

// 选择排序
ArrayList.prototype.selectSort = function () {
    
    
    // 1. 获取数组的长度
    var length = this.array.length,
    min;
    // 2.每一次减少提取最小值的范围,直到未排序序列的最后一个元素。
    for (var i = 0; i < length - 1; i++) {
    
    
        min = i;
        // 第一次:遍历整个数组,选出最小的元素。
        // 第n次:剩下最后一个元素。
        for (var j = min; j < length; j++) {
    
    
            if (this.array[min] > this.array[j]) {
    
    
                min = j;
            }
        }
        // 将最小的数放到已排序序列的末尾
        this.swap(min, i);
    }
}

选择排序的效率
同冒泡排序的效率一样,它最坏的情况需要比较的次数也是 N * (N + 1)/ 2(次) ,只是它的交换次数减少了,所以通常认为选择排序在执行效率上是高于冒泡排序的。

时间复杂度为O(N2)

优化
选择排序一共需要比较 N * (N + 1)/ 2 次,需要减少比较的次数。

3、插入排序

插入排序是简单排序(冒泡、选择、插入)中效率最好的。
在进入高级排序之前,插入排序是基础,理解了插入排序对于高级排序的理解有很大的帮助。
插入排序的核心思想就是局部有序

什么是局部有序?
比如我们在队伍中选择一个人,作为标记队员;
那么在标记队员的左边的所有队员都已经是有序的,也就是说在排队的过程中,有一部分人是排序好的,而有一部分是没有排序的。

主要思路

  • 第一步,将第一个元素看成是一个有序列表,把剩下的列表当做无序列表;
  • 第二步,从无序列表中的第一个元素开始,依次插入到有序列表的相应位置,期间的比较是有序列表的最后一个和无序列表的第一个,往有序列表的左边进行依次比较进行插入。

依旧是上面的例子进行插入排序
冒泡排序
插入排序动画
在这里插入图片描述

插入排序算法

// 插入排序
ArrayList.prototype.insertionSort = function(){
    
    
    // 1. 获取数组的长度
    var length = this.array.length,
    temp,j;

    // 2. 外层循环,从第2个元素(索引为1)开始获取数据,将它作为标记,向前面局部有序的列表中插入
    for(var i = 1; i < length; i++){
    
    
        // 3. 内层循环,将标记元素和前面的数据依次进行比较
        temp = this.array[i];
        j = i;
        // 4. 只要大于标记元素的值,就继续往前面找,在列表范围内直到找到不比标记元素的值大的位置。
        while(this.array[j - 1] > temp && j > 0){
    
    
            this.array[j] = this.array[j - 1];
            j--;
        }

        // 5. 将标记元素插入
        this.array[j] = temp;
    }
}

插入排序的效率
虽说最坏的情况下比较和交换的次数都是 N *(N - 1)/ 2 (次) ;
然而呢,平均次数也只有全体数据项的一半(N *(N - 1)/ 4)需要进行比较和交换,也就是说,插入排序的比较和交换次数的平均值之和才等于选择排序的比较次数;
因此插入排序的比较和交换的次数通常认为比冒泡排序和选择排序的都小,所以认为插入排序在执行效率上是高于冒泡排序和选择排序的。

时间复杂度为O(N2)

优化
向高级算法迈进!

总结

排序算法在很多情况下都可能会被使用到,比如列表的价格按照升序或者降序排列,也可能按照销售量排序…
了解简单排序算法是了解高级排序算法的前提,一开始学习高级排序算法肯定是不透彻也是吃不消的,所以打好基础来进入高级排序算法吧!----》【JS数据结构与算法】希尔排序、快速排序算法的实现(待更新)

猜你喜欢

转载自blog.csdn.net/weixin_42339197/article/details/102907562