Go语言实现各类排序算法

排序算法是计算机科学中的一个重要概念,它是一种将一个无序的数列重新排列成有序的方法。常见的排序算法有:

选择排序(Selection Sort)

选择排序是一种简单直观的排序演算法。它的工作原理:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,,再從剩餘未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以上步骤反复执行,直到所有数据元素均排序完毕。

Go 复制代码
package main

import "fmt"

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

func main() {
    arr := []int{64, 34, 25, 12, 22, 11, 90}
    selectionSort(arr)
    fmt.Println("Sorted array is:", arr)
}

冒泡排序(Bubble Sort):

最简单的排序算法,通过重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。

Go 复制代码
package main

import "fmt"

func bubbleSort(arr []int) {
    n := len(arr)
    for i := 0; i < n-1; 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}
    bubbleSort(arr)
    fmt.Println("Sorted array is:", arr)
}

插入排序(Insertion Sort):

插入排序是一种简单直观的排序演算法。通过构建有序序列,对未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。

Go 复制代码
package main

import (
    "fmt"
)

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

func main() {
    arr := []int{64, 34, 25, 12, 22, 11, 90}
    insertSort(arr)
    fmt.Println("Sorted array is:", arr)
}

希尔排序(Shell Sort):

希尔排序是一种插入排序的改进版本。希尔排序的基本思想是使数组中的元素像是在一个具有各种尺寸的篮子里进行排序。希尔排序通过设定一个步长,将数组分为若干个子序列,然后对这些子序列分别进行插入排序。当步长为1时,希尔排序就退化为插入排序。希尔排序的步长可以选择不同的值,通常选择2的幂次方,比如1,2,4,8,16,32等。

Go 复制代码
package main

import "fmt"

func shellSort(arr []int) {
    n := len(arr)
    gap := n / 2
    for gap > 0 {
        for i := gap; i < n; i++ {
            temp := arr[i]
            j := i
            for j >= gap && arr[j-gap] > temp {
                arr[j] = arr[j-gap]
                j -= gap
            }
            arr[j] = temp
        }
        gap /= 2
    }
}

func main() {
    arr := []int{64, 34, 25, 12, 22, 11, 90}
    shellSort(arr)
    fmt.Println("Sorted array is:", arr)
}

归并排序(Merge Sort):

是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。

Go 复制代码
package main

import (
    "fmt"
    "math/rand"
)

func merge(arr []int, l, m, r int) {
    n1 := m - l + 1
    n2 := r - m

    L := make([]int, n1)
    R := make([]int, n2)

    for i := 0; i < n1; i++ {
        L[i] = arr[l+i]
    }
    for j := 0; j < n2; j++ {
        R[j] = arr[m+1+j]
    }

    i := 0
    j := 0
    k := l
    for i < n1 && j < n2 {
        if L[i] <= R[j] {
            arr[k] = L[i]
            i++
        } else {
            arr[k] = R[j]
            j++
        }
        k++
    }

    for i < n1 {
        arr[k] = L[i]
        i++
        k++
    }

    for j < n2 {
        arr[k] = R[j]
        j++
        k++
    }
}

func mergeSort(arr []int, l, r int) {
    if l < r {
        m := (l + r) / 2
        mergeSort(arr, l, m)
        mergeSort(arr, m+1, r)
        merge(arr, l, m, r)
    }
}

func main() {
    arr := []int{64, 34, 25, 12, 22, 11, 90}
    rand.Seed(42)
    for i := 0; i < len(arr); i++ {
        arr[i] = rand.Intn(100)
    }
    mergeSort(arr, 0, len(arr)-1)
    fmt.Println("Sorted array is:", arr)
}

快速排序(Quick Sort):

快速排序是一种高效的排序算法,基于分治法(Divide and Conquer)的一个策略。将要排序的数组分为两个子数组,一个包含相应的元素,一个包含其他的元素。

Go 复制代码
package main

import "fmt"

func quickSort(arr []int, left, right int) {
    if left < right {
        pivot := partition(arr, left, right)
        quickSort(arr, left, pivot-1)
        quickSort(arr, pivot+1, right)
    }
}

func partition(arr []int, left, right int) int {
    pivot := arr[right]
    i := left
    for j := left; j < right; j++ {
        if arr[j] <= pivot {
            arr[i], arr[j] = arr[j], arr[i]
            i++
        }
    }
    arr[i], arr[right] = arr[right], arr[i]
    return i
}

func main() {
    arr := []int{64, 34, 25, 12, 22, 11, 90}
    quickSort(arr, 0, len(arr)-1)
    fmt.Println("Sorted array is:", arr)
}

