I排序算法.go

前言:在计算机科学中,排序算法是一个重要且基础的主题。

目录

选择排序:挑挑拣拣选出最小的!

插入排序:像插队一样插入正确的位置!

快速排序:分治法的高手!

归并排序:合并的艺术!

总结


冒泡排序,一听这名字就很有画面感,就像小泡泡在水里往上冒一样。它的原理很简单,就是把数组里的元素两两比较,把大的那个往后冒,这样经过一轮比较,最大的元素就 "冒" 到最后面了。

  • 算法原理 :从第一个元素开始,比较相邻两个元素,如果前者大于后者(假设是升序),则交换它们的位置。遍历一遍后,最大的元素会沉到数组末尾。重复上述过程,未排序部分的长度每次减少 1,直到整个数组有序。

先看代码:

Go 复制代码
package main

import "fmt"

func BubbleSort(arr []int) {
    n := len(arr)
    for i := 0; i < n-1; i++ { // 这是第i轮冒泡
        for j := 0; j < n-i-1; j++ { // 每轮比较的次数逐渐减少
            if arr[j] > arr[j+1] { // 如果前一个比后一个大,就交换
                arr[j], arr[j+1] = arr[j+1], arr[j]
            }
        }
    }
}

func main() {
    arr := []int{64, 34, 25, 12, 22, 11, 90} // 这是我们要排序的数组
    fmt.Println("原数组:", arr) // 先看看原数组长什么样
    BubbleSort(arr) // 开始冒泡排序啦!
    fmt.Println("排序后的数组:", arr) // 看看排序后的效果
}

咱来聊聊这个算法。冒泡排序的平均时间复杂度是 O(n²),最坏情况也是 O(n²),所以它适合小规模数据的排序。不过,它的优点是实现简单,代码量少,理解起来也容易。就像你去小卖部买包口香糖,虽然口香糖不贵,但也能解解馋。

选择排序:挑挑拣拣选出最小的!

选择排序就像你去商场买东西,你得在一堆商品里找出最便宜的那个。它的原理是:从数组的第 i 个位置开始,找到后面所有元素中的最小值,和第 i 个元素交换。

  • 算法原理 :从数组第一个元素开始,假设第一个元素是最小值,然后依次与后面元素比较。如果找到更小的元素,就更新最小值的索引。遍历完未排序部分后,将最小值和未排序部分的第一个元素交换位置。重复这一过程,直到整个数组有序。

代码别走开,这就来:

Go 复制代码
package main

import "fmt"

func SelectionSort(arr []int) {
    n := len(arr)
    for i := 0; i < n-1; i++ { // 这是第i次选择
        minIndex := i // 假设当前元素是最小的
        for j := i + 1; j < n; j++ { // 找找看有没有更小的
            if arr[j] < arr[minIndex] {
                minIndex = j // 更新最小值的索引
            }
        }
        arr[i], arr[minIndex] = arr[minIndex], arr[i] // 把最小值放到前面
    }
}

func main() {
    arr := []int{64, 25, 12, 22, 11} // 这是我们的数组
    fmt.Println("原数组:", arr) // 瞧一瞧原数组
    SelectionSort(arr) // 开始选择排序之旅
    fmt.Println("排序后的数组:", arr) // 看看排序后的模样
}

这个算法也挺简单的,时间复杂度是 O(n²),和冒泡排序差不多。不过,它的交换次数比冒泡排序少,因为每次找到最小值才交换一次。这就像是你在网上购物,虽然花了不少时间挑拣,但最终只下单买了一样东西。

插入排序:像插队一样插入正确的位置!

插入排序就像是你在排队买电影票,新来的人要找到合适的位置插入进去,不然就会被后面的人吐槽。这个算法的原理是:把数组分成已排序区和未排序区,然后从未排序区里挑一个元素,在已排序区里找合适的位置插入。

  • 算法原理 :从第二个元素开始,把它与前面的有序子数组依次比较。如果比前面的元素小,就交换位置,直到找到合适的位置插入。

代码来了:

Go 复制代码
package main

import "fmt"

func InsertionSort(arr []int) {
    n := len(arr)
    for i := 1; i < n; i++ { // 从未排序区开始
        key := arr[i] // 挑一个元素
        j := i - 1
        for j >= 0 && arr[j] > key { // 在已排序区找位置
            arr[j+1] = arr[j] // 比key大的元素都往后挪
            j--
        }
        arr[j+1] = key // 插入到正确的位置
    }
}

func main() {
    arr := []int{12, 11, 13, 5, 6} // 这就是我们的数组
    fmt.Println("原数组:", arr) // 原数组长啥样呢
    InsertionSort(arr) // 开始插入排序的旅程
    fmt.Println("排序后的数组:", arr) // 看看排序后的效果
}

插入排序的平均时间复杂度也是 O(n²),但在数据基本有序的情况下,它的效率很高。这就好比你去一个几乎没人排队的超市,插队都变得轻松多了。

快速排序:分治法的高手!

