이분 탐색

이분 탐색


  • "지수적 폭발"을 역으로 취한 탐색 방법
  • 탐색 범위를 탐색해 갈 때마다 반으로 해 간다
  • 즉, 한 번 더 조사하면 두 배의 검색 범위에서 찾아낼 수 있도록 함으로써 대량의 데이터에서 효율적으로 찾아낼 수 있다.
  • 검색 대상 레코드 열의 길이가 $n$이면 $\log_2 n$회 영역을 반으로 하면 탐색해야 하는 범위가 $1$이므로 이진 탐색은 $O(\log_2 n) $에서 효율적입니다
  • 검색 범위를 좁히는 근거가 필요하다. 따라서 검색 대상은 "정렬"되어야합니다
  • 2분 탐색에 있어서의 「열」로서 배열을 사용한다(선형 리스트는 사용하지 않는다)
  • 왜냐하면, 어느 범위를 결정했을 때, 정확히 가운데에 있는 데이터에 즉시 액세스 할 수 있어야 하기 때문


  • 🚀 탐색 알고리즘으로 2분 탐색을 채용할 때의 데이터 구조의 채우는 성질


  • 데이터가 정렬되었습니다
  • 어느 범위를 결정했을 때, 가운데에 있는 데이터에 즉시 액세스 할 수 있다

  • 이것을 만족하는 데이터 구조는 "배열"또는 "이분 트리"
  • 배열은 랜덤 액세스 가능하다
  • 이분 트리는 좌우에 매달리는 노드의 개수가 대체로 같다고 이분 탐색에 적합하다

  • 소박하게 하다


  • 루프를 돌 때마다 두 번 비교하는 것이 낭비
  • package main
    
    import (
        "fmt"
    )
    
    func BinarySearch(array *[]int, target int) (bool, int) {
        low, high := 0, len(*array)-1
        for low <= high {
            middle := (low + high) / 2
            if target <= (*array)[middle] {
                high = middle - 1
            }
            if target >= (*array)[middle] {
                low = middle + 1
            }
        }
        return low == high + 2, low - 1 // 失敗しているときは low == high + 1 になっている
    }
    
    func LinearSearch(array *[]int, target int) (bool, int) {
        for i := range *array {
            if (*array)[i] == target {
                return true, i
            }
        }
        return false, -1
    }
    
    func main() {
        array := make([]int, 10)
        for i := range array {
            array[i] = i
        }
        fmt.Println(array)
        if found, _ := BinarySearch(&array, 3); found {
            fmt.Println("Found!")
        } else {
            fmt.Println("Not Found!")
        }
    }
    

    좀 더 현명하게


    package main
    
    import "fmt"
    
    func BinarySearch(array []int, target int) (bool, int) {
        n := len(array) - 1
        low, high := 1, n
        for low <= high {
            mid := (low + high) / 2
            if target < array[mid] {
                high = mid - 1
            } else {
                low = mid + 1
            }
        }
        pos := high
        if pos == 0 {
            return false, -1
        } else {
            return true, pos
        }
    }
    
    func main() {
        array := make([]int, 11)
        for i := range array {
            array[i] = i*i
        }
        if found, _ := BinarySearch(array, 25); found {
            fmt.Println("Found!")
        } else {
            fmt.Println("Not Found!")
        }
    }
    
  • 「무엇을 하고 있는 것인가」가 언뜻 보면 잘 모른다. 이 경우 루프의 불변 조건에 주목하십시오.

    【불변 조건】
    1. $j = 1, 2, ..., low-1$에 대해 $array[j] <= target$
    2. $j = high + 1, high + 2, ..., n - 1, n$에 대해 $array[j] > target$







  • 좋은 웹페이지 즐겨찾기