只会用 Go 写 O(N²) 的冒泡排序算法?来看看优化后最好情况下的 O(N) 算法吧

简介: 本文首先对冒泡排序进行简单的介绍,然后通过图片演示冒泡排序的思路。普通冒泡排序算法一共要遍历 n - 1 轮,由测试用例 [4 2 1 3 5] 的结果可以推断出 如果在一轮遍历中,没有进行元素交换位置的操作,那么此时数组的里所有元素都处于正确位置。 根据这个结论,对算法进行优化,优化后的算法,最好的情况下时间复杂度为 O(N)。

耐心和持久胜过激烈和狂热。

哈喽大家好,我是陈明勇,本文分享的内容是使用 Go 实现冒泡排序算法。如果本文对你有帮助,不妨点个赞,如果你是 Go 语言初学者,不妨点个关注,一起成长一起进步,如果本文有错误的地方,欢迎指出!

冒泡排序

冒泡排序是交换排序中最简单的一种算法。 算法思路:

  • 遍历数组,相邻的两个元素进行比较,以升序为例,如果前面的元素大于后面的元素,则将它们的位置进行交换
  • 第一轮遍历结束之后,最大的元素会处于所遍历范围的最后一个位置,然后继续下一轮遍历
  • 每轮都会固定一个元素,直到所有元素都被固定,因此会执行 n - 1轮,n 为元素的个数,也就是数组(切片)的长度。为什么会是 n - 1 而不是 n,因为到了第 n 轮,只剩下最后一个元素没有被固定,没有元素可以和它进行比较了,因此第 n 轮可以忽略。

图片演示

冒泡排序.png

  • 第一轮遍历 [4, 2, 1, 3]
  • i = 0 时,比较第 i 个元素 4 与第 i + 1 个元素 2 的大小,因为 nums[i] > num[i+1],也就是 4 > 2,因此交换它们的位置。
  • i = 1 时,4 > 1,互换位置。
  • i = 2 时,4 > 3,互换位置。最大值 4 被交换到最后一个位置,此时所有元素都参与比较过了,结束第一轮遍历,执行下一轮遍历。
  • 第二轮遍历 [2, 1, 3, 4]
  • i = 0 时,2 > 1,互换位置。
  • i = 1 时,2 < 3,不做交换。次大值 3 被交换到 4 的左边,此时所有元素都参与比较过了,结束第二轮遍历,执行下一轮遍历。
  • 第三轮遍历 [1, 2, 3, 4]
  • i = 0 时,1 < 2,不做交换。此时所有元素都参与比较过了,结束第三轮遍历,
  • 执行了 n - 1 轮遍历,n 为数组的长度,n - 1个元素被交换到正确的位置,第 n 轮遍历时,只剩最后一个元素,因此不用继续进行。

普通的冒泡排序算法

import "fmt"
func main() {
    nums := [4]int{4, 2, 1, 3}
    fmt.Println("原数组:", nums)
    fmt.Println("--------------------------------")
    NormalBubbleSort(nums)
}
func NormalBubbleSort(nums [4]int) {
    for i := 0; i < len(nums)-1; i++ {
        for j := 0; j < len(nums)-i-1; j++ {
            if nums[j] > nums[j+1] {
                    nums[j], nums[j+1] = nums[j+1], nums[j]
            }
        }
        fmt.Printf("第 %d 轮遍历后的数组:%v\n", i+1, nums)
    }
    fmt.Println("--------------------------------")
    fmt.Println("排序后的数组:", nums)
}
复制代码

执行结果:

原数组: [4 2 1 3]
--------------------------------
第 1 轮遍历后的数组:[2 1 3 4]
第 2 轮遍历后的数组:[1 2 3 4]
第 3 轮遍历后的数组:[1 2 3 4]
--------------------------------
排序后的数组: [1 2 3 4]
复制代码
  • 值得注意的一个地方是第二层循环的条件 j < len(nums)-i-1,为什么会减去 i,因为每轮遍历结束之后,都会有一个元素被固定到后面,因此再进行下一轮的时候,那个元素无须再进行比较。
  • 算法遍历次数为 n -1,每次遍历时元素比较的次数依次为 n - 1、n - 2、n - 3、···、3、2、1,将所有次数求和 = 1 + 2 + 3 + ··· + n - 2 + n - 1= n - 1 * (n - 1 + 1) / 2 = (n² - 1) / 2,因此时间复杂度为 O(n²)。

优化算法

上述例子中,对数组 [4,2,1,3] 进行排序,我们来看看对数组 [4,2,1,3,5] 进行排序,打印数组排序的变化过程中:

原数组: [4 2 1 3 5]
--------------------------------
第 1 轮遍历后的数组:[2 1 3 4 5]
第 2 轮遍历后的数组:[1 2 3 4 5]
第 3 轮遍历后的数组:[1 2 3 4 5]
第 4 轮遍历后的数组:[1 2 3 4 5]
--------------------------------
排序后的数组: [1 2 3 4 5]
复制代码

不难看出,第三轮与第四轮遍历过程中,都没有进行元素交换位置的操作,对此我们可以推出一个结论,如果在一轮遍历中,没有进行元素交换位置的操作,那么此时数组的里所有元素都处于正确位置。 根据这个结论,我们可以对算法进行优化:

