2 回答

TA貢獻1810條經驗 獲得超5個贊
sort包演示了如何使用接口以與類型無關的方式實現算法。
線性搜索需要兩個基本操作,具體取決于 haystack 元素類型:Len 和 Equal。因此,我們可以編寫以下 Haystack 接口和使用它的搜索函數:
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 的編寫實現變得簡單,但不是類型安全的:
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
}
請注意 Equal 方法中的類型斷言。為了使這個類型安全,我們必須去掉interface{}Equal 的參數:
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
}
這使得界面實現和搜索功能的使用變得更加復雜。
這個故事的寓意是,以這種方式使用接口需要足夠復雜的算法才值得這樣做。如果為特定類型編寫接口實現比為算法編寫具體實現需要更多工作,那么只需編寫您需要的具體函數即可:
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貢獻1802條經驗 獲得超10個贊
目前,不可能構建一個符合您所有標準的解決方案。一旦實現泛型,這將成為可能。或者您可以嘗試使用 構建一個reflect,但這會產生一個復雜且可能緩慢的解決方案......所以我通常建議不要使用reflect像這樣簡單的東西(請參見下面的第二個片段)。
你現在可以做的是使用類似的東西:
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
}
正如你可以想象的那樣,這沒有多大意義......因為簡單地顯式地寫出循環可以說更簡單、更快、更慣用:
// 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
}
}
顯然,只有當切片中的元素數量很少時,整個方法(線性掃描)才合理。sort.Slice如果您的切片很大并且很少更改,那么(從時間復雜度的角度來看)首先對其進行排序 ( ),然后sort.Search對排序后的切片進行二分搜索 ( )可能更有意義?;蛘?,您也可以使用 amap來代替: 在這種情況下(假設鍵很?。┎檎业臅r間復雜度為 O(1)。
- 2 回答
- 0 關注
- 169 瀏覽
添加回答
舉報