在很多語言中,排序演算法都是和序列資料型別關聯,同時排序函式和具體型別元素關聯。而 Go 語言的 sort.Sort() 函式不會對具體的序列和它的元素做任何假設。相反,它使用了一個介面型別 sort.Interface 來指定通用的排序演算法和可能被排序到的序列型別之間的約定。
這個介面的實現由序列的具體表示和它希望排序的元素決定,序列的表示經常是一個切片。
一個內建的排序演算法需要知道三個東西:序列的長度,表示兩個元素比較的結果,一種交換兩個元素的
方式;這就是 sort.Interface 的三個方法:
package 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)
}
為了對序列進行排序,我們需要定義一個實現了這三個方法的型別,然後對這個型別的一個例項應用
sort.Sort() 函式。
例子:對一個表格中的音樂播放列表進行排序
package main
import (
"fmt"
"os"
"sort"
"text/tabwriter"
"time"
)
//定義音樂播放列表的結構體
type Track struct {
Title string
Artist string
Album string
Year int
Length time.Duration
}
//例項化幾條測試資料
var tracks = []*Track{
{"GO", "Delilah", "From the Roots Up", 2012, length("3m38s")},
{"GO", "Moby", "Moby", 2012, length("13m38s")},
{"GOaaaa", "Alicic keys", "As I am", 2012, length("31m38s")},
{"GO", "Martin solveig", "Smash", 2012, length("34m38s")},
}
/**
獲取時間長度
*/
func length(s string) time.Duration {
d, err := time.ParseDuration(s)
if err != nil {
panic(err)
}
return d
}
/**
將播放列表列印成一個表格,
使用text/tabwriter包來生成一個列是整齊對齊和隔開的表格
*/
func printTracks(track []*Track) {
const format = "%v\t%v\t%v\t%v\t%v\t\n"
tw := new(tabwriter.Writer).Init(os.Stdout, 0, 8, 2, ' ', 0)
fmt.Fprintf(tw, format, "Title", "Artist", "Album", "Year", "Length")
for _, t := range track {
fmt.Fprintf(tw, format, t.Title, t.Artist, t.Album, t.Year, t.Length)
}
tw.Flush()
}
/**
為了能按照Artist欄位對播放列表進行排序,
我們要按照sort.Interface定義實現三個方法:
Len() int
Less(i,j int) bool
Swap(i,j)
*/
type byArtist []*Track
func (x byArtist) Len() int {
return len(x)
}
//按照Artilst排序
func (x byArtist) Less(i, j int) bool {
return x[i].Artist < x[j].Artist
}
func (x byArtist) Swap(i, j int) {
x[i], x[j] = x[j], x[i]
}
//程式入口
func main() {
sort.Sort(byArtist(tracks)) //將tracks轉換為新的byArtist型別
printTracks(tracks)
}
輸出結果:
假設使用者第二次請求 「按照 artist 排序」,我們會對 tracks 進行逆向排序。然而我們不需要定義一個有
顛倒 Less 方法的新型別 byReverseArtist ,因為sort包中提供了 Reverse 函式將排序順序轉換成逆序。
func main() {
sort.Sort(sort.Reverse(byArtist(tracks)))//逆向排序
printTracks(tracks)
}
逆向排序的結果:
sort 包定義了一個不公開的 struct 型別 reverse,它嵌入了一個 sort.Interface。reverse的Less方法調
用了內嵌的sort.Interface值的Less方法,但是通過交換索引的方式使排序結果變成逆序:
package sort
type reverse struct {
// This embedded Interface permits Reverse to use the methods of
// another Interface implementation.
Interface
}
// Less returns the opposite of the embedded implementation's Less method.
func (r reverse) Less(i, j int) bool {
return r.Interface.Less(j, i)
}
// Reverse returns the reverse order for data.
func Reverse(data Interface) Interface {
return &reverse{data}
}
reverse 的另外兩個方法 Len 和 Swap 隱式地由原有內嵌的 sort.Interface 提供。因為reverse是一個不公開的型別,所以匯出函式 Reverse 函式返回一個包含原有sort.Interface 值的 reverse 型別例項。
本作品採用《CC 協議》,轉載必須註明作者和本文連結