golang二分查找算法实现

前言

项目中使用到有序数组查找特定元素,简单记录下Golang中二分查找算法。

目录

  • 前言
  • 二分查找算法简介
  • 二分查找算法简单实现
  • 二分查找算法进阶使用
      • 1. 查找第一个或最后一个等于目标值的元素:
      • 2. 查找第一个大于或等于目标值的元素:
      • 3. 查找最后一个小于或等于目标值的元素:
      • 4. 查找循环有序数组中的元素:


二分查找算法简介

二分查找算法是一种在有序数组中查找特定元素的高效算法。它的基本思想是通过不断将查找范围缩小一半,来快速定位目标元素是否存在。该算法要求数组是有序的,这是因为有序数组的特性允许我们在每一步中排除掉一半的元素。

以下是二分查找的基本步骤:

  1. 初始化: 确定数组的初始搜索范围,通常是整个数组。设定lowhigh分别为搜索范围的最低和最高索引。

  2. 中间元素: 计算中间元素的索引,即mid = (low + high) / 2

  3. 比较: 将目标值与中间元素进行比较。

    • 如果目标值等于中间元素,搜索成功,返回中间元素的索引。
    • 如果目标值小于中间元素,说明目标值可能在左半部分,更新high = mid - 1
    • 如果目标值大于中间元素,说明目标值可能在右半部分,更新low = mid + 1
  4. 循环: 重复上述步骤,直到搜索范围缩小到无法再分割,即low > high。此时,如果目标值存在,返回其索引;否则,返回-1表示目标值不存在。

二分查找的时间复杂度是O(log n),其中n是数组的大小。由于每一步都能将搜索范围减半,因此它在大型有序数组中的性能非常高效。这使得二分查找成为一种常用的查找算法。

请注意,二分查找要求数组是有序的,因此在使用之前需要确保数组有序。

二分查找算法简单实现

package main

import "fmt"

// 二分查找函数
func binarySearch(arr []int, target int) int {
	low, high := 0, len(arr)-1

	for low <= high {
		mid := (low + high) / 2

		if arr[mid] == target {
			return mid // 找到目标值,返回索引
		} else if arr[mid] < target {
			low = mid + 1 // 目标值在右半部分,缩小搜索范围
		} else {
			high = mid - 1 // 目标值在左半部分,缩小搜索范围
		}
	}

	return -1 // 目标值不存在
}

func main() {
	// 示例数组,必须是已排序的数组
	arr := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}

	// 要查找的目标值
	target := 7

	// 调用二分查找算法
	index := binarySearch(arr, target)

	if index != -1 {
		fmt.Printf("目标值 %d 在数组中的索引是 %d\n", target, index)
	} else {
		fmt.Printf("目标值 %d 不存在于数组中\n", target)
	}
}

在这个例子中,binarySearch函数接受一个已排序的数组和目标值作为参数,然后使用二分查找算法找到目标值的索引。如果找到目标值,返回其索引;如果找不到,返回-1。在main函数中,我们提供了一个已排序的数组和要查找的目标值,然后调用binarySearch函数进行查找。

二分查找算法进阶使用

二分查找算法在进阶使用时,可以通过一些变体或特殊情况的处理来满足更复杂的需求。以下是一些二分查找算法的进阶使用场景和技巧:

1. 查找第一个或最后一个等于目标值的元素:

在有序数组中,如果存在重复元素,可以通过稍作修改,使二分查找找到第一个等于目标值或最后一个等于目标值的元素。例如,找到数组中第一个等于目标值的索引:

func firstOccurrence(arr []int, target int) int {
    low, high := 0, len(arr)-1
    result := -1

    for low <= high {
        mid := (low + high) / 2

        if arr[mid] == target {
            result = mid     // 记录当前找到的索引
            high = mid - 1   // 继续在左半部分查找
        } else if arr[mid] < target {
            low = mid + 1    // 目标值在右半部分,缩小搜索范围
        } else {
            high = mid - 1   // 目标值在左半部分,缩小搜索范围
        }
    }

    return result
}

2. 查找第一个大于或等于目标值的元素:

如果需要找到数组中第一个大于或等于目标值的元素,可以进行相应的调整:

func firstGreaterOrEqual(arr []int, target int) int {
    low, high := 0, len(arr)-1
    result := -1

    for low <= high {
        mid := (low + high) / 2

        if arr[mid] >= target {
            result = mid     // 记录当前找到的索引
            high = mid - 1   // 继续在左半部分查找
        } else {
            low = mid + 1    // 目标值在右半部分,缩小搜索范围
        }
    }

    return result
}

3. 查找最后一个小于或等于目标值的元素:

类似地,如果需要找到数组中最后一个小于或等于目标值的元素:

func lastLessOrEqual(arr []int, target int) int {
    low, high := 0, len(arr)-1
    result := -1

    for low <= high {
        mid := (low + high) / 2

        if arr[mid] <= target {
            result = mid     // 记录当前找到的索引
            low = mid + 1    // 继续在右半部分查找
        } else {
            high = mid - 1   // 目标值在左半部分,缩小搜索范围
        }
    }

    return result
}

4. 查找循环有序数组中的元素:

如果数组是循环有序的,可以先找到旋转点,然后分别在两个有序部分中进行二分查找。

这些进阶使用场景展示了如何通过适当的调整,使得二分查找算法适用于更多的情况。在实际应用中,根据具体问题的要求,可以进一步定制二分查找算法的逻辑。

你可能感兴趣的:(golang,go,算法,golang,开发语言)