【排序算法】十大排序算法之冒泡排序

【排序算法】十大排序算法之冒泡排序

冒泡排序是数据结构和算法课程中最基础的排序算法,通过循环比较相邻的两个元素的大小,按照预设的升序或降序交换不符合排序规则的相邻元素,十分简单有效。

整个排序过就好像气泡不断从水里冒出来,最大的先出来,次大的第二出来,最小的最后出来,所以将这种排序方式称为冒泡排序(Bubble Sort)。

一、复杂度分析

  • 时间复杂度

时间复杂度:定量描述了算法的运算时间,用大O符号来表示。

在计算的时候,先找出算法基本操作的执行次数,即为T(n),然后找到它的同数量级,即为f(n),如果T(n)与f(n)的比值求极限可得到一个常数c,那么时间复杂度T(n)=O(f(n))。

冒泡排序的时间复杂度为两个嵌套 for 循环的时间复杂度:T(n) = O(n*n)

  • 空间复杂度

空间复杂度:是运行完一个程序所需要的内存的大小。

此处所占空间包括了存储算法本身所需要的空间,输入与输出数据所占空间,以及一些临时变量(比如上面的h)所占用的空间。一般而言,我们只比较额外空间,来比较算法的空间优越性。

冒泡排序的临时变量所占空间不随处理数据n的大小改变而改变,则空间复杂度为O(1)。

二、算法步骤

  1. 从第一个元素开始;

  2. 比较相邻元素,如果第一个元素大于第二个元素,则交换两元素;

  3. 依此执行步骤 2 。最后的元素会是最大的数。

  4. 对剩余的元素循环执行步骤1、2、3;

  5. 直到没有可交换的元素为止,则排序结束;

三、图示

借用网络动图;

bubble_sort

四、源代码(go语言实现)

实现了最简单的冒泡,和添加标识位的冒泡;

package main

import (
	"fmt"
	"time"
)

// 最简排序
func bubbleSort1(order []int) {
	defer calcTime(time.Now())

	order_len := len(order)
	if order_len < 2 {
		return
	}

	for i := 0; i < order_len-1; i++ {
		for j := 0; j < order_len-i-1; j++ {
			if order[j] > order[j+1] {
				order[j], order[j+1] = order[j+1], order[j]
			}
			fmt.Printf("<%d-%d> %v\r\n", i, j, order)
		}
	}
}

// 添加 升降序控制、排序完成标识
func bubbleSort2(order []int, asc bool) {
	defer calcTime(time.Now())

	order_len := len(order)
	if order_len < 2 {
		return
	}

	flag_order := true // 已排序完成标识

	for i := 0; i < order_len-1; i++ {
		for j := 0; j < order_len-i-1; j++ {
			if (asc && order[j] > order[j+1]) || (!asc && order[j] < order[j+1]) {
				order[j], order[j+1] = order[j+1], order[j] // 这种交换方式真是方便
				flag_order = false
			} else {
				continue
			}
			fmt.Printf("<%d-%d> %v\r\n", i, j, order)
		}

		if flag_order {
			return
		}

		flag_order = true
	}
}

func main() {
	order := []int{12, 34, 0, 6, 89, 67, 78, 56}
	bubbleSort1(order)

	order = []int{12, 34, 0, 6, 89, 67, 78, 56}
	fmt.Printf("<%d-%d> %v\r\n", 0, 0, order)
	bubbleSort2(order, true)
}

// 计算函数执行事件
func calcTime(start time.Time) {
	fmt.Printf("===【cost time: %v】===\r\n", time.Since(start))
}

五、输出结果

  1. 打印了每次交换元素后的序列,以观察具体的元素交换细节;
  2. 同时打印两个排序函数的执行时间,用作对比;
# 执行结果
# 添加控制之后的冒泡函数在序列相对整齐的情况下,消耗时间明显短于普通的冒泡函数
<0-0> [12 34 0 6 89 67 78 56]
<0-1> [12 0 34 6 89 67 78 56]
<0-2> [12 0 6 34 89 67 78 56]
<0-3> [12 0 6 34 89 67 78 56]
<0-4> [12 0 6 34 67 89 78 56]
<0-5> [12 0 6 34 67 78 89 56]
<0-6> [12 0 6 34 67 78 56 89]
<1-0> [0 12 6 34 67 78 56 89]
<1-1> [0 6 12 34 67 78 56 89]
<1-2> [0 6 12 34 67 78 56 89]
<1-3> [0 6 12 34 67 78 56 89]
<1-4> [0 6 12 34 67 78 56 89]
<1-5> [0 6 12 34 67 56 78 89]
<2-0> [0 6 12 34 67 56 78 89]
<2-1> [0 6 12 34 67 56 78 89]
<2-2> [0 6 12 34 67 56 78 89]
<2-3> [0 6 12 34 67 56 78 89]
<2-4> [0 6 12 34 56 67 78 89]
<3-0> [0 6 12 34 56 67 78 89]
<3-1> [0 6 12 34 56 67 78 89]
<3-2> [0 6 12 34 56 67 78 89]
<3-3> [0 6 12 34 56 67 78 89]
<4-0> [0 6 12 34 56 67 78 89]
<4-1> [0 6 12 34 56 67 78 89]
<4-2> [0 6 12 34 56 67 78 89]
<5-0> [0 6 12 34 56 67 78 89]
<5-1> [0 6 12 34 56 67 78 89]
<6-0> [0 6 12 34 56 67 78 89]
===【cost time: 217.854µs】===
<0-0> [12 34 0 6 89 67 78 56]
<0-1> [12 0 34 6 89 67 78 56]
<0-2> [12 0 6 34 89 67 78 56]
<0-4> [12 0 6 34 67 89 78 56]
<0-5> [12 0 6 34 67 78 89 56]
<0-6> [12 0 6 34 67 78 56 89]
<1-0> [0 12 6 34 67 78 56 89]
<1-1> [0 6 12 34 67 78 56 89]
<1-5> [0 6 12 34 67 56 78 89]
<2-4> [0 6 12 34 56 67 78 89]
===【cost time: 99.877µs】===

Process finished with exit code 0

六、总结

冒泡排序是一种简单、易理解的排序算法,对理解程序的时间复杂度和空间复杂度很有帮助,也有助于理解其它排序算法;

特别是在毕业入职面试中,是面试官很喜欢问出的一道题目。


——2019-02-28——

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值