go 언어의 정렬 아이디어는 C 및 C++의 정렬 아이디어와 다소 다릅니다. c는 기본적으로 배열을 정렬하고, c++는 시퀀스를 정렬하며, go는 더 일반적입니다. 정렬할 객체는 어떤 객체라도 될 수 있습니다. 그러나 많은 경우에는 슬라이스(배열과 유사한 슬라이스)이거나 다음의 슬라이스를 포함합니다. 객체.
3가지 정렬 요소(인터페이스):
정렬할 요소 수 n;
i번째 요소와 j번째 요소의 비교 함수 cmp
i번째 요소와 j번째 요소 교환; ;
cha 언뜻 보기에 조건 3은 중복되며, C나 C++ 모두 스왑을 제공하지 않습니다. c에서 qsort 사용법: qsort(data, n, sizeof(int), cmp_int); data는 시작 주소, n은 요소 수, sizeof(int)는 각 요소의 크기, cmp_int는 다음의 비교입니다. 두 개의 정수 함수.
C++에서 정렬 사용법: sort(data, data+n, cmp_int); data는 첫 번째 요소의 위치이고, data+n은 마지막 요소의 다음 위치이며, cmp_int는 비교 함수입니다.
기본 유형 int, float64 및 문자열 정렬
오름차순 정렬
int, float64 및 문자열 배열 또는 슬라이스 정렬을 위해 go에서는 각각 sort.Ints() 및 sort.Float64s()를 제공합니다. sort.Strings() 함수는 기본적으로 작은 것부터 큰 것 순으로 정렬됩니다. (sort.Float32s() 함수가 없는데 좀 이상하네요.)
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) }
Descending sort
int, float64 및 string에는 모두 기본 오름차순 정렬 기능이 있습니다. 이제 문제는 내림차순에 관한 것입니다. 다른 언어의 프로그래밍 경험이 있는 사람이라면 cmp의 비교 규칙만 교환하면 된다는 것을 알고 있습니다. go의 구현은 비슷하지만 다릅니다.
go에서 특정 유형의 객체 obj를 정렬하려면 sort.Sort(obj)를 사용할 수 있습니다. 즉, Type 유형에 세 가지 메소드를 바인딩해야 합니다: Len() 길이를 찾으려면 Less(i,j) i번째 요소와 j번째 요소의 크기 함수를 비교하려면 Swap(i,j) i번째 요소와 j번째 요소를 바꾸는 함수입니다.
sort 패키지의 IntSlice, Float64Slice 및 StringSlice 세 가지 유형은 각각 이 세 가지 메서드를 구현하며 해당 정렬 메서드는 [] int, [] float64 및 [] string입니다. 역순으로 정렬하려면 해당 Less 함수만 수정하면 됩니다.
go의 정렬 패키지는 비교 함수인 Slice.Interface.Less를 대체하기 위해 sort.Reverse(slice)를 사용할 수 있습니다. 따라서 int, float64 및 string에 대한 역 정렬 함수는 다음과 같이 작성할 수 있습니다.
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) }
이해하세요 심도 있는 정렬
sort 패키지에는 Len(), Less(i,j) 및 Swap(i,j)의 세 가지 메서드가 있는 sort.Interface 인터페이스가 있습니다. 일반 정렬 함수 sort.Sort는 sort.Inferface 인터페이스를 구현하는 모든 개체(변수)를 정렬할 수 있습니다.
[] int, [] float64 및 [] 문자열의 경우 특별히 지정된 함수를 사용하는 것 외에도 수정된 유형 IntSclice, Float64Slice 및 StringSlice를 사용한 다음 해당 Sort() 메서드를 직접 호출할 수도 있습니다. type은 sort.Interface 인터페이스도 구현하므로 이 세 가지 유형의 Interface.Less 메서드를 sort.Reverse를 통해 변환하여 역 정렬을 수행할 수 있습니다.
다음은 sort.Reverse 함수 대신 사용자 정의(사용자 정의) 역방향 구조를 사용하여 역 정렬을 구현합니다.
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는 정수/부동 소수점/문자열 유형의 슬라이스나 조각 또는 엄밀히 말하면 배열이 아닌 정렬에 사용됩니다. 그런 다음 순서대로 테스트하는 기능이 있습니다. 해당 검색 기능도 있습니다. 그러나 검색 기능이 존재하지 않는 경우에만 위치를 찾을 수 있는 것으로 나타났습니다.
일반적인 배열 정렬과 관련하여 프로그램에서는 3가지 방법이 있음을 보여줍니다! 현재 제공되는 세 가지 유형인 int, float64 및 string은 대칭형입니다. 즉, 여러분이 갖고 있는 것, 저에게도 해당하는 유형이 있습니다.
뒤집기 정렬이나 역 정렬의 경우 뒤집기 구조를 사용하고 Less 함수를 다시 작성하면 됩니다. 위의 역방향은 일반적인 구조입니다.
위에서 설명한 내용이 너무 많아서 기본 유형만 정렬했습니다. 이제 실제로는 이것이 더 많이 사용됩니다.
구조체 유형 정렬
구조체 유형 정렬은 슬라이스가 sort.Interface의 세 가지 메서드를 구현하는 한 sort.Sort(슬라이스)를 사용하여 수행됩니다. 그런데 정렬하는 방법에는 여러 가지가 있습니다. 첫 번째는 [] int 정렬을 시뮬레이션하여 해당 IntSlice 유형을 구성한 다음 IntSlice 유형에 대한 인터페이스의 세 가지 메서드를 구현하는 것입니다.
구조 정렬 방법 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) }
완전히 시뮬레이션 방법이므로 IntSlice를 이해하면 자연스럽게 이해되고, 반대로 이것을 이해하면 IntSlice도 이해하게 됩니다.
구조 정렬 방법 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语言教程栏目。
위 내용은 Go 언어로 정렬 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!