堆排序(Heap Sort):

是一种比较高效的选择排序,无论原址排序还是非原址排序都有其实现。

Go 复制代码
package main

import (
    "fmt"
)

func maxHeapify(arr []int, n int, i int) {
    largest := i
    l := 2*i + 1
    r := 2*i + 2

    if l < n && arr[l] > arr[largest] {
        largest = l
    }

    if r < n && arr[r] > arr[largest] {
        largest = r
    }

    if largest!= i {
        arr[i], arr[largest] = arr[largest], arr[i]
        maxHeapify(arr, n, largest)
    }
}

func heapSort(arr []int) {
    n := len(arr)
    for i := n/2 - 1; i >= 0; i-- {
        maxHeapify(arr, n, i)
    }

    for i := n - 1; i >= 0; i-- {
        arr[0], arr[i] = arr[i], arr[0]
        maxHeapify(arr, i, 0)
    }
}

func main() {
    arr := []int{64, 34, 25, 12, 22, 11, 90}
    heapSort(arr)
    fmt.Println("Sorted array is:", arr)
}

桶排序:

桶排序是计算机科学中的一种排序算法,工作原理是将要排序的元素划分到不同的桶,然后分别对每个桶中的元素进行排序,最后将每个桶中的元素合并成一个有序的序列。

Go 复制代码
package main

import (
    "fmt"
    "math"
)

func bucketSort(arr []float64) []float64 {
    var n int = len(arr)
    var maxValue = math.Ceil(max(arr))
    var size = math.Ceil((maxValue - min(arr)) / n)
    var buckets = make([][]float64, n)

    for i := 0; i < n; i++ {
        var index = int(math.Floor(arr[i]/size))
        buckets[index] = append(buckets[index], arr[i])
    }

    for i := 0; i < n; i++ {
        insertionSort(buckets[i])
    }

    var sortedArr []float64
    for i := 0; i < n; i++ {
        for j := 0; j < len(buckets[i]); j++ {
            sortedArr = append(sortedArr, buckets[i][j])
        }
    }

    return sortedArr
}

func insertionSort(arr []float64) []float64 {
    var n = len(arr)
    for i := 1; i < n; i++ {
        var key = arr[i]
        var j = i - 1
        for j >= 0 && arr[j] > key {
            arr[j+1] = arr[j]
            j = j - 1
        }
        arr[j+1] = key
    }
    return arr
}

func min(arr []float64) float64 {
    var min = arr[0]
    for _, value := range arr {
        if value < min {
            min = value
        }
    }
    return min
}

func max(arr []float64) float64 {
    var max = arr[0]
    for _, value := range arr {
        if value > max {
            max = value
        }
    }
    return max
}

func main() {
    var arr = []float64{0.897, 0.565, 0.656, 0.1234, 0.665, 0.3434}
    var sortedArr = bucketSort(arr)
    fmt.Println("Sorted array:")
    for _, value := range sortedArr {
        fmt.Printf("%.3f ", value)
    }
}

计数排序:

计数排序是一种线性时间复杂度的排序算法,这种算法对输入的数据有一定的限制,如它们都是非负整数。计数排序是一种非比较排序算法,其核心思想是将输入的数据值转化为键存储在额外开辟的数组空间中。当输入数据是非负整数时,计数排序是一个线性时间排序算法。

Go 复制代码
package main

import "fmt"

func countSort(arr []int) []int {
    max := arr[0]
    min := arr[0]

    // 找到数组中的最大和最小值
    for _, v := range arr {
        if v > max {
            max = v
        }
        if v < min {
            min = v
        }
    }

    // 初始化计数数组
    count := make([]int, max-min+1)

    // 计算每个元素的数量
    for _, v := range arr {
        count[v-min]++
    }

    // 修改计数数组,使得每个元素的值表示该元素在数组中的位置
    for i := 1; i < len(count); i++ {
        count[i] += count[i-1]
    }

    // 创建一个结果数组,每个元素的位置由计数数组决定
    output := make([]int, len(arr))
    for i := len(arr) - 1; i >= 0; i-- {
        output[count[arr[i]-min]-1] = arr[i]
        count[arr[i]-min]--
    }

    return output
}

func main() {
    arr := []int{10, 20, 7, 8, 9, 1, 5}
    fmt.Println("Sorted array:")
    fmt.Println(countSort(arr))
}

基数排序:

基数排序是一种非比较整数排序算法,其原理是将整数按位数切割成不同的数字,然后按每个位数分别比较。通常适用于对小范围整数的排序。将整个整数(例如名字或日期)中的每个数字或字母类似于排序每个单独的数字。

