Golang 二分查找

huangapple go评论105阅读模式
英文:

Golang Binary search

问题

我正在练习一道面试算法题,现在用Go语言编写代码。目的是练习基本的面试算法,并提升我的Go语言技能。我正在尝试对一个数字数组进行二分查找。

package main

import "fmt"

func main() {
    searchField := []int{2, 5, 8, 12, 16, 23, 38, 56, 72, 91}
    searchNumber := 23

    fmt.Println("Running Program")
    fmt.Println("Searching list of numbers: ", searchField)
    fmt.Println("Searching for number: ", searchNumber)

    numFound := false
    //searchCount not working. Belongs in second returned field
    result, _ := binarySearch2(searchField, len(searchField), searchNumber, numFound)
    fmt.Println("Found! Your number is found in position: ", result)
    //fmt.Println("Your search required ", searchCount, " cycles with the Binary method.")
}

func binarySearch2(a []int, field int, search int, numFound bool) (result int, searchCount int) {
    //searchCount removed for now.
    searchCount, i := 0, 0
    for !numFound {
        searchCount++
        mid := i + (field-i)/2
        if search == a[mid] {
            numFound = true
            result = mid
            return result, searchCount
        } else if search > a[mid] {
            field++
            //i = mid + 1 causes a stack overflow
            return binarySearch2(a, field, search, numFound)
        }
        field = mid
        return binarySearch2(a, field, search, numFound)
    }
    return result, searchCount
}

我遇到的主要问题是:

  1. 当要查找的数字在列表中的位置比中间位置更靠后时,我是否仍在进行二分查找,还是已经转为顺序查找了?我该如何解决这个问题?我已经注释掉了另一种选项,因为它会导致堆栈溢出。

  2. 我想添加一个步骤计数器,以查看完成搜索需要多少步。这对其他搜索方法也有用。如果我按原样打印搜索计数,它总是显示为1。这是因为我需要返回它(因此在方法的头部调用它)吗?

我知道Go语言有一些可以简化这个过程的方法。我正在努力增加我的知识和编码技能。感谢您的建议。

英文:

I'm practicing an interview algorithm, now coding it in Go. The purpose is to practice basic interview algorithms, and my skills in Go. I'm trying to perform a Binary search of an array of numbers.

package main

import "fmt"

func main() {
	searchField := []int{2, 5, 8, 12, 16, 23, 38, 56, 72, 91}
	searchNumber := 23

    fmt.Println("Running Program")
    fmt.Println("Searching list of numbers: ", searchField)
    fmt.Println("Searching for number: ", searchNumber)

    numFound := false
    //searchCount not working. Belongs in second returned field
    result, _ := binarySearch2(searchField, len(searchField), searchNumber, numFound)
    fmt.Println("Found! Your number is found in position: ", result)
    //fmt.Println("Your search required ", searchCount, " cycles with the Binary method.")
}

func binarySearch2(a []int, field int, search int, numFound bool) (result int, searchCount int) {
	//searchCount removed for now.
	searchCount, i := 0, 0
	for !numFound {
		searchCount++
		mid := i + (field-i)/2
		if search == a[mid] {
			numFound = true
			result = mid
			return result, searchCount
		} else if search > a[mid] {
			field++
			//i = mid + 1 causes a stack overflow
			return binarySearch2(a, field, search, numFound)
		}
		field = mid
		return binarySearch2(a, field, search, numFound)
	}
	return result, searchCount
}

The main problems I'm coming across are:

  1. When the number is higher in the list than my mid search, am I truly continuing a binary search, or has it turned to a sequential? How can I fix that? The other option I've placed has been commented out because it causes a stack overflow.

  2. I wanted to add a step count to see how many steps it takes to finish the search. Something to use with other search methods as well. If I print out the search count as is, it always reads one. Is that because I need to return it (and therefore call for it in the header) in the method?

I understand Go has methods that streamline this process. I'm trying to increase my knowledge and coding skills. I appreciate your input.

答案1

得分: 11

你没有正确地进行二分查找。首先,你的for循环是无用的,因为条件树中的每个分支都有一个返回语句,所以它永远不会运行多于一次的迭代。看起来你开始以迭代的方式编写代码,然后转换为递归设置,但只是部分地进行了转换。

二分查找的思想是你有一个高位和低位索引,并在它们之间搜索中间点。你没有这样做,你只是增加了field变量并再次尝试(这将导致你搜索每个索引两次,直到找到该项或通过列表末尾运行而导致段错误)。然而,在Go中,你不需要跟踪高位和低位索引,因为你可以根据需要对搜索字段进行切片。

这是一个更优雅的递归版本:

func binarySearch(a []int, search int) (result int, searchCount int) {
    mid := len(a) / 2
    switch {
    case len(a) == 0:
        result = -1 // 未找到
    case a[mid] > search:
        result, searchCount = binarySearch(a[:mid], search)
    case a[mid] < search:
        result, searchCount = binarySearch(a[mid+1:], search)
        if result >= 0 { // 除了-1(未找到)之外的任何结果
            result += mid + 1
        }
    default: // a[mid] == search
        result = mid // 找到
    }
    searchCount++
    return
}

