Heim  >  Artikel  >  Backend-Entwicklung  >  Sortiererklärung in Go-Sprache

Sortiererklärung in Go-Sprache

尚
nach vorne
2020-01-16 17:30:282969Durchsuche

Sortiererklärung in Go-Sprache

Die Sortieridee der Go-Sprache unterscheidet sich etwas von der von C und C++. c sortiert standardmäßig ein Array, c++ sortiert eine Sequenz und go ist allgemeiner. Das zu sortierende Objekt kann ein beliebiges Objekt sein, obwohl es in vielen Fällen ein Slice (Slice, ähnlich einem Array) ist oder ein Slice davon enthält ein Objekt.

Drei Elemente der Sortierung (Schnittstelle):

Die Anzahl der zu sortierenden Elemente n;

Die Vergleichsfunktion cmp der i-ten und j-ten Elemente;

Austausch der i-ten und j-ten Elemente;

Auf den ersten Blick ist Bedingung 3 redundant, weder C noch C++ bieten einen Austausch. Verwendung von qsort in c: qsort(data, n, sizeof(int), cmp_int); data ist die Startadresse, n ist die Anzahl der Elemente, sizeof(int) ist die Größe jedes Elements und cmp_int ist ein Vergleich von zwei Ints-Funktion.

Verwendung von sort in c++: sort(data, data+n, cmp_int); data ist die Position des ersten Elements, data+n ist die nächste Position des letzten Elements und cmp_int ist die Vergleichsfunktion .

Sortierung der Grundtypen int, float64 und string

Aufsteigende Sortierung

Für int, Zum Sortieren von Float64- und String-Arrays oder Slices bietet Go die Funktionen sort.Ints(), sort.Float64s() und sort.Strings(). Standardmäßig werden sie von klein nach groß sortiert. (Es gibt keine sort.Float32s()-Funktion, was für mich etwas seltsam ist.)

package main
 
import (
    "fmt"
    "sort"
)
 
func main() {
    intList := [] int {2, 4, 3, 5, 7, 6, 9, 8, 1, 0}
    float8List := [] float64 {4.2, 5.9, 12.3, 10.0, 50.4, 99.9, 31.4, 27.81828, 3.14}
    // float4List := [] float32 {4.2, 5.9, 12.3, 10.0, 50.4, 99.9, 31.4, 27.81828, 3.14}    // no function : sort.Float32s
    stringList := [] string {"a", "c", "b", "d", "f", "i", "z", "x", "w", "y"}
   
    sort.Ints(intList)
    sort.Float64s(float8List)
    sort.Strings(stringList)
   
    fmt.Printf("%v\n%v\n%v\n", intList, float8List, stringList)
 
}

Absteigende Sortierung

int, float64 und string haben alle standardmäßig die aufsteigende Sortierung Sortierfunktionen, jetzt Die Frage ist, was ist, wenn die Reihenfolge absteigend ist? Jeder mit Programmiererfahrung in anderen Sprachen weiß, dass man nur die Vergleichsregeln von cmp austauschen muss. Die Implementierung von go ist ähnlich, aber unterschiedlich.

Um Objekte obj eines bestimmten Typs in go zu sortieren, können Sie sort.Sort(obj) verwenden, was bedeutet, dass Sie drei Methoden an den Typtyp binden müssen: Len(), um die Länge zu ermitteln, Less( i,j) ist eine Funktion, die die Größe des i-ten und j-ten Elements vergleicht, Swap(i,j) ist eine Funktion, die das i-te und j-te Element vertauscht.

Die drei Typen IntSlice, Float64Slice und StringSlice unter dem Sortierpaket implementieren diese drei Methoden. Die entsprechenden Sortiermethoden sind [] int, [] float64 und [] string. Wenn Sie in umgekehrter Reihenfolge sortieren möchten, müssen Sie lediglich die entsprechende Less-Funktion ändern.

Das Sortierpaket von Go kann sort.Reverse(slice) verwenden, um Slice.Interface.Less zu ersetzen, die die Vergleichsfunktion ist. Daher kann die umgekehrte Sortierfunktion für int, float64 und string wie folgt geschrieben werden:

package main
 
import (
    "fmt"
    "sort"
)
 