Go 复制代码
package main

import (
    "fmt"
    "math"
)

func countingSort(arr []int, exp int) {
    n := len(arr)
    output := make([]int, n)
    count := make([]int, 10)

    for i := 0; i < n; i++ {
        index := (arr[i] / exp) % 10
        count[index]++
    }

    for i := 1; i < 10; i++ {
        count[i] += count[i-1]
    }

    for i := n - 1; i >= 0; i-- {
        index := (arr[i] / exp) % 10
        output[count[index]-1] = arr[i]
        count[index]--
    }

    for i := 0; i < n; i++ {
        arr[i] = output[i]
    }
}

func radixsort(arr []int) {
    max := getMax(arr)

    for exp := 1; max/exp > 0; exp *= 10 {
        countingSort(arr, exp)
    }
}

func getMax(arr []int) int {
    max := math.Inf(-1)
    for _, num := range arr {
        if num > max {
            max = num
        }
    }
    return int(max)
}

func print(arr []int) {
    for _, num := range arr {
        fmt.Print(num, " ")
    }
    fmt.Println()
}

func main() {
    arr := []int{170, 45, 75, 90, 802, 24, 2, 66}
    radixsort(arr)
    print(arr)
}

斐波那契排序:

这是一个对冒泡排序的改进,通过引入斐波那契数列的概念,减少了比较的次数。工作原理是通过两层循环,外层循环控制整个排序过程,内层循环控制每一轮的排序。如果前一个元素大于后一个元素,就交换它们的位置。这样一轮比较下来,最大的元素就会移动到它应该在的位置上。

Go 复制代码
package main

import "fmt"

func swap(a *int, b *int) {
    *a, *b = *b, *a
}

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

func main() {
    arr := []int{5, 8, 1, 3, 9, 6}
    fbSort(arr)
    fmt.Println("Sorted array:")
    for _, i := range arr {
        fmt.Println(i)
    }
}

哈夫曼排序:

哈夫曼排序是一种优先队列排序,它的基本思想是将待排序的序列看作是一棵完全二叉树,然后从上到下和从左到右进行排序。

Go 复制代码
package main

import (
    "fmt"
    "container/heap"
)

type Node struct {
    Value int
    Key   int
}

type PriorityQueue []*Node

func (pq PriorityQueue) Len() int { return len(pq) }

func (pq PriorityQueue) Less(i, j int) bool {
    return pq[i].Key < pq[j].Key
}

func (pq PriorityQueue) Swap(i, j int) {
    pq[i], pq[j] = pq[j], pq[i]
}

func (pq *PriorityQueue) Push(x interface{}) {
    item := x.(*Node)
    *pq = append(*pq, item)
}

func (pq *PriorityQueue) Pop() interface{} {
    old := *pq
    n := len(old)
    item := old[n-1]
    *pq = old[0 : n-1]
    return item
}

func huffmanCodes(freq []int) {
    pq := make(PriorityQueue, 0)
    heap.Init(&pq)
    for i, val := range freq {
        if val > 0 {
            heap.Push(&pq, &Node{val, val, i})
        }
    }
    for pq.Len() > 1 {
        left := heap.Pop(&pq).(*Node)
        right := heap.Pop(&pq).(*Node)
        heap.Push(&pq, &Node{left.Key + right.Key, left.Key, left.Value})
        heap.Push(&pq, &Node{left.Key + right.Key, right.Key, right.Value})
    }
    fmt.Println(pq)
}

func main() {
    freq := []int{5, 9, 12, 13, 16, 45}
    huffmanCodes(freq)
}
相关推荐
明志刘明44 分钟前
昇思量子计算系列教程-龙算法
深度学习·算法·量子计算
დ旧言~1 小时前
刷题训练之栈
算法
fieldsss1 小时前
动态规划part 06
算法·动态规划
kuilaurence1 小时前
C语言数组学习
c语言·学习·算法
LG.YDX1 小时前
数据结构:(OJ141)环形列表
数据结构
郭源潮11 小时前
【C++二叉树】二叉树的前序遍历、中序遍历、后序遍历递归与非递归实现
开发语言·c++·算法
请揣满RMB1 小时前
BFS 解决多源最短路问题
算法·宽度优先
Mephisto.java2 小时前
【数据结构与算法 | 灵神题单 | 二叉搜索树篇】力扣653
算法·leetcode·职场和发展
sjsjs112 小时前
【贪心】【数据结构-小根堆,差分】力扣2406. 将区间分为最少组数
数据结构·算法·leetcode
码上一元2 小时前
【百日算法计划】:每日一题,见证成长(019)
java·数据结构·算法