今天闲的无聊,回忆一下算法:
- 插入排序(直接插入排序)
- 二分插入排序算法
- 希尔排序算法
插入排序(直接插入排序)
基本思想
将一个记录插入到已排序好的有序表中,从而得到一个新且记录数增1的有序表。即:先将序列的第1个记录看成是一个有序的子序列,然后从第2个记录逐个进行插入,直至整个序列有序为止。(要点:设立哨兵,作为临时存储和判断数组边界之用)
代码
package main
import (
"fmt"
"math/rand"
)
func InsertSort(st []int) []int {
if len(st) <= 1 {
return st
}
for i := 1; i < len(st); i++ {
back := st[i]
j := i - 1
for j >= 0 && back < st[j] {
st[j+1] = st[j]
j--
}
st[j+1] = back
}
return st
}
func main() {
r := rand.New(rand.NewSource(time.Now().UnixNano()))
var list []int
for i := 0; i < 100; i++ {
list = append(list, r.Intn(100))
}
fmt.Println(InsertSort(list))
}
二分插入排序算法
基本思想
也是插入排序算法的一种,其基本思想是:引入二分查找的思想,在直接插入排序的基础上减少比较次数,从而更快的找到插入位置。
二分插入排序只是减少元素比较次数,并没有减少元素的移动次数,其相对直接插入排序性能并未有本质提升。
时间复杂度为T(n)=O(n^2),空间复杂度为S(n)=O(1)
代码
package main
import (
"fmt"
"math/rand"
)
func EInsertSort(st []int, start, end, cur int) int {
//对比当前位置与需要排序的元素大小,返回较大值的位置
if start >= end {
if st[start] < st[cur] {
return cur
}
return start
}
mid := (start + end) / 2
//二分查找递归
if st[mid] > st[cur] {
return EInsertSort(st, start, mid, cur)
} else {
return EInsertSort(st, mid+1, end, cur)
}
}
func main() {
r := rand.New(rand.NewSource(time.Now().UnixNano()))
list := make([]int, 0)
for i := 0; i < 100; i++ {
list = append(list, r.Intn(100))
}
for i := 1; i < len(list); i++ {
p := EInsertSort(list, 0, i-1, i)
if p != i { //不等 需要插入
temp := list[i]
for j := i; j > p; j-- {
list[j], list[j-1] = list[j-1], list[j]
}
list[p] = temp
}
}
fmt.Println(list)
}
希尔排序算法
基本思想
先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序 待整个序列中的记录“基本有序”时 再对全体记录进行依次直接插入排序
- 实现简单处理增量序列 d = {n/2 ,n/4, n/8 …1}, n为要排序数的个数
- 先将要排序的一组记录按某个增量d(n/2,n为要排序数的个数)分成若干组子序列
- 每组中记录的下标相差d,对每组中元素进行直接插入排序
- 再用一个较小的增量(d/2)对它进行分组
- 在每组中再进行直接插入排序
- 继续不断缩小增量直至为1,最后使用直接插入排序完成排序
代码
package main
import (
"fmt"
"math/rand"
)
/**
希尔排序:把切片分成n个batch,对每个batch进行插入排序;然后减小batch,再对每个batch进行插入排序;直到bathc等于1
*/
func shellSort(st []int, batchSize int) {
if batchSize < 1 {
return
}
// i : 每个batch中的元素所在batch的index, 介于[0, batchSize)
for i := 0; i < batchSize; i++ {
// 用到了插入排序
for j := 1; batchSize*j+i < len(st); j++ { // j: 用来获取每个batch所在的第i个元素,拥有多少个batch
for n := j; n > 0; n-- {
pre := batchSize*(n-1) + i
next := batchSize*n + i
if st[next] < st[pre] {
st[next], st[pre] = st[pre], st[next]
}
}
}
}
shellSort(st, batchSize/2)
}
func main() {
r := rand.New(rand.NewSource(time.Now().UnixNano()))
list := make([]int, 0)
for i := 0; i < 100; i++ {
list = append(list, r.Intn(100))
}
shellSort(list, len(list)/2)
fmt.Println(list)