缘起
最近阅读<<我的第一本算法书>>(【日】石田保辉;宫崎修一)
本系列笔记拟采用golang练习之
选择排序
选择排序就是重复“从待排序的数据中寻找最小值,将其与序列最左边的数字进行交换”这一操作的算法。在序列中寻找最小值时使用的是线性查找。选择排序的时间复杂度也和冒泡排序的一样,都为O(n^2)。摘自 <<我的第一本算法书>> 【日】石田保辉;宫崎修一
流程
- 给定待排序数组data[N]
- 设定目标位置i = 0
- 获取n = min(data, i), 即[0-N)区间的最小值的下标
- 判断n是否等于i, 否则交换n, i的数值, 也就是把最小值放到i的位置
- i++
- 循环3-5步, 直到i == N-1
目标
- 实现并测试选择排序
- 通过定义比较函数兼容任意值类型
- 通过调整比较函数实现倒序输出
设计
- ISorter: 定义排序算法接口, 以及值比较函数
- tSelectSorter: 选择排序的实现. 内部定义min函数, 线性查找数组中指定区间的最小值的下标.
单元测试
select_sort_test.go, 测试过程与冒泡排序基本一致. 从测试结果看, 比冒泡排序快近一倍
package sortingimport ("fmt""learning/gooop/sorting""learning/gooop/sorting/select_sort""math/rand""testing""time")func Test_SelectSort(t *testing.T) {fnAssertTrue := func(b bool, msg string) {if !b {t.Fatal(msg)}}reversed := falsefnCompare := func(a interface{}, b interface{}) sorting.CompareResult {i1 := a.(int)i2 := b.(int)if i1 < i2 {if reversed {return sorting.GREATER} else {return sorting.LESS}} else if i1 == i2 {return sorting.EQUAL} else {if reversed {return sorting.LESS} else {return sorting.GREATER}}}sorter := select_sort.SelectSorter// test 10000 items sortingrnd := rand.New(rand.NewSource(time.Now().UnixNano()))sampleCount := 10000t.Logf("prepare large array with %v items", sampleCount)samples := make([]interface{}, sampleCount)for i := 0;i < sampleCount;i++ {samples[i] = rnd.Intn(sampleCount*10)}t.Log("sorting large array")t0 := time.Now().UnixNano()sorter.Sort(samples, fnCompare)cost := time.Now().UnixNano() - t0for i := 1;i < sampleCount;i++ {fnAssertTrue(fnCompare(samples[i-1], samples[i]) != sorting.GREATER, "expecting <=")}t.Logf("end sorting large array, cost = %v ms", cost / 1000000)// test 0-20sampleCount = 20t.Log("sorting 0-20")samples = make([]interface{}, sampleCount)for i := 0;i < sampleCount;i++ {for {p := rnd.Intn(sampleCount)if samples[p] == nil {samples[p] = ibreak}}}t.Logf("unsort = %v", samples)sorter.Sort(samples, fnCompare)t.Logf("sorted = %v", samples)fnAssertTrue(fmt.Sprintf("%v", samples) == "[0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19]", "expecting 0-20")t.Log("pass sorting 0-20")// test specialsamples = []interface{} {}sorter.Sort(samples, fnCompare)t.Log("pass sorting []")samples = []interface{} { 1 }sorter.Sort(samples, fnCompare)t.Log("pass sorting [1]")samples = []interface{} { 3,1 }sorter.Sort(samples, fnCompare)fnAssertTrue(fmt.Sprintf("%v", samples) == "[1 3]", "expecting 1,3")t.Log("pass sorting [1 3]")samples = []interface{} { 2,3,1 }sorter.Sort(samples, fnCompare)fnAssertTrue(fmt.Sprintf("%v", samples) == "[1 2 3]", "expecting 1,2,3")t.Log("pass sorting [1 2 3]")reversed = truesorter.Sort(samples, fnCompare)fnAssertTrue(fmt.Sprintf("%v", samples) == "[3 2 1]", "expecting 3,2,1")t.Log("pass sorting [3 2 1]")}
测试输出
从测试结果看, 比冒泡排序快近一倍
$ go test -v select_sort_test.go=== RUN Test_SelectSortselect_sort_test.go:46: prepare large array with 10000 itemsselect_sort_test.go:52: sorting large arrayselect_sort_test.go:59: end sorting large array, cost = 293 msselect_sort_test.go:63: sorting 0-20select_sort_test.go:74: unsort = [19 6 15 14 16 2 5 11 12 18 8 3 17 4 10 7 1 13 9 0]select_sort_test.go:77: sorted = [0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19]select_sort_test.go:79: pass sorting 0-20select_sort_test.go:84: pass sorting []select_sort_test.go:88: pass sorting [1]select_sort_test.go:93: pass sorting [1 3]select_sort_test.go:98: pass sorting [1 2 3]select_sort_test.go:103: pass sorting [3 2 1]--- PASS: Test_SelectSort (0.29s)PASSok command-line-arguments 0.297s
ISorter.go
定义排序算法接口, 以及值比较函数
package sortingtype ISorter interface {Sort(data []interface{}, comparator CompareFunction) []interface{}}type CompareFunction func(a interface{}, b interface{}) CompareResulttype CompareResult intconst LESS CompareResult = -1const EQUAL CompareResult = 0const GREATER CompareResult = 1
tSelectSorter.go
选择排序的实现. 内部定义min函数, 线性查找数组中指定区间的最小值的下标.
package select_sortimport "learning/gooop/sorting"type tSelectSorter struct {}func newSelectSorter() sorting.ISorter {return &tSelectSorter{}}// 选择排序func (me *tSelectSorter) Sort(data []interface{}, comparator sorting.CompareFunction) []interface{} {if data == nil {return nil}size := len(data)if size <= 1 {return data}last := size - 1for i := 0;i < last;i++ {p := me.min(data, i, size, comparator)if p != i {data[i], data[p] = data[p], data[i]}}return data}// 使用线性查找法, 获取最小值的索引func (me *tSelectSorter) min(data []interface{}, from int, to int, comparator sorting.CompareFunction) int {p := fromv := data[from]for i := from + 1;i < to;i++ {v1 := data[i]if comparator(v1, v) == sorting.LESS {p = iv = v1}}return p}var SelectSorter = newSelectSorter()
(end)
