简单排序(冒泡排序,选择排序,插入排序)

83 阅读9分钟

前言

假期转瞬即逝,今天又是一个新的开始。在此祝愿大家:开工大吉,龙年行大运!愿大家的事业如龙腾飞,步步高升,财富滚滚来。
不知道今天大家都收到了多少开工红包,我这里收到了四个哦。

微信图片_20240218181522.jpg

新的一年我将继续在掘金这里分享我的学习,争取可以早日成为技术大佬。在此也祝大家技术精湛,项目顺利,步步高升,成就非凡。

冒泡排序

简单排序有三种,包括冒泡排序(Bubble Sort)、选择排序(Selection Sort)和插入排序(Insert Sort)

可能是习惯的问题,也可能是大学的时候老师对冒泡排序比较着重的讲解,我平时在做简单的排序算法题时大多数都会下意识的使用冒泡排序。

冒泡排序的原理是:从左到右,相邻元素进行比较。每次比较一轮,就会找到序列中最大的一个或最小的一个。这个数就会从序列的最右边冒出来。

以从小到大排序为例,第一轮比较后,所有数中最大的那个数就会浮到最右边;第二轮比较后,所有数中第二大的那个数就会浮到倒数第二个位置……就这样一轮一轮地比较,最后实现从小到大排序。

冒泡.gif

代码如下:

let arr = [2,44,38,5,47,15,36,50,48,26,27,2,46,4,19]  //因为gif图片是在网上找到的,为了更好的解释冒泡排序稍微调整了数组的顺序
let len = arr.length
for(let i = 0; i < len - 1; i++){
    for(let j = 0; j < len - 1 - i; j++){ //len-1-i是因为每一趟就会少一个数比较
        if(arr[j] > arr[j + 1]){
            let temp = arr[j]
            arr[j] = arr[j + 1]
            arr[j + 1] = temp
        }
    }
    console.log(arr)
}

console.log(arr,'+++')

打印:
[   3, 38,  5, 44, 15, 36,  47, 48, 26, 27,  2, 46,   4, 19, 50]  // 第一次打印确定了数组最后一位的数字
[   3,  5, 38, 15, 36, 44,  47, 26, 27,  2, 46,  4,  19, 48, 50] // 第二次打印确定了数组最后两位位的数字
[   3,  5, 15, 36, 38, 44,  26, 27,  2, 46,  4, 19,  47, 48, 50]// 第三次打印确定了数组最后三位的数字,后面以此类推
[   3,  5, 15, 36, 38, 26,  27,  2, 44,  4, 19, 46,  47, 48, 50]
[   3,  5, 15, 36, 26, 27,   2, 38,  4, 19, 44, 46,  47, 48, 50]
[   3,  5, 15, 26, 27,  2,  36,  4, 19, 38, 44, 46,  47, 48, 50]
[   3,  5, 15, 26,  2, 27,   4, 19, 36, 38, 44, 46,  47, 48, 50]
[   3,  5, 15,  2, 26,  4,  19, 27, 36, 38, 44, 46,  47, 48, 50]
[   3,  5,  2, 15,  4, 19,  26, 27, 36, 38, 44, 46,  47, 48, 50]
[   3,  2,  5,  4, 15, 19,  26, 27, 36, 38, 44, 46,  47, 48, 50]
[   2,  3,  4,  5, 15, 19,  26, 27, 36, 38, 44, 46,  47, 48, 50]
[   2,  3,  4,  5, 15, 19,  26, 27, 36, 38, 44, 46,  47, 48, 50]
[   2,  3,  4,  5, 15, 19,  26, 27, 36, 38, 44, 46,  47, 48, 50]
[   2,  3,  4,  5, 15, 19,  26, 27, 36, 38, 44, 46,  47, 48, 50]
[   2,  3,  4,  5, 15, 19,  26, 27, 36, 38, 44, 46,  47, 48, 50] +++

冒泡排序:
时间复杂度:最坏情况:O(N^2)
最好情况:O(N)
空间复杂度:O(1)

选择排序

选择排序的原理: 选择排序算法是通过遍历数组,选择出数组的最小或最大值,与指定位置交换数据,遍历完整个数组的所有位置就完成排序。

选择.gif

代码如下:

let arr = [3,44,38,5,47,15,36,26,27,2,46,4,19,50,48]
let len = arr.length

for(let i = 0; i < len - 1; i++){
    let index = i
    for(let j = i + 1; j < len; j++){
        if(arr[index] > arr[j]){
            index = j
        }
    }
    if(index != i){
        let temp = arr[i]
        arr[i] = arr[index]
        arr[index] = temp
    }
    console.log(arr)
}
console.log(arr,'+++')

打印:
[
   2, 44, 38, 5, 47, 15,
  36, 26, 27, 3, 46,  4,
  19, 50, 48
] //遍历第一趟数组,找出数组的最小值,与第一个数据交换
[
   2,  3, 38,  5, 47, 15,
  36, 26, 27, 44, 46,  4,
  19, 50, 48]// 遍历第二趟数组,继续找出最小值,与第二个数据交换
