Go实现十大排序算法

Olivia的小跟班 Lv3

题记

排序算法是《数据结构与算法》中最基本的算法之一。

排序算法可以分为内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部的排序记录,在排序过程中需要访问外存。常见的内部排序算法有:插入排序、希尔排序、选择排序、冒泡排序、归并排序、快速排序、堆排序、基数排序等。

img

1.冒泡排序

比较相邻的元素。如果第一个比第二个大,就交换他们两个。

对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。

针对所有的元素重复以上的步骤,除了最后一个。

持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package main

import "fmt"

func main() {
var arr []int
arr = []int{1, 9, 7, 8, 4, 5, 6, 2, 1, 0}
arr = Bubblesort(arr)
fmt.Println(arr)
}

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

2.选择排序

首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置。

再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。

重复第二步,直到所有元素均排序完毕。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package main

import "fmt"

func main() {
var arr []int
arr = []int{1, 9, 7, 8, 4, 5, 6, 2, 1, 0}
arr = selectionSort(arr)
fmt.Println(arr)
}

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

3.插入排序

将第一待排序序列第一个元素看做一个有序序列,把第二个元素到最后一个元素当成是未排序序列。

从头到尾依次扫描未排序序列,将扫描到的每个元素插入有序序列的适当位置。(如果待插入的元素与有序序列中的某个元素相等,则将待插入元素插入到相等元素的后面。)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package main

import "fmt"

func main() {
var arr []int
arr = []int{1, 9, 7, 8, 4, 5, 6, 2, 1, 0}
arr = insertionSort(arr)
fmt.Println(arr)
}

func insertionSort(arr []int) []int {
for i := range arr {
preIndex := i - 1
current := arr[i]
for preIndex >= 0 && arr[preIndex] > current {
arr[preIndex+1] = arr[preIndex]
preIndex -= 1
}
arr[preIndex+1] = current
}
return arr
}

4.希尔排序

选择一个增量序列 t1,t2,……,tk,其中 ti > tj, tk = 1;

按增量序列个数 k,对序列进行 k 趟排序;

每趟排序,根据对应的增量 ti,将待排序列分割成若干长度为 m 的子序列,分别对各子表进行直接插入排序。仅增量因子为 1 时,整个序列作为一个表来处理,表长度即为整个序列的长度。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package main

func shellSort(array []int, length int) {
for gap := length / 2; gap > 0; gap = gap / 2 {
for i := gap; i < length; i++ {
var j = i
for {
if j-gap < 0 || array[j] >= array[j-gap] {
break
}
swap(array, j, j-gap)
j = j - gap
}
}
}
}

func swap(array []int, a int, b int) {
array[a] = array[a] + array[b]
array[b] = array[a] - array[b]
array[a] = array[a] - array[b]
}

5.归并排序

  1. 申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列;
  2. 设定两个指针,最初位置分别为两个已经排序序列的起始位置;
  3. 比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置;
  4. 重复步骤 3 直到某一指针达到序列尾;
  5. 将另一序列剩下的所有元素直接复制到合并序列尾。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
package main

func mergeSort(arr []int) []int {
length := len(arr)
if length < 2 {
return arr
}
middle := length / 2
left := arr[:middle]
right := arr[middle:]
return merge(mergeSort(left), mergeSort(right))
}

func merge(left []int, right []int) []int {
var result []int
for len(left) != 0 && len(right) != 0 {
if left[0] < right[0] {
result = append(result, left[0])
left = left[1:]
} else {
result = append(result, right[0])
right = right[1:]
}
}
for len(left)!=0{
result = append(result, left[0])
left = left[1:]
}
for len(right)!=0{
result = append(result, right[0])
right = right[1:]
}
return result
}

6.快速排序

  1. 从数列中挑出一个元素,称为 “基准”(pivot);
  2. 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作;
  3. 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
func partition(nums []int, left int, right int) int {
value := nums[left] // 基准值
for left < right {
for nums[right] >= value && left < right { // 依次查找大于等于基准值的位置
right--
}
nums[left] = nums[right]
for nums[left] < value && left < right { // 依次查找小于基准值的位置
left++
}
nums[right] = nums[left]
}
nums[left] = value
// 最终 left == right 就是基准值的位置
return left
}

