仓库码云地址
声明
本人是个菜鸟,不一定对哦。。。
我只测试一个是正确的。还有对于数组只有 一个数或者nil的不考虑。
先写一个公共的方法。替换俩个位置的数。
basicsort/tools.go
package basicsort
func swap(arr []int, i int, j int) {
temp := arr[i]
arr[i] = arr[j]
arr[j] = temp
}
01 冒泡排序
俩俩比较,大的往后冒。
俩个for循环,每次循环排好一个最大的数
basicsort/01_bubble_sort.go
package basicsort
//函数名首字母大写才能被其他包引用。
func Bubble_sort(arr []int) {
//冒泡排序
for i := len(arr) - 1; i > 0; i-- {
for j := 0; j <= i-1; j++ {
if arr[j] > arr[j+1] {
swap(arr, j, j+1)
}
}
}
}
- main.go 测试
package main
import (
"fmt"
"go-alg/basicsort"
)
func main() {
arr := []int{3, 2, 4, 5, 1, 6, 9, 8, 7, 0}
basicsort.Bubble_sort(arr)
fmt.Println(arr)
}
02 选择排序
也是俩层for循环,也是俩俩比较。但是只是记录最大的索引,循环完之后。最大的索引和当前循环到的索引替换。
package basicsort
func Select_sort(arr []int) {
for i := len(arr) - 1; i > 0; i-- {
currnet_max_index := i //记录当前循环最大的索引
for j := 0; j < i; j++ {
if arr[j] > arr[currnet_max_index] {
currnet_max_index = j
}
}
swap(arr, i, currnet_max_index) //当前索引交换最大索引
}
}
03 插入排序
就相当于打扑克,拿牌一样。前面都是已排好的序,新拿的牌从最后一张开始比较,直到找到自己插入的位置。
默认第一张是已排序。从第二张开始插入。
package basicsort
func Insert_sort(arr []int) {
for i := 1; i < len(arr); i++ {
insert_value := arr[i] // 要插入的值
var j int // j要声明到for循环之外,这是最后确定要插入的索引位置。 python不需要。
for j = i - 1; j >= 0; j-- {
if arr[j] > insert_value {
arr[j+1] = arr[j] //当前牌往后移一个。直接赋值
} else {
break
}
}
arr[j+1] = insert_value //插入到指定位置,因为for循环有一个减一操作。所以这里应该是j+1才是要插入的位置
}
}
04 希尔排序
优化的插入排序。插入排序的插入 步数是一个一个。希尔排序是一次就往前插好几个位置。慢慢回归到1. 加快 数快速移动到自己的位置。
一般是从 n/3 还是 n/2 开始 ,每次除2,慢慢到1.
多了个gap循环,插入排序多了个gap参数。每次插入比较 不是1而是gap了。
package basicsort
func Shell_sort(arr []int) {
for gap := len(arr) / 2; gap >= 1; gap /= 2 {
Insert_sort_with_gap(arr, gap)
}
}
func Insert_sort_with_gap(arr []int, gap int) {
for i := 1; i < len(arr); i++ {
insert_value := arr[i] // 要插入的值
var j int // j要声明到for循环之外,这是最后确定要插入的索引位置。 python不需要。
for j = i - gap; j >= 0; j -= gap {
if arr[j] > insert_value {
arr[j+gap] = arr[j] //当前牌往后移一个。直接赋值
} else {
break
}
}
arr[j+gap] = insert_value //插入到指定位置,因为for循环有一个减一操作。所以这里应该是j+gap才是要插入的位置
}
}
05 归并排序
分而治之,
先划分到只有1个数的数组,然后俩俩合并。
是个递归函数。
会新增内存。
package basicsort
import "fmt"
func Merge_sort(arr []int) {
if len(arr) <= 1 {
return
}
mid := len(arr) / 2
left_arr := make([]int, len(arr[:mid]))
right_arr := make([]int, len(arr[mid:]))
copy(left_arr, arr[:mid])
copy(right_arr, arr[mid:])
fmt.Println("left_arr:", left_arr)
fmt.Println("right_arr:", right_arr)
Merge_sort(left_arr) // 左边数组排序
Merge_sort(right_arr) //右边数组排序
l := 0 // 左边数组的索引
r := 0 // 右边数组的索引
c := 0 // 原始数组的索引
// 开始合并左边数组和右边数组
for l < len(left_arr) && r < len(right_arr) {
//比较当前俩个数组哪个小。
if left_arr[l] <= right_arr[r] {
arr[c] = left_arr[l]
l++
} else {
arr[c] = right_arr[r]
r++
}
c++
}
//走到这说明其中一个数组肯定没数了。把另一个数组的数依次合并到主数组
for l < len(left_arr) {
arr[c] = left_arr[l]
c++
l++
}
for r < len(right_arr) {
arr[c] = right_arr[r]
c++
r++
}
}
06 快速排序
也是递归和分而治之的思想
找一个基准数,把一个数组分成俩块,左边都是小于基准数,右边都是大于基准数的。
然后递归调用自己.
因数的顺序对时间复杂度影响较大。优化:每次随机选择基准数。
我做不到出来了;
package basicsort
func Quick_sort2(arr []int) {
help(arr, 0, len(arr)-1)
}
func help(arr []int, l int, r int) {
if l < r {
less, more := partation2(arr, l, r)
help(arr, l, less-1)
help(arr, more+1, r)
}
}
func partation2(arr []int, l int, r int) (int, int) {
less := l - 1
more := r
for l < more {
if arr[l] < arr[r] {
less++
swap(arr, less, l)
l++
} else if arr[l] > arr[r] {
more--
swap(arr, more, l)
} else {
l++
}
}
swap(arr, more, r)
return less + 1, more
}