搜索是指从元素集合中找到某个特定元素的过程。搜索过程通常返回true或false,分别表示元素是否存在。
顺序搜索(无序、有序列表)
存储于列表等集合中的数据项彼此存在线性或顺序的关系,每个数据项的位置与其他数据项相关。在Golang数组、切片中,数据项的位置就是它的下标。因为下标是有序的,所以能够顺序访问,由此可以进行顺序搜索。
顺序搜索原理:从列表的第一个元素开始,沿着默认的顺序逐个查看,直到找到目标元素或者查完列表。如果查完列表后仍没有找到目标元素,则说明目标元素不在列表中。
无序列表的顺序搜索Golang代码实现如下:
package main
import "fmt"
func unorderedSequentialSearch(numList []int, num int) bool {
exist := false
for _, value := range numList {
if value == num {
exist = true
break
}
}
return exist
}
func main() {
numList := []int{2, 3, 1, 53, 23, 10}
fmt.Println(unorderedSequentialSearch(numList, 33))
// false
fmt.Println(unorderedSequentialSearch(numList, 1))
// true
}
假设列表中的元素按照升序排序。如果存在目标元素, 那么它出现在n个位置中任意一个位置的可能性仍然一样大,因此比较次数与在无序列表中相同。不过,如果不存在目标元素,那么搜索效率就会提高。如果碰到一个已比目标元素还大的元素,那么意味着后面所有的元素都不是目标元素,可以提前结束查找,不必搜完整个列表。
有序列表的顺序搜索Golang代码实现如下:
package main
import "fmt"
func orderedSequentialSearch(numList []int, num int) bool {
exist := false
for _, value := range numList {
if value == num {
exist = true
break
} else if value > num {
break
}
}
return exist
}
func main() {
numList := []int{0, 1, 2, 3, 4, 5, 6}
fmt.Println(unorderedSequentialSearch(numList, 33))
// false
fmt.Println(unorderedSequentialSearch(numList, 1))
// true
}
有序列表优先使用二分搜索
二分搜索是从中间的元素着手。如果这个元素就是目标元素,那就立即停止搜索;如果不是,则利用列表有序的特性,排除一半的元素。如果目标元素比中间的元素大,就可以直接排除列表的左半部分和中间的元素。这是因为,如果列表包含目标元素,它必定位于右半部分。接下来,针对右半部分一分为二。从中间的元素着手,将其和目标元素比较。同理,要么直接找到目标元素,要么将右半部分一分为二,再次缩小搜索范围。
有序列表的二分搜索Golang代码实现如下:
package main
import "fmt"
func binarySearch(numList []int, num int) bool {
first := 0
last := len(numList) - 1
exist := false
for ;(first <= last) && !(exist); {
midPoint := (first + last) / 2
if numList[midPoint] == num {
exist = true
} else {
if num < numList[midPoint] {
last = midPoint - 1
} else {
first = midPoint + 1
}
}
}
return exist
}
func main() {
numList := []int{0, 1, 2, 3, 4, 5, 6}
fmt.Println(binarySearch(numList, 2))
// true
fmt.Println(binarySearch(numList, 9))
// false
}