快速排序可是排序算法里的高手,它用分治法的思想,把数组分成两部分,左边的都比右边的小。然后对左右两部分分别排序,最后整个数组就排好序啦。

  • 算法原理 :选取一个分区点(通常可以选首元素、尾元素或中间元素),通过一次划分操作,将数组分成左右两个子数组。再对左右子数组递归进行快速排序。

上代码:

Go 复制代码
package main

import "fmt"

func QuickSort(arr []int) {
    if len(arr) <= 1 { // 如果数组只有一个元素,就不用排啦
        return
    }
    pivotIndex := partition(arr) // 找到分区点
    QuickSort(arr[:pivotIndex]) // 递归排序左边
    QuickSort(arr[pivotIndex+1:]) // 递归排序右边
}

func partition(arr []int) int {
    pivot := arr[0] // 挑一个基准元素
    j := 0
    for i := 1; i < len(arr); i++ { // 遍历数组
        if arr[i] <= pivot { // 如果比基准小
            j++ // 就放到左边
            arr[i], arr[j] = arr[j], arr[i] // 交换位置
        }
    }
    arr[0], arr[j] = arr[j], arr[0] // 把基准放到中间
    return j // 返回分区点
}

func main() {
    arr := []int{10, 7, 8, 9, 1, 5} // 我们的数组
    fmt.Println("原数组:", arr) // 原数组是啥样呢
    QuickSort(arr) // 开始快速排序啦
    fmt.Println("排序后的数组:", arr) // 看看排序后的效果
}

快速排序的平均时间复杂度是 O(n log n),在大多数情况下都很快。这就像是你开了一辆跑车,在高速公路上飞驰,效率极高。

归并排序:合并的艺术!

归并排序也是分治法的高手,它把数组分成一个个小块,然后把这些小块合并成一个有序的数组。这就像是你有几段绳子,把它们一段段地接起来,最后变成一根长长的绳子。

  • 算法原理 :将数组一分为二,分别对左右两个子数组进行归并排序。然后合并两个有序子数组。合并过程是归并排序的关键,它将两个有序数组合并成一个有序数组。

代码走一波:

Go 复制代码
package main

import "fmt"

func MergeSort(arr []int) []int {
    if len(arr) <= 1 { // 如果数组只有一个元素
        return arr // 直接返回
    }
    mid := len(arr) / 2 // 找到中间点
    left := MergeSort(arr[:mid]) // 递归排序左边
    right := MergeSort(arr[mid:]) // 递归排序右边
    return merge(left, right) // 合并两个有序数组
}

func merge(left, right []int) []int {
    result := make([]int, 0, len(left)+len(right)) // 创建一个结果数组
    i, j := 0, 0 // 定义两个指针
    for i < len(left) && j < len(right) { // 遍历两个数组
        if left[i] <= right[j] { // 如果左边的元素小
            result = append(result, left[i]) // 就放到结果里
            i++
        } else {
            result = append(result, right[j]) // 否则放右边的元素
            j++
        }
    }
    result = append(result, left[i:]...) // 把剩下的元素都放到结果里
    result = append(result, right[j:]...)
    return result
}

func main() {
    arr := []int{12, 11, 13, 5, 6, 7} // 这是我们的数组
    fmt.Println("原数组:", arr) // 原数组的样子
    sortedArr := MergeSort(arr) // 开始归并排序啦
    fmt.Println("排序后的数组:", sortedArr) // 看看排序后的效果
}

总结

Go 语言提供了简单而强大的语法来实现这些排序算法。不同的排序算法在时间复杂度、空间复杂度和稳定性等方面各有特点。在实际应用中,要根据具体场景选择合适的排序算法。例如,对于小规模数据或基本有序的数据,插入排序可能比较高效;对于大规模数据,快速排序和归并排序通常是更好的选择。理解这些排序算法的实现原理和性能特点,有助于我们更好地进行编程实践和优化。

相关推荐
mldong39 分钟前
mldong 快速开发框架登录模块设计与实现
java·后端·架构
三体世界1 小时前
HTTPS加密原理
linux·开发语言·网络·c++·网络协议·http·https
Wilber的技术分享1 小时前
【机器学习实战笔记 12】集成学习:AdaBoost算法
人工智能·笔记·算法·决策树·机器学习·分类·集成学习
我爱Jack1 小时前
@annotation:Spring AOP 的“精准定位器“
java·后端·spring
明月与玄武1 小时前
Python爬虫工作基本流程及urllib模块详解
开发语言·爬虫·python
云空1 小时前
《NuGet:.NET开发的魔法包管理器》
开发语言·.net
我崽不熬夜2 小时前
为什么你该立即学习 Java 的 Lambda 表达式?
java·后端·java ee
小怡同学..2 小时前
c++系列之智能指针的使用
开发语言·c++
黑客飓风2 小时前
JavaScript性能优化实战
开发语言·javascript·性能优化
金融小师妹2 小时前
基于LSTM-GARCH混合模型的“获利了结”量化解析:黄金单日1.27%跌幅的技术性归因
大数据·人工智能·算法