链接:https://play.golang.org/p/UyZ3-14VGB9

英文:

You're not doing a binary search properly. First off, your for loop is useless, since each branch in the conditional tree has a return statement in it, so it can never run more than one iteration. It looks like you started to code it iteratively, then swapped to a recursive setup, but only kinda halfway converted it.

The idea of a binary search is that you have a high and low index and search the midway point between them. You're not doing that, you're just incrementing the field variable and trying again (which will cause you to search each index twice until you find the item or segfault by running past the end of the list). In Go, though, you don't need to keep track of the high and low indexes, as you can simply subslice the search field as appropriate.

Here's a more elegant recursive version:

func binarySearch(a []int, search int) (result int, searchCount int) {
	mid := len(a) / 2
	switch {
	case len(a) == 0:
		result = -1 // not found
	case a[mid] &gt; search:
		result, searchCount = binarySearch(a[:mid], search)
	case a[mid] &lt; search:
		result, searchCount = binarySearch(a[mid+1:], search)
		if result &gt;= 0 { // if anything but the -1 &quot;not found&quot; result
			result += mid + 1
		}
	default: // a[mid] == search
		result = mid // found
	}
	searchCount++
	return
}

https://play.golang.org/p/UyZ3-14VGB9

答案2

得分: 5

func BinarySearch(a []int, x int) int {
    r := -1 // 未找到
    start := 0
    end := len(a) - 1
    for start <= end {
        mid := (start + end) / 2
        if a[mid] == x {
            r = mid // 找到
            break
        } else if a[mid] < x {
            start = mid + 1
        } else if a[mid] > x {
            end = mid - 1
        }
    }
    return r
}

这是一个二分查找的函数。给定一个已排序的整数数组 a 和一个目标值 x,函数会在数组中查找目标值,并返回其索引。如果目标值不存在于数组中,则返回 -1。

英文:
func BinarySearch(a []int, x int) int {
    r := -1 // not found
    start := 0
    end := len(a) - 1
    for start &lt;= end {
        mid := (start + end) / 2
        if a[mid] == x {
            r = mid // found
            break
        } else if a[mid] &lt; x {
            start = mid + 1
        } else if a[mid] &gt; x {
            end = mid - 1
        }
    }
    return r
}

答案3

得分: 2

这是一个离题的问题,但可能会帮助其他寻找简单二分查找的人。

由于标准库没有提供这个常见功能,所以在GitHub上有一个通用的二分查找模块:https://github.com/bbp-brieuc/binarysearch

英文:

Off-topic, but might help others looking for a simple binary search who could land here.

There's a generic binary search module on github since the standard library doesn't offer this common functionality: https://github.com/bbp-brieuc/binarysearch

答案4

得分: 1

func BinarySearch(array []int, target int) int {
	startIndex := 0
	endIndex := len(array) - 1
	midIndex := len(array) / 2
	for startIndex <= endIndex {

		value := array[midIndex]

		if value == target {
			return midIndex
		}

		if value > target {
			endIndex = midIndex - 1
			midIndex = (startIndex + endIndex) / 2
			continue
		}

		startIndex = midIndex + 1
		midIndex = (startIndex + endIndex) / 2
	}

	return -1
}

这是一个二分查找的函数,它接受一个整数数组和一个目标值作为参数,并返回目标值在数组中的索引。如果目标值不存在于数组中,则返回-1。

英文:
func BinarySearch(array []int, target int) int {
  startIndex := 0
  endIndex := len(array) - 1
  midIndex := len(array) / 2
  for startIndex &lt;= endIndex {

	value := array[midIndex]

	if value == target {
		return midIndex
	}

	if value &gt; target {
		endIndex = midIndex - 1
		midIndex = (startIndex + endIndex) / 2
		continue
	}

	startIndex = midIndex + 1
	midIndex = (startIndex + endIndex) / 2
}

  return -1
}

答案5

得分: 0

通用类型版本!(go 1.18)

时间复杂度:log2(n)+1

package main
import "golang.org/x/exp/constraints"

func BinarySearch[T constraints.Ordered](a []T, x T) int {
    start, mid, end := 0, 0, len(a)-1
    for start <= end {
        mid = (start + end) >> 1
        switch {
        case a[mid] > x:
            end = mid - 1
        case a[mid] < x:
            start = mid + 1
        default:
            return mid
        }
    }
    return -1
}

带有迭代计数器的完整版本请参见playground

英文:

generic type version ! (go 1.18)

Time Complexity : log2(n)+1

package main
import &quot;golang.org/x/exp/constraints&quot;

func BinarySearch[T constraints.Ordered](a []T, x T) int {
  	start, mid, end := 0, 0, len(a)-1
   	for start &lt;= end {
   		mid = (start + end) &gt;&gt; 1
   		switch {
   		case a[mid] &gt; x:
   			end = mid - 1
   		case a[mid] &lt; x:
   			start = mid + 1
   		default:
   			return mid
   		}
   	}
   	return -1
}

full version with iteration counter at playground.

huangapple
  • 本文由 发表于 2017年3月28日 23:27:01
  • 转载请务必保留本文链接:https://go.coder-hub.com/43073681.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定