func QuickSort(list []int, left int, right int) {
if left < right {
middle := partition(list, left, right)
QuickSort(list, left, middle-1)
QuickSort(list, middle+1, right)
}
}

7.堆排序

  1. 创建一个堆 H[0……n-1];
  2. 把堆首(最大值)和堆尾互换;
  3. 把堆的尺寸缩小 1,并调用 shift_down(0),目的是把新的数组顶端数据调整到相应位置;
  4. 重复步骤 2,直到堆的尺寸为 1。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
func heapSort(arr []int) []int {
arrLen := len(arr)
buildMaxHeap(arr, arrLen)
for i := arrLen - 1; i >= 0; i-- {
swap(arr, 0, i)
arrLen -= 1
heapify(arr, 0, arrLen)
}
return arr
}

func buildMaxHeap(arr []int, arrLen int) {
for i := arrLen / 2; i >= 0; i-- {
heapify(arr, i, arrLen)
}
}

func heapify(arr []int, i, arrLen int) {
left := 2*i + 1
right := 2*i + 2
largest := i
if left < arrLen && arr[left] > arr[largest] {
largest = left
}
if right < arrLen && arr[right] > arr[largest] {
largest = right
}
if largest != i {
swap(arr, i, largest)
heapify(arr, largest, arrLen)
}
}

func swap(arr []int, i, j int) {
arr[i], arr[j] = arr[j], arr[i]
}

8.计数排序

(1)找出待排序的数组中最大和最小的元素

(2)统计数组中每个值为i的元素出现的次数,存入数组C的第i项

(3)对所有的计数累加(从C中的第一个元素开始,每一项和前一项相加)

(4)反向填充目标数组:将每个元素i放在新数组的第C(i)项,每放一个元素就将C(i)减去1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
func countingSort(arr []int, maxValue int) []int {
bucketLen := maxValue + 1
bucket := make([]int, bucketLen) // 初始为0的数组
sortedIndex := 0
length := len(arr)
for i := 0; i < length; i++ {
bucket[arr[i]] += 1
}
for j := 0; j < bucketLen; j++ {
for bucket[j] > 0 {
arr[sortedIndex] = j
sortedIndex += 1
bucket[j] -= 1
}
}
return arr
}

9.桶排序

  • 将数组的元素按照最高位依次放入到不同的桶内
  • 桶内按照大小排序
  • 桶内元素依次输入到数组中
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
func Bucket(arr []int) {
//将数组装入桶中
bucket := make(map[int][]int)
for _, val := range arr {
bucket[val/10] = append(bucket[val/10], val)
}

//各个桶内进行从小到大排序
for _, val := range bucket {
sort.Ints(val)
}

//由于map无序,因此需要获取map的key的有序集合
var keys []int
for key := range bucket {
keys = append(keys, key)
}
sort.Ints(keys)


//桶内元素转入数组中
index := 0
for _, key := range keys {
for _, val := range bucket[key] {
arr[index] = val
index++
}
}
}

10.基数排序

image-20230327171555757

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
func radixSort(arr []int) []int {
if len(arr) == 0 {
return arr
}

// 计算最大值,并确定要进行几轮基数排序
maxVal := arr[0]
for i := 1; i < len(arr); i++ {
if arr[i] > maxVal {
maxVal = arr[i]
}
}
rounds := int(math.Ceil(math.Log10(float64(maxVal))))

// 依次对每一位进行基数排序
for i := 0; i < rounds; i++ {
buckets := make([][]int, 10)
for _, num := range arr {
digit := (num / int(math.Pow(10, float64(i)))) % 10
buckets[digit] = append(buckets[digit], num)
}
arr = make([]int, 0, len(arr))
for j := 0; j < 10; j++ {
arr = append(arr, buckets[j]...)
}
}

return arr
}
  • 标题: Go实现十大排序算法
  • 作者: Olivia的小跟班
  • 创建于 : 2023-01-02 15:03:32
  • 更新于 : 2023-05-27 04:01:14
  • 链接: https://www.youandgentleness.cn/2023/01/02/Go实现十大排序算法/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论