(1)冒泡排序和其优化

一 冒泡排序

在这里插入图片描述

1.1 冒泡排序概念

冒泡排序(Bubble Sort)是一种交换排序,基本思想是:两两比较相邻记录的关键字,如果反序则交换,直到没有反序记录位置。

假设要对无序数列{2,3,4,5,6,7,8,1}排序:

冒泡排序规律:每一轮排序两两比较都会把最大的值移动到最后一位,最大值就像在不断的冒泡一样。

1.2 冒泡算法

func BubbleSort(arr []int) {

	if arr == nil || len(arr) < 2 {
		fmt.Println("数组不满足要求")
		return
	}

	// 外层循环:确定扫描的次数
	for i := 1; i <= len(arr) - 1; i++ {
		// 内层循环:一轮扫描内,两两比较,进行交换
		for j := 0; j <= len(arr) - 1 - i; j++ {	 // - i 的原因是后面的元素已经被排序过
			if arr[j] > arr[j + 1] {
				temp := arr[j]
				arr[j] = arr[j + 1]
				arr[j + 1] = temp
			}
		}
	}
}

1.3 冒泡算法优化

如果要排序的数据序列已经完全有序了,那么冒泡算法仍然会按照两两比较策略继续走下去,这是不能容忍的,我们可以先记录该数据序列是否有序,只要内层循环没有发生交换,就证明整个数组现在已经有序,无需外层循环再次排序!

func BubbleSort(arr []int) {
	if arr == nil || len(arr) < 2 {
		fmt.Println("数组不满足要求")
		return
	}
	isSorted := false
	for i := 1; i <= len(arr)-1; i++ {
		isSorted = true
		for j := 0; j < len(arr)-1-i; j++ {
			if arr[j] > arr[j+1] {
				temp := arr[j+1]
				arr[j+1] = arr[j]
				arr[j] = temp
				isSorted = false
			}
		}
		if isSorted {
			break
		}
	}
}

1.4 冒泡排序优化二

显然数据的完全有序概率是很低的,但是数据局部有序的情况概率还是很高的。如果如果最后几个元素都已经是排好的,那么这几个局部有序的数据就无需进行冒泡排序了,如:arr := []int{3, 2, 4, 1, 6, 0, 5, 7, 8, 9}。在1.3优化一的基础上,我们可以通过记录最后一次排序比较的索引,来继续优化:

func BubbleSort(arr []int) {

	if arr == nil || len(arr) < 2 {
		fmt.Println("数组不满足要求")
		return
	}

	isSorted := false
	sortIndex := len(arr) - 1 - 1
	lastIndex := 0 // 记录最后一次交换的位置
	for i := 1; i <= len(arr)-1; i++ {
		isSorted = true
		for j := 0; j <= sortIndex; j++ {
			if arr[j] > arr[j+1] {			// 不能加入等号,这样会造成不稳定
				temp := arr[j]
				arr[j] = arr[j+1]
				arr[j+1] = temp
				isSorted = false
				lastIndex = j
			}
		}
		if isSorted {
			break
		}
		sortIndex = lastIndex
	}
}

二 冒泡排序复杂度分析

  • 最好情况:数据本身是有序的,那么其时间复杂度应该是O(n)
  • 最坏情况:表中所有的元素都是逆序的,时间复杂度为O(n^2)。

三 扩展:鸡尾酒排序

冒泡排序的每一轮都是从左到右比较,进行单向的位置交换。鸡尾酒排序则可以让比较和交换的过程是双向的。

对1.1图中的序列进行冒泡排序会造成大量浪费,鸡尾酒排序则很容易实现:

也就是说鸡尾酒的排序过程像钟摆一样,奇数轮和偶数轮来回排序,第1轮从左往右,第2轮从右往左,第3轮再从左往右,直到有一轮排序时没有发生交换,则退出循环。

我们也不难发现:当一个无需数列中,大多元素都有序的时,使用鸡尾酒排序则能达到很好的效果。

  • 10
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值