扩散二分查找

比如查找一个数组var arr = []int{10, 5, 6, 19, 35, 24, 17, 5, 5, 5, 5, 5, 5, 5}里面5出现的起始位置和终止位置

1:直接遍历,时间复杂度为O(N)

如果是排序好的数组 5 5 5 5 5 5 5 5 6 10 17 19 24 35

2:可以先二分查找到5,再向两边扩散,扩算的时候可以继续二分

package main

import (
	"fmt"
	"sort"
)

func find(arr []int, el int) (first, last int) {
	left := 0
	right := len(arr) - 1
	middle := middle_find(arr, left, right, el)
	if middle == -1 {
		return -2, -2
	}
	first = middle_find(arr, left, middle-1, el) //middle=-1就越界了
	last = middle_find(arr, middle+1, right, el)

	tmpfirst, tmplast := first, last

	//二分向两边扩散
	for {

		if first == -1 {
			first = tmpfirst
			break
		}
		if first <= left {
			break
		}

		tmpfirst = first
		first = middle_find(arr, left, first-1, el) //二分偏移量最少,并且是单边二分,往小的方向
	}

	for {

		if last == -1 {
			last = tmplast
			break
		}
		if last >= right {
			break
		}

		tmplast = last
		last = middle_find(arr, last+1, right, el) //单边二分,往大的方向
	}

	if first == -1 && middle != -1 {
		first = middle
	}
	if last == -1 && middle != -1 {
		last = middle
	}

	return first, last
}

//二分查找
func middle_find(arr []int, left, right int, el int) int {
	middle := (left + right) / 2
	for left < right-1 { //注意是right-1,left=0,right=1,middle=(left+right)/2=0 不然会导致死循环
		if arr[middle] < el {
			left = middle
			middle = (left + right) / 2
		}

		if arr[middle] > el {
			right = middle
			middle = (left + right) / 2
		}

		if arr[middle] == el {
			return middle
		}
	}
	if arr[right] == el {
		return left
	} else {
		return -1
	}

}

func show_arr(arr []int) {
	len1 := len(arr)
	for i := 0; i < len1; i++ {
		fmt.Printf("%d ", arr[i])
	}
	fmt.Printf("\n")
}

func main() {
	var arr = []int{10, 5, 6, 19, 35, 24, 17, 5, 5, 5, 5, 5, 5, 5}
	sort.Ints(arr)
	first, last := find(arr, 5)
	fmt.Printf("search the value %d: first index %d,last index %d \n", 5, first+1, last+1)
	show_arr(arr)
}

输出:

search the value 5: first index 1,last index 8 

5 5 5 5 5 5 5 5 6 10 17 19 24 35


转载于:https://my.oschina.net/yang1992/blog/547494

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值