排序算法是计算机科学中的一个重要概念,它是一种将一个无序的数列重新排列成有序的方法。常见的排序算法有:
选择排序(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)
}