func main() {
    intList := [] int {2, 4, 3, 5, 7, 6, 9, 8, 1, 0}
    float8List := [] float64 {4.2, 5.9, 12.3, 10.0, 50.4, 99.9, 31.4, 27.81828, 3.14}
    stringList := [] string {"a", "c", "b", "d", "f", "i", "z", "x", "w", "y"}
   
    sort.Sort(sort.Reverse(sort.IntSlice(intList)))
    sort.Sort(sort.Reverse(sort.Float64Slice(float8List)))
    sort.Sort(sort.Reverse(sort.StringSlice(stringList)))
   
    fmt.Printf("%v\n%v\n%v\n", intList, float8List, stringList)
}

Umfassendes Verständnis der Sortierung

Im Sortierpaket gibt es eine sort.Interface-Schnittstelle mit drei Methoden: Len(), Less(i,j) und Swap(i,j) . Die allgemeine Sortierfunktion sort.Sort kann jedes Objekt (Variable) sortieren, das die Schnittstelle sort.Inferface implementiert.

Für [] int, [] float64 und [] string können Sie zusätzlich zur Verwendung spezieller Funktionen auch die modifizierten Typen IntSclice, Float64Slice und StringSlice verwenden und dann direkt ihre entsprechenden Sort()-Methoden aufrufen; Da diese drei Typen auch die Schnittstelle sort.Interface implementieren, können Sie die Methoden Interface.Less dieser drei Typen mit sort.Reverse konvertieren, um eine umgekehrte Sortierung zu erreichen.

Im Folgenden wird eine benutzerdefinierte (benutzerdefinierte) Reverse-Struktur anstelle der Funktion sort.Reverse verwendet, um die umgekehrte Sortierung zu implementieren.

package main
 
import (
    "fmt"
    "sort"
)
 
// 自定义的 Reverse 类型
type Reverse struct {
    sort.Interface    // 这样, Reverse 可以接纳任何实现了 sort.Interface (包括 Len, Less, Swap 三个方法) 的对象
}
 
// Reverse 只是将其中的 Inferface.Less 的顺序对调了一下
func (r Reverse) Less(i, j int) bool {
    return r.Interface.Less(j, i)
}
 
func main() {
    ints := []int{5, 2, 6, 3, 1, 4}     // 未排序
 
    sort.Ints(ints)                                     // 特殊排序函数, 升序
    fmt.Println("after sort by Ints:\t", ints)  // [1 2 3 4 5 6]
 
    doubles := []float64{2.3, 3.2, 6.7, 10.9, 5.4, 1.8}
 
    sort.Float64s(doubles)                                      // float64 排序版本 1
    fmt.Println("after sort by Float64s:\t", doubles)   // [1.8 2.3 3.2 5.4 6.7 10.9]
 
    strings := []string{"hello", "good", "students", "morning", "people", "world"}
    sort.Strings(strings)
    fmt.Println("after sort by Strings:\t", strings)    // [good hello mornig people students world]
 
    ipos := sort.SearchInts(ints, -1)    // int 搜索
    fmt.Printf("pos of 5 is %d th\n", ipos)     // 并不总是正确呀 ! (搜索不是重点)
 
    dpos := sort.SearchFloat64s(doubles, 20.1)    // float64 搜索
    fmt.Printf("pos of 5.0 is %d th\n", dpos)   // 并不总是正确呀 !
 
    fmt.Printf("doubles is asc ? %v\n", sort.Float64sAreSorted(doubles))
 
    doubles = []float64{3.5, 4.2, 8.9, 100.98, 20.14, 79.32}
    // sort.Sort(sort.Float64Slice(doubles))    // float64 排序方法 2
    // fmt.Println("after sort by Sort:\t", doubles)    // [3.5 4.2 8.9 20.14 79.32 100.98]
    (sort.Float64Slice(doubles)).Sort()         // float64 排序方法 3
    fmt.Println("after sort by Sort:\t", doubles)       // [3.5 4.2 8.9 20.14 79.32 100.98]
 
    sort.Sort(Reverse{sort.Float64Slice(doubles)})    // float64 逆序排序
    fmt.Println("after sort by Reversed Sort:\t", doubles)      // [100.98 79.32 20.14 8.9 4.2 3.5]
}

