排序算法之冒泡排序

什么是冒泡排序

冒泡排序是一种简单直观的排序算法,它重复地遍历待排序的元素序列,依次比较相邻的两个元素,如果它们的顺序不符合排序规则(例如升序排序时,前面的元素大于后面的元素),则交换它们的位置。通过一轮的遍历,最大(或最小)的元素就会沉到序列的最后(或最前),接着对剩余的元素重复这个过程,直到整个序列有序。

基本原理

以下是冒泡排序的基本原理:

  1. 比较相邻元素: 从头开始,比较相邻的两个元素,如果它们的顺序不符合排序规则,则交换它们的位置。
  2. 一轮遍历: 重复上述比较和交换的过程,直到遍历到数组的倒数第二个元素(第 n-1 个元素),这样就确保了最后一个元素在当前轮次中已经是最大(或最小)的。
  3. 多轮遍历: 继续进行多轮的遍历,每一轮都会将当前轮次中的最大(或最小)元素沉到序列的最后(或最前),直到所有元素都有序。

冒泡排序的时间复杂度为 O(n^2),其中 n 是待排序序列的长度。它是一种稳定的排序算法,即相等元素的相对位置在排序前后不会改变。尽管冒泡排序简单,但在大部分情况下,它的性能通常较差,因为它需要进行多次遍历和交换操作。

记住一句话:每冒泡一次,即使最大值沉底。

冒泡排序优化

虽然冒泡排序在实现上简单,但是它的性能并不理想,特别是对于大规模数据集。然而,我们可以对冒泡排序进行一些优化,以提高其性能,主要包括以下几种优化方式:

1. 提前终止: 如果在某一轮遍历中没有发生任何元素交换,说明序列已经有序,可以提前结束排序过程。

2. 记录最后交换位置: 在每一轮遍历中,记录最后一次发生元素交换的位置,这个位置之后的元素已经有序,可以作为下一轮遍历的结束位置。
package main

import "fmt"

func bubbleSort(arr []int) {
	n := len(arr)
	for i := 0; i < n-1; i++ {
		for j := 0; j < n-1-i; j++ {
			if arr[j] > arr[j+1] {
				arr[j], arr[j+1] = arr[j+1], arr[j]
			}
		}
	}
}

func bubbleSort1(arr []int) {
	// 优化1:提前终止
	n := len(arr)
	for i := 0; i < n-1; i++ {
		flagend := true // 提前终止标记
		for j := 0; j < n-1-i; j++ {
			if arr[j] > arr[j+1] {
				arr[j], arr[j+1] = arr[j+1], arr[j]
				flagend = false
			}
		}
		if flagend {
			break
		}
	}
}

func bubbleSort2(arr []int) {
	// 优化2:提前终止 + 记录最后交换位置
	n := len(arr)
	for i := 0; i < n-1; i++ {
		flagend := true // 提前终止标记
		swapIdx := 0    // 记录最后交换位置
		k := n - 1
		fmt.Printf("第%v轮\n", i)
		for j := 0; j < k; j++ {
			if arr[j] > arr[j+1] {
				arr[j], arr[j+1] = arr[j+1], arr[j]
				flagend = false
				swapIdx = j
			}

			fmt.Println(arr, swapIdx)
		}

		if flagend {
			break
		}

		k = swapIdx // 下一轮遍历的结束位置
	}
}

func main() {
	arr := []int{64, 34, 25, 22, 11, 90, 23, 54, 12, 87}

	fmt.Println("排序前:", arr) // 排序前

	bubbleSort2(arr)

	fmt.Println("排序后:", arr)

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值