1. 程式人生 > >golang中sort包用法

golang中sort包用法

golang中也實現了排序演算法的包sort包.

sort包中實現了3種基本的排序演算法:插入排序.快排和堆排序.和其他語言中一樣,這三種方式都是不公開的,他們只在sort包內部使用.所以使用者在使用sort包進行排序時無需考慮使用那種排序方式,sort.Interface定義的三個方法:獲取資料集合長度的Len()方法、比較兩個元素大小的Less()方法和交換兩個元素位置的Swap()方法,就可以順利對資料集合進行排序。sort包會根據實際資料自動選擇高效的排序演算法

type Interface interface {

    Len() int    // Len 為集合內元素的總數
Less(i, j int) bool //如果index為i的元素小於index為j的元素,則返回true,否則返回false   Swap(i, j int) // Swap 交換索引為 i 和 j 的元素 }

任何實現了 sort.Interface 的型別(一般為集合),均可使用該包中的方法進行排序。這些方法要求集合內列出元素的索引為整數。


func Float64s(a []float64)     //Float64s將型別為float64的slice a以升序方式進行排序
func Float64sAreSorted(a []float64) bool  //判定是否已經進行排序func Ints(a []int)

func Ints(a []int)                       //Ints 以升序排列 int 切片。
func IntsAreSorted(a []int) bool     //IntsAreSorted 判斷 int 切片是否已經按升序排列。
func IsSorted(data Interface) bool    IsSorted 判斷資料是否已經排序。包括各種可sort的資料型別的判斷.

func Strings(a []string)//Strings 以升序排列 string 切片。
func StringsAreSorted(a []string) bool//StringsAreSorted 判斷 string 切片是否已經按升序排列。

package main

import (
	"fmt"
	"sort"
)

//定義interface{},並實現sort.Interface介面的三個方法
type IntSlice []int

func (c IntSlice) Len() int {
	return len(c)
}
func (c IntSlice) Swap(i, j int) {
	c[i], c[j] = c[j], c[i]
}
func (c IntSlice) Less(i, j int) bool {
	return c[i] < c[j]
}

func main() {
	a := IntSlice{1, 3, 5, 7, 2}
	b := []float64{1.1, 2.3, 5.3, 3.4}
	c := []int{1, 3, 5, 4, 2}
	fmt.Println(sort.IsSorted(a)) //false
	if !sort.IsSorted(a) {
		sort.Sort(a) 
	}

	if !sort.Float64sAreSorted(b) {
		sort.Float64s(b)
	}
	if !sort.IntsAreSorted(c) {
		sort.Ints(c)
	}
	fmt.Println(a)//[1 2 3 5 7]
	fmt.Println(b)//[1.1 2.3 3.4 5.3]
	fmt.Println(c)// [1 2 3 4 5]
}

func Search(n int, f func(int) bool) int   

search使用二分法進行查詢,Search()方法回使用“二分查詢”演算法來搜尋某指定切片[0:n],並返回能夠使f(i)=true的最小的i(0<=i<n)值,並且會假定,如果f(i)=true,則f(i+1)=true,即對於切片[0:n],i之前的切片元素會使f()函式返回false,i及i之後的元素會使f()函式返回true。但是,當在切片中無法找到時f(i)=true的i時(此時切片元素都不能使f()函式返回true),Search()方法會返回n(而不是返回-1)。

Search 常用於在一個已排序的,可索引的資料結構中尋找索引為 i 的值 x,例如陣列或切片。這種情況下,實參 f,一般是一個閉包,會捕獲所要搜尋的值,以及索引並排序該資料結構的方式。

為了查詢某個值,而不是某一範圍的值時,如果slice以升序排序,則 f func中應該使用>=,如果slice以降序排序,則應該使用<=. 例子如下:package main

package main

import (
	"fmt"
	"sort"
)

func main() {
	a := []int{1, 2, 3, 4, 5}
	b := sort.Search(len(a), func(i int) bool { return a[i] >= 30 })
	fmt.Println(b)       //5,查詢不到,返回a slice的長度5,而不是-1
	c := sort.Search(len(a), func(i int) bool { return a[i] <= 3 })
	fmt.Println(c)                             //0,利用二分法進行查詢,返回符合條件的最左邊數值的index,即為0
	d := sort.Search(len(a), func(i int) bool { return a[i] == 3 })
	fmt.Println(d)                          //2   
}

官網上面有趣的例子:

func GuessingGame() {
	var s string
	fmt.Printf("Pick an integer from 0 to 100.\n")
	answer := sort.Search(100, func(i int) bool {
		fmt.Printf("Is your number <= %d? ", i)
		fmt.Scanf("%s", &s)
		return s != "" && s[0] == 'y'
	})
	fmt.Printf("Your number is %d.\n", answer)
}

func SearchFloat64s(a []float64, x float64) int  //SearchFloat64s 在float64s切片中搜索x並返回索引如Search函式所述. 返回可以插入x值的索引位置,如果x不存在,返回陣列a的長度切片必須以升序排列
func SearchInts(a []int, x int) int  //SearchInts 在ints切片中搜索x並返回索引如Search函式所述. 返回可以插入x值的索引位置,如果x不存在,返回陣列a的長度切片必須以升序排列
func SearchStrings(a []string, x string) int//SearchFloat64s 在strings切片中搜索x並返回索引如Search函式所述. 返回可以插入x值的索引位置,如果x不存在,返回陣列a的長度切片必須以升序排列

其中需要注意的是,以上三種search查詢方法,其對應的slice必須按照升序進行排序,否則會出現奇怪的結果.

package main

import (
	"fmt"
	"sort"
)

func main() {
	a := []string{"a", "c"}
	i := sort.SearchStrings(a, "b")
	fmt.Println(i) //1
	b := []string{"a", "b", "c", "d"}
	i = sort.SearchStrings(b, "b")
	fmt.Println(i) //1
	c := []string{"d", "c"}
	i = sort.SearchStrings(c, "b")
	fmt.Println(i) //0
	d := []string{"c", "d", "b"}
	i = sort.SearchStrings(d, "b")
	fmt.Println(i) //0,由於d不是以升序方式排列,所以出現奇怪的結果,這可以根據SearchStrings的定義進行解釋.見下方.
}
func SearchStrings(a []string, x string) int {
return Search(len(a), func(i int) bool { return a[i] >= x })
}
由此可見,為了精確查詢,必須對[]string 以升序方式進行排序.
func Sort(data Interface)//Sort 對 data 進行排序。它呼叫一次 data.Len 來決定排序的長度 n,呼叫 data.Less 和 data.Swap 的開銷為O(n*log(n))。此排序為不穩定排序。他根據不同形式決定使用不同的排序方式(插入排序,堆排序,快排)

func Stable(data Interface)Stable對data進行排序,不過排序過程中,如果data中存在相等的元素,則他們原來的順序不會改變,即如果有兩個相等元素num,他們的初始index分別為i和j,並且i<j,則利用Stable對data進行排序後,i依然小於j.直接利用sort進行排序則不能夠保證這一點.

golang自身實現的interface有三種,Float64Slice,IntSlice,StringSlice,具體如下所示:

type Float64Slice

type Float64Slice []float64
Float64Slice 針對 []float6 實現介面的方法,以升序排列。
func (p Float64Slice) Len() int    //求長度
func (p Float64Slice) Less(i, j int) bool //比大小
func (p Float64Slice) Search(x float64) int //查詢
func (p Float64Slice) Sort()      //排序
func (p Float64Slice) Swap(i, j int)   //交換位置


type IntSlice

type IntSlice []int

IntSlice 針對 []int 實現介面的方法,以升序排列。

func (p IntSlice) Len() int
func (p IntSlice) Less(i, j int) bool
func (p IntSlice) Search(x int) int
func (p IntSlice) Sort()
func (p IntSlice) Swap(i, j int)


type StringSlice

type StringSlice []string

StringSlice 針對 []string 實現介面的方法,以升序排列。

func (p StringSlice) Len() int
func (p StringSlice) Less(i, j int) bool
func (p StringSlice) Search(x string) int
func (p StringSlice) Sort()
func (p StringSlice) Swap(i, j int)


func Reverse(data Interface) Interface Reverse實現對data的逆序排列
package main

import (
	"fmt"
	"sort"
)

func main() {
	a := []int{1, 2, 5, 3, 4}
	fmt.Println(a)        // [1 2 5 3 4]
	sort.Sort(sort.Reverse(sort.IntSlice(a)))
	fmt.Println(a)        // [5 4 3 2 1]
}