sort.Ints / sort.Float64s / sort.Strings werden zum Sortieren von Ganzzahl-/Gleitkomma-/String-Typ-Slices oder Fragmenten oder nicht reinen Arrays verwendet. Dann gibt es eine Funktion, die prüft, ob es in Ordnung ist. Es gibt auch entsprechende Suchfunktionen. Es stellt sich jedoch heraus, dass die Suchfunktion die Position nur dann finden kann, wenn sie nicht existiert.

Bezüglich der allgemeinen Array-Sortierung zeigt das Programm, dass es drei Methoden gibt! Die drei derzeit bereitgestellten Typen int, float64 und string sind symmetrisch, das heißt, was Sie haben, ich habe auch die entsprechenden.

Bezüglich der Umkehrsortierung oder umgekehrten Sortierung verwenden Sie einfach eine Umkehrstruktur und schreiben Sie die Less-Funktion neu. Die obige Rückseite ist eine allgemeine Struktur.

Nachdem wir so viel oben gesagt haben, ist es an der Zeit, über die Sortierung von Strukturtypen zu sprechen. In der Praxis wird dies häufiger verwendet.

Sortierung von Strukturtypen

Die Sortierung von Strukturtypen wird durch die Verwendung von sort.Sort(slice) erreicht, sofern Slice implementiert ist Drei Methoden von sort.Interface reichen aus. Allerdings gibt es mehrere Möglichkeiten zum Sortieren. Die erste besteht darin, die Sortierung von [] int zu simulieren, um den entsprechenden IntSlice-Typ zu erstellen, und dann die drei Schnittstellenmethoden für den IntSlice-Typ zu implementieren.

Struktursortiermethode 1

package main
 
import (
    "fmt"
    "sort"
)
 
type Person struct {
    Name string    // 姓名
    Age  int    // 年纪
}
 
// 按照 Person.Age 从大到小排序
type PersonSlice [] Person
 
func (a PersonSlice) Len() int {    // 重写 Len() 方法
    return len(a)
}
func (a PersonSlice) Swap(i, j int){     // 重写 Swap() 方法
    a[i], a[j] = a[j], a[i]
}
func (a PersonSlice) Less(i, j int) bool {    // 重写 Less() 方法, 从大到小排序
    return a[j].Age < a[i].Age
}
 
func main() {
    people := [] Person{
        {"zhang san", 12},
        {"li si", 30},
        {"wang wu", 52},
        {"zhao liu", 26},
    }
 
    fmt.Println(people)
 
    sort.Sort(PersonSlice(people))    // 按照 Age 的逆序排序
    fmt.Println(people)
 
    sort.Sort(sort.Reverse(PersonSlice(people)))    // 按照 Age 的升序排序
    fmt.Println(people)
 
}

Dies ist eine reine Simulationsmethode. Wenn Sie also IntSlice verstehen, werden Sie dies natürlich verstehen, und umgekehrt werden Sie dies auch verstehen. Dann wird IntSlice es verstehen.

Struktursortiermethode 2

方法 1 的缺点是 : 根据 Age 排序需要重新定义 PersonSlice 方法,绑定 Len 、 Less 和 Swap 方法, 如果需要根据 Name 排序, 又需要重新写三个函数; 如果结构体有 4 个字段,有四种类型的排序,那么就要写 3 × 4 = 12 个方法, 即使有一些完全是多余的, 仔细思量一下,根据不同的标准 Age 或是 Name, 真正不同的体现在 Less 方法上,所以, me 们将 Less 抽象出来, 每种排序的 Less 让其变成动态的,比如下面一种方法。

package main
 
import (
    "fmt"
    "sort"
)
 
type Person struct {
    Name string    // 姓名
    Age  int    // 年纪
}
 
type PersonWrapper struct {
    people [] Person
    by func(p, q * Person) bool
}
 
func (pw PersonWrapper) Len() int {    // 重写 Len() 方法
    return len(pw.people)
}
func (pw PersonWrapper) Swap(i, j int){     // 重写 Swap() 方法
    pw.people[i], pw.people[j] = pw.people[j], pw.people[i]
}
func (pw PersonWrapper) Less(i, j int) bool {    // 重写 Less() 方法
    return pw.by(&pw.people[i], &pw.people[j])
}
 
