查看完整代碼,點擊這裏git
最近在使用 Go 語言實現一些簡單的排序算法時,發現沒法實現一個支持多種類型的排序方法,固然實現一個 int
類型的排序算法是簡單的。例以下面的選擇排序:github
func SelectionSort(arr []int, length int) { for i := 0; i < length; i++ { minIndex := i for j := i + 1; j < length; j++ { if arr[j] < arr[j - 1] { minIndex = j } } arr[i], arr[minIndex] = arr[minIndex], arr[i] } }
可是如何實現一個方法,能夠對字母排序、按照結構體內數據排序... 呢?golang
我首先想到的固然是 interface
類型,將 int
替換成 interface
就能夠了嗎?實際是不行的,Go 語言對於類型的要求很是嚴格,由於程序沒法判斷 interface
具體是什麼數據類型,因此它也不知道該怎麼比較一個未知的數據類型,這會致使一個運行時錯誤。算法
對 interface
的斷言也是行不通的,由於咱們也不知道會傳入什麼數據類型,又怎麼判斷要斷言爲何數據類型呢。數據結構
而後我就想到了 Go 自帶的 sort 排序包,發現自定義數據類型的排序須要實現對應的接口。如下內容與此文章相似,有部分參考的內容。app
既然 Go 不知道怎麼排序未知的數據類型,咱們本身來定義比較的規則不就能夠了嗎?Go 的 sort 包正是這樣實現的。學習
// A type, typically a collection, that satisfies sort.Interface can be // sorted by the routines in this package. The methods require that the // elements of the collection be enumerated by an integer index. type Interface interface { // Len is the number of elements in the collection. Len() int // Less reports whether the element with // index i should sort before the element with index j. Less(i, j int) bool // Swap swaps the elements with indexes i and j. Swap(i, j int) }
Less()
解決的就是問題的癥結,咱們能夠本身定義比較的邏輯。測試
如下內容是展現如何使用這個接口。ui
這裏定義了一個學生的數據結構,咱們將對全部的學生進行排序,學生包含他的姓名以及成績,排序的規則是按照學習的成績排序。this
type Student struct { Name string Score int } type Students []Student
func (s Students) Len() int { return len(s) } // 在比較的方法中,定義排序的規則 func (s Students) Less(i, j int) bool { if s[i].Score < s[j].Score { return true } else if s[i].Score > s[j].Score { return false } else { return s[i].Name < s[i].Name } } func (s Students) Swap(i, j int) { temp := s[i] s[i] = s[j] s[j] = temp }
Go 提供了基於快排實現的排序方法,這裏爲了體驗爲何 Go 這麼定義 Interface
接口,我使用了選擇排序的方法代替 Go 的快排。
func Sort(s sort.Interface) { length := s.Len() for i := 0; i < length; i++ { minIndex := i for j := i + 1; j < length; j++ { if s.Less(j, i) { minIndex = j } } s.Swap(minIndex, i) } }
在這個排序中,我使用了接口中定義的三個方法: Len()
,Less()
,Swap()
。最重要的仍是 Less()
,沒有它程序就不知道如何去比較兩個未知元素的大小。
爲了更好的輸出學生的信息,重寫學生的字符串輸出格式
func (s Student) String() string { return fmt.Sprintf("Student: %s %v", s.Name, s.Score) }
經過如下程序測試咱們的排序算法
func main() { arr := []int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1} SelectionSort(arr, len(arr)) fmt.Println(arr) students := student.Students{} students = append(students, student.Student{"D", 90}) students = append(students, student.Student{"C", 100}) students = append(students, student.Student{"B", 95}) students = append(students, student.Student{"A", 95}) Sort(students) for _, student := range students { fmt.Println(student) } }
如下是輸出結果:
[1 2 3 4 5 6 7 8 9 10] Student: D 90 Student: A 95 Student: B 95 Student: C 100
查看 sort 包的官方文檔,能夠看到對 Float64
,int
, String
的結構體和接口實現,他們的原理跟上文描述其實都是同樣的,只不過是擴展包替咱們預先封裝了這些經常使用的數據類型而已。
實際排序時,優先使用官方提供的 Sort
方法,這裏只是爲了練習才本身實現了一個選擇排序。