import "fmt"
func main() {
    nums := [5]int{4, 2, 1, 3, 5}
    fmt.Println("原数组:", nums)
    fmt.Println("--------------------------------")
    BestBubbleSort(nums)
}
func BestBubbleSort(nums [5]int) {
    isSwapped := true
    for isSwapped {
        isSwapped = false
        for i := 0; i < len(nums)-1; i++ {
            if nums[i] > nums[i+1] {
                nums[i], nums[i+1] = nums[i+1], nums[i]
                isSwapped = true
            }
        }
        fmt.Println("遍历后的数组:", nums)
    }
    fmt.Println("--------------------------------")
    fmt.Println("排序后的数组:", nums)
}
复制代码

执行结果:

原数组: 
--------------------------------
遍历后的数组: [2 1 3 4 5]
遍历后的数组: [1 2 3 4 5]
遍历后的数组: [1 2 3 4 5]
--------------------------------
排序后的数组: [1 2 3 4 5]
复制代码
  • 定义交换的标记变量 isSwapper,作为第一层循环的条件,每轮遍历开始之后,将标记变量  isSwapper 赋值为 false,如果在比较的过程中发生元素交换,则将标记变量 isSwapper 赋值为 true。直到 isSwapperfalse 时,数组的里所有元素都处于正确的位置,此时可以结束遍历了。
  • 根据执行结果可知,相比普通的算法,优化后的算法少了一轮遍历,这只是在数组元素少的情况下,如果在数组元素多的情况下,对比结果会更明显。
  • 如果数组为 [5,1,2,3,4],那么算法只会遍历一轮,就能得到正确的排序结果。因此优化后的算法,最好的情况下时间复杂度为 O(N),最坏的情况下仍为 O(N²)。

小结

本文首先对冒泡排序进行简单的介绍,然后通过图片演示冒泡排序的思路。普通冒泡排序算法一共要遍历 n - 1 轮,由测试用例 [4 2 1 3 5] 的结果可以推断出 如果在一轮遍历中,没有进行元素交换位置的操作,那么此时数组的里所有元素都处于正确位置。 根据这个结论,对算法进行优化,优化后的算法,最好的情况下时间复杂度为 O(N)。

目录
相关文章
|
21天前
|
机器学习/深度学习 算法 新能源
【优化调度】基于matlab粒子群算法求解水火电经济调度优化问题研究(Matlab代码实现)
【优化调度】基于matlab粒子群算法求解水火电经济调度优化问题研究(Matlab代码实现)
|
21天前
|
存储 算法 安全
【无人机】基于灰狼优化算法的无人机路径规划问题研究(Matlab代码实现)
【无人机】基于灰狼优化算法的无人机路径规划问题研究(Matlab代码实现)
118 0
|
21天前
|
机器学习/深度学习 数据采集 算法
【创新无忧】基于白鲨算法WSO优化广义神经网络GRNN电机故障诊断(Matlab代码实现)
【创新无忧】基于白鲨算法WSO优化广义神经网络GRNN电机故障诊断(Matlab代码实现)
|
22天前
|
算法 Java 调度
【车间调度】基于GA、PSO、SA、ACO、TS优化算法的车间调度比较研究(Matlab代码实现)
【车间调度】基于GA、PSO、SA、ACO、TS优化算法的车间调度比较研究(Matlab代码实现)
101 0
|
22天前
|
机器学习/深度学习 算法 网络性能优化
【EI复现】基于元模型优化算法的主从博弈多虚拟电厂动态定价和能量管理(Matlab代码实现)
【EI复现】基于元模型优化算法的主从博弈多虚拟电厂动态定价和能量管理(Matlab代码实现)
|
24天前
|
机器学习/深度学习 分布式计算 算法
【升级版本】基于多目标粒子群算法的微电网优化调度【风光、储能、柴油、燃气、电网交互】(Matlab代码实现)
【升级版本】基于多目标粒子群算法的微电网优化调度【风光、储能、柴油、燃气、电网交互】(Matlab代码实现)
|
24天前
|
安全 调度 Python
【电动车】基于多目标优化遗传算法NSGAII的峰谷分时电价引导下的电动汽车充电负荷优化研究(Matlab代码实现)
【电动车】基于多目标优化遗传算法NSGAII的峰谷分时电价引导下的电动汽车充电负荷优化研究(Matlab代码实现)
|
27天前
|
机器学习/深度学习 算法 数据挖掘
没发论文的注意啦!重磅更新!GWO-BP-AdaBoost预测!灰狼优化、人工神经网络与AdaBoost集成学习算法预测研究(Matlab代码实现)
没发论文的注意啦!重磅更新!GWO-BP-AdaBoost预测!灰狼优化、人工神经网络与AdaBoost集成学习算法预测研究(Matlab代码实现)
|
27天前
|
机器学习/深度学习 算法 安全
计及需求响应的粒子群算法求解风能、光伏、柴油机、储能容量优化配置(Matlab代码实现)
计及需求响应的粒子群算法求解风能、光伏、柴油机、储能容量优化配置(Matlab代码实现)
|
30天前
|
算法
离散粒子群算法(DPSO)的原理与MATLAB实现
离散粒子群算法(DPSO)的原理与MATLAB实现
74 0

热门文章

最新文章