[
   2,  3,  4,  5, 47, 15,
  36, 26, 27, 44, 46, 38,
  19, 50, 48
]// 遍历第三趟数组,继续找出最小值,与第三个数据交换,后面依此类推
[
   2,  3,  4,  5, 47, 15,
  36, 26, 27, 44, 46, 38,
  19, 50, 48
]
[
   2,  3,  4,  5, 15, 47,
  36, 26, 27, 44, 46, 38,
  19, 50, 48
]
[
   2,  3,  4,  5, 15, 19,
  36, 26, 27, 44, 46, 38,
  47, 50, 48
]
[
   2,  3,  4,  5, 15, 19,
  26, 36, 27, 44, 46, 38,
  47, 50, 48
]
[
   2,  3,  4,  5, 15, 19,
  26, 27, 36, 44, 46, 38,
  47, 50, 48
]
[
   2,  3,  4,  5, 15, 19,
  26, 27, 36, 44, 46, 38,
  47, 50, 48
]
[
   2,  3,  4,  5, 15, 19,
  26, 27, 36, 38, 46, 44,
  47, 50, 48
]
[
   2,  3,  4,  5, 15, 19,
  26, 27, 36, 38, 44, 46,
  47, 50, 48
]
[
   2,  3,  4,  5, 15, 19,
  26, 27, 36, 38, 44, 46,
  47, 50, 48
]
[
   2,  3,  4,  5, 15, 19,
  26, 27, 36, 38, 44, 46,
  47, 50, 48
]
[
   2,  3,  4,  5, 15, 19,
  26, 27, 36, 38, 44, 46,
  47, 48, 50
]
[
   2,  3,  4,  5, 15, 19,
  26, 27, 36, 38, 44, 46,
  47, 48, 50
] +++

选择排序:
时间复杂度:最坏情况:O(N^2)
最好情况:O(N^2)
空间复杂度:O(1)

插入排序

插入排序就是将待排序的记录按照它的关键码值插入到一个已经排好序的有序序列中,直到所有的记录都插入完,得到一个新的有序序列。

插入排序的算法很简单,依次对每一个元素进行单趟排序就行了,由于要前一个数比较则只需要从1开始遍历n-1次。

插入排序和选择排序有一个异曲同工的地方在于他们都存在一个:在原数组上创建子数组的思想,这两种排序方法都会将原数组分为两个部分:待排序数组与已排好序的数组,但是这两种算法的内核思想却截然不同。

插入.gif

根据动图,我们可以指导插入排序的过程了(以从小到大排序为例):我们将原数组空间看成两个部分,前边是有序部分,后边是无序部分。当我们不断的取无序数组的首元素,从有序数组的尾部向首部依此对比找到比取出元素的小的元素,插入到该元素的后面;没有比取出元素小的则插入到数组第一位。这个移动过程有点像冒泡排序的过程:新加入元素和它前边的元素进行对比,如果它比它前边的元素小,则二者互换位置,重复这个行为,直到它前边的元素小于它才会停止,这样一来,有序数组就仍然是有序数组了。我们重复这个向有序数组中插入不断插入数据,直到无序数组的长度为0整个数组排序宣告完成。

代码如下:

let arr = [3,44,38,5,47,15,36,26,27,2,46,4,19,50,48]
let len = arr.length

for(let i = 1; i < len; i++){
    for(let j = i - 1; j >= 0; j--){
        if(arr[j] > arr[j + 1]){
            let temp = arr[j]
            arr[j] = arr[j+1]
            arr[j+1] = temp
        }else{
            break
        }
    }
    console.log(arr)
}

console.log(arr,'+++')

打印:
[
   3, 44, 38, 5, 47, 15,
  36, 26, 27, 2, 46,  4,
  19, 50, 48
] // 有序数组:[3,44] 无序数组:[38, 5, 47, 15, 36, 26, 27, 2, 46, 4, 19, 50, 48]
[
   3, 38, 44, 5, 47, 15,
  36, 26, 27, 2, 46,  4,
  19, 50, 48
]// 有序数组:[3,38,44,] 无序数组:[ 5, 47, 15, 36, 26, 27, 2, 46, 4, 19, 50, 48]
[
   3,  5, 38, 44, 47, 15,
  36, 26, 27,  2, 46,  4,
  19, 50, 48
]// 有序数组:[3,5,38,44] 无序数组:[47, 15, 36, 26, 27, 2, 46, 4, 19, 50, 48] //以此类推
[
   3,  5, 38, 44, 47, 15,
  36, 26, 27,  2, 46,  4,
  19, 50, 48
]
[
   3,  5, 15, 38, 44, 47,
  36, 26, 27,  2, 46,  4,
  19, 50, 48
]
[
   3,  5, 15, 36, 38, 44,
  47, 26, 27,  2, 46,  4,
  19, 50, 48
]
[
   3,  5, 15, 26, 36, 38,
  44, 47, 27,  2, 46,  4,
  19, 50, 48
]
[
   3,  5, 15, 26, 27, 36,
  38, 44, 47,  2, 46,  4,
  19, 50, 48
]
[
   2,  3,  5, 15, 26, 27,
  36, 38, 44, 47, 46,  4,
  19, 50, 48
]
[
   2,  3,  5, 15, 26, 27,
  36, 38, 44, 46, 47,  4,
  19, 50, 48
]
[
   2,  3,  4,  5, 15, 26,
  27, 36, 38, 44, 46, 47,
  19, 50, 48
]
[
   2,  3,  4,  5, 15, 19,
  26, 27, 36, 38, 44, 46,
  47, 50, 48
]
[
   2,  3,  4,  5, 15, 19,
  26, 27, 36, 38, 44, 46,
  47, 50, 48
]
[
   2,  3,  4,  5, 15, 19,
  26, 27, 36, 38, 44, 46,
  47, 48, 50
]
[
   2,  3,  4,  5, 15, 19,
  26, 27, 36, 38, 44, 46,
  47, 48, 50
] +++

插入排序:
时间复杂度:最坏情况下为O(N^2),此时待排序列为逆序,或者说接近逆序
最好情况下为O(N),此时待排序列为升序,或者说接近升序。
空间复杂度:O(1)

小结

本文介绍了简单排序(冒泡排序,选择排序,插入排序),下一篇我将会对高级排序做一个详细的介绍。