什么是冒泡排序
冒泡排序是一种简单直观的排序算法,它重复地遍历待排序的元素序列,依次比较相邻的两个元素,如果它们的顺序不符合排序规则(例如升序排序时,前面的元素大于后面的元素),则交换它们的位置。通过一轮的遍历,最大(或最小)的元素就会沉到序列的最后(或最前),接着对剩余的元素重复这个过程,直到整个序列有序。
基本原理
以下是冒泡排序的基本原理:
- 比较相邻元素: 从头开始,比较相邻的两个元素,如果它们的顺序不符合排序规则,则交换它们的位置。
- 一轮遍历: 重复上述比较和交换的过程,直到遍历到数组的倒数第二个元素(第 n-1 个元素),这样就确保了最后一个元素在当前轮次中已经是最大(或最小)的。
- 多轮遍历: 继续进行多轮的遍历,每一轮都会将当前轮次中的最大(或最小)元素沉到序列的最后(或最前),直到所有元素都有序。
冒泡排序的时间复杂度为 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)
}