2 回答

TA貢獻(xiàn)1810條經(jīng)驗(yàn) 獲得超5個(gè)贊
sort包演示了如何使用接口以與類型無(wú)關(guān)的方式實(shí)現(xiàn)算法。
線性搜索需要兩個(gè)基本操作,具體取決于 haystack 元素類型:Len 和 Equal。因此,我們可以編寫以下 Haystack 接口和使用它的搜索函數(shù):
type Haystack interface {
Len() int
Equal(int, interface{}) bool
}
func Search(haystack Haystack, needle interface{}) int {
for i := 0; i < haystack.Len(); i++ {
if haystack.Equal(i, needle) {
return i
}
}
return -1
}
這使得 Haystack 的編寫實(shí)現(xiàn)變得簡(jiǎn)單,但不是類型安全的:
type Strings []string
func (s Strings) Len() int { return len(s) }
func (s Strings) Equal(i int, x interface{}) bool { return s[i] == x.(string) }
type Ints []int
func (s Ints) Len() int { return len(s) }
func (s Ints) Equal(i int, x interface{}) bool { return s[i] == x.(int) }
func main() {
strings := []string{"b", "a", "c", "d"}
fmt.Println(Search(Strings(strings), "c")) // 2
fmt.Println(Search(Strings(strings), "e")) // -1
ints := []int{2, 1, 3, 4}
fmt.Println(Search(Ints(ints), 3)) // 2
fmt.Println(Search(Ints(ints), 5)) // -1
}
請(qǐng)注意 Equal 方法中的類型斷言。為了使這個(gè)類型安全,我們必須去掉interface{}Equal 的參數(shù):
type Haystack interface {
Len() int
Equal(int) bool
}
func Search(haystack Haystack) int {
for i := 0; i < haystack.Len(); i++ {
if haystack.Equal(i) {
return i
}
}
return -1
}
type Strings struct {
hs []string
needle string
}
func (s Strings) Len() int { return len(s.hs) }
func (s Strings) Equal(i int) bool { return s.hs[i] == s.needle }
type Ints struct {
hs []int
needle int
}
func (s Ints) Len() int { return len(s.hs) }
func (s Ints) Equal(i int) bool { return s.hs[i] == s.needle }
func main() {
strings := []string{"b", "a", "c", "d"}
fmt.Println(Search(Strings{strings, "c"})) // 2
fmt.Println(Search(Strings{strings, "e"})) // -1
ints := []int{2, 1, 3, 4}
fmt.Println(Search(Ints{ints, 3})) // 2
fmt.Println(Search(Ints{ints, 5})) // -1
}
這使得界面實(shí)現(xiàn)和搜索功能的使用變得更加復(fù)雜。
這個(gè)故事的寓意是,以這種方式使用接口需要足夠復(fù)雜的算法才值得這樣做。如果為特定類型編寫接口實(shí)現(xiàn)比為算法編寫具體實(shí)現(xiàn)需要更多工作,那么只需編寫您需要的具體函數(shù)即可:
func SearchStr(haystack []string, needle string) int {
for i, x := range haystack {
if x == needle {
return i
}
}
return -1
}
func SearchInt(haystack []int, needle int) int {
for i, x := range haystack {
if x == needle {
return i
}
}
return -1
}
func main() {
strings := []string{"b", "a", "c", "d"}
fmt.Println(SearchStr(strings, "c")) // 2
fmt.Println(SearchStr(strings, "e")) // -1
ints := []int{2, 1, 3, 4}
fmt.Println(SearchInt(ints, 3)) // 2
fmt.Println(SearchInt(ints, 5)) // -1
}

TA貢獻(xiàn)1802條經(jīng)驗(yàn) 獲得超10個(gè)贊
目前,不可能構(gòu)建一個(gè)符合您所有標(biāo)準(zhǔn)的解決方案。一旦實(shí)現(xiàn)泛型,這將成為可能?;蛘吣梢試L試使用 構(gòu)建一個(gè)reflect,但這會(huì)產(chǎn)生一個(gè)復(fù)雜且可能緩慢的解決方案......所以我通常建議不要使用reflect像這樣簡(jiǎn)單的東西(請(qǐng)參見下面的第二個(gè)片段)。
你現(xiàn)在可以做的是使用類似的東西:
func FindFirst(n int, f func(int) bool) int {
for i := 0; i < n; i++ {
if f(i) {
return i
}
}
return -1
}
// in your code (s is the slice, e the value you are searching for)
i := FindFirst(len(s), func(i int) bool {
return s[i] == e
})
if i != -1 {
// i is the index of the element with value e
}
正如你可以想象的那樣,這沒有多大意義......因?yàn)楹?jiǎn)單地顯式地寫出循環(huán)可以說更簡(jiǎn)單、更快、更慣用:
// in your code (s is the slice, e the value you are searching for)
for i, v := range s {
if v == e {
_ = i // i is the index of the element with value e
break
}
}
顯然,只有當(dāng)切片中的元素?cái)?shù)量很少時(shí),整個(gè)方法(線性掃描)才合理。sort.Slice如果您的切片很大并且很少更改,那么(從時(shí)間復(fù)雜度的角度來(lái)看)首先對(duì)其進(jìn)行排序 ( ),然后sort.Search對(duì)排序后的切片進(jìn)行二分搜索 ( )可能更有意義?;蛘撸部梢允褂?amap來(lái)代替: 在這種情況下(假設(shè)鍵很?。┎檎业臅r(shí)間復(fù)雜度為 O(1)。
- 2 回答
- 0 關(guān)注
- 176 瀏覽
添加回答
舉報(bào)