模仿 Go Sort 排序接口實現的自定義排序

Go 語言對於類型的要求非常嚴格,導致我們無法聲明一個 interface 類型的切片對其排序。所以這裏模仿 Go 的 sort 排序擴展包,實現對某個特定類型排序的方法。

Interface 接口

若要實現一個自定義的排序,就要實現 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)
}

自定義排序的結構體

我們將對所有的學生進行排序,學生包含他的姓名以及成績,排序的規則是按照學習的成績排序。

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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章