func main() {
    people := [] Person{
        {"zhang san", 12},
        {"li si", 30},
        {"wang wu", 52},
        {"zhao liu", 26},
    }
 
    fmt.Println(people)
 
    sort.Sort(PersonWrapper{people, func (p, q *Person) bool {
        return q.Age < p.Age    // Age 递减排序
    }})
 
    fmt.Println(people)
    sort.Sort(PersonWrapper{people, func (p, q *Person) bool {
        return p.Name < q.Name    // Name 递增排序
    }})
 
    fmt.Println(people)
 
}

方法 2 将 [] Person 和比较的准则 cmp 封装在了一起,形成了 PersonWrapper 函数,然后在其上绑定 Len 、 Less 和 Swap 方法。 实际上 sort.Sort(pw) 排序的是 pw 中的 people, 这就是前面说的, go 的排序未必就是针对的一个数组或是 slice, 而可以是一个对象中的数组或是 slice 。

结构体排序方法 3

me 赶脚方法 2 已经很不错了, 唯一一个缺点是,在 main 中使用的时候暴露了 sort.Sort 的使用,还有就是 PersonWrapper 的构造。 为了让 main 中使用起来更为方便, me 们可以再简单的封装一下, 构造一个 SortPerson 方法, 如下:

package main
 
import (
    "fmt"
    "sort"
)
 
type Person struct {
    Name string    // 姓名
    Age  int    // 年纪
}
 
type PersonWrapper struct {
    people [] Person
    by func(p, q * Person) bool
}
 
type SortBy func(p, q *Person) bool
 
func (pw PersonWrapper) Len() int {    // 重写 Len() 方法
    return len(pw.people)
}
func (pw PersonWrapper) Swap(i, j int){     // 重写 Swap() 方法
    pw.people[i], pw.people[j] = pw.people[j], pw.people[i]
}
func (pw PersonWrapper) Less(i, j int) bool {    // 重写 Less() 方法
    return pw.by(&pw.people[i], &pw.people[j])
}
 
 
func SortPerson(people [] Person, by SortBy){    // SortPerson 方法
    sort.Sort(PersonWrapper{people, by})
}
 
func main() {
    people := [] Person{
        {"zhang san", 12},
        {"li si", 30},
        {"wang wu", 52},
        {"zhao liu", 26},
    }
 
    fmt.Println(people)
 
    sort.Sort(PersonWrapper{people, func (p, q *Person) bool {
        return q.Age < p.Age    // Age 递减排序
    }})
 
    fmt.Println(people)
 
    SortPerson(people, func (p, q *Person) bool {
        return p.Name < q.Name    // Name 递增排序
    })
 
    fmt.Println(people)
 
}

在方法 2 的基础上构造了 SortPerson 函数,使用的时候传过去一个 [] Person 和一个 cmp 函数。

结构体排序方法 4

下面是另外一个实现思路, 可以说是方法 1、 2 的变体。

package main
 
import (
    "fmt"
    "sort"
)
 
type Person struct {
    Name        string
    Weight      int
}
 
type PersonSlice []Person
 
func (s PersonSlice) Len() int  { return len(s) }
func (s PersonSlice) Swap(i, j int)     { s[i], s[j] = s[j], s[i] }
 
type ByName struct{ PersonSlice }    // 将 PersonSlice 包装起来到 ByName 中
 
func (s ByName) Less(i, j int) bool     { return s.PersonSlice[i].Name < s.PersonSlice[j].Name }    // 将 Less 绑定到 ByName 上
 
 
type ByWeight struct{ PersonSlice }    // 将 PersonSlice 包装起来到 ByWeight 中
func (s ByWeight) Less(i, j int) bool   { return s.PersonSlice[i].Weight < s.PersonSlice[j].Weight }    // 将 Less 绑定到 ByWeight 上
 
func main() {
    s := []Person{
        {"apple", 12},
        {"pear", 20},
        {"banana", 50},
        {"orange", 87},
        {"hello", 34},
        {"world", 43},
    }
 
    sort.Sort(ByWeight{s})
    fmt.Println("People by weight:")
    printPeople(s)
 
    sort.Sort(ByName{s})
    fmt.Println("\nPeople by name:")
    printPeople(s)
 
}
 
func printPeople(s []Person) {
    for _, o := range s {
        fmt.Printf("%-8s (%v)\n", o.Name, o.Weight)
    }
}

更多go语言知识请关注PHP中文网go语言教程栏目。

Das obige ist der detaillierte Inhalt vonSortiererklärung in Go-Sprache. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:cnblogs.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen