Fork me on GitHub

极客时间课程《数据结构与算法之美》笔记08 - 二分查找

二分查找

普通循环代码:

public int bsearch(int[] a, int n, int value) {
  int low = 0;
  int high = n - 1;

  while (low <= high) {
    int mid = (low + high) / 2;
    if (a[mid] == value) {
      return mid;
    } else if (a[mid] < value) {
      low = mid + 1;
    } else {
      high = mid - 1;
    }
  }

  return -1;
}

关键点:

  • 循环退出条件:是low<=high,而不是low<high
  • mid 取值,如果low和high比较大,则会让mid溢出。改进:mid = low+(high-low)/2。甚至优化为mid = (low+(high-low)>>1),右移k相当于缩小2^k倍
  • low和high的更新分别要+1,-1。如果low = mid则可能发生死循环。

递归写法:

// 二分查找的递归实现
public int bsearch(int[] a, int n, int val) {
  return bsearchInternally(a, 0, n - 1, val);
}

private int bsearchInternally(int[] a, int low, int high, int value) {
  if (low > high) return -1;

  int mid =  low + ((high - low) >> 1);
  if (a[mid] == value) {
    return mid;
  } else if (a[mid] < value) {
    return bsearchInternally(a, mid+1, high, value);
  } else {
    return bsearchInternally(a, low, mid-1, value);
  }
}

应用场景:

  • 依赖顺序表结构,最好是数组,可以根据下标快速访问。
  • 有序数据。
  • 数据量太小太大都不适合二分查找。

二分查找底层依赖数组,不需要存储额外的其他信息。

二分查找的变形与改进

常见问题:

  • 查找第一个,值(等于)给定值的元素
  • 查找最后一个,值(等于)给定值的元素
  • 查找第一个,值(大于等于)给定值的元素
  • 查找最后一个,值(大于等于)给定值的元素
public int bsearch(int[] a, int n, int value) {
  int low = 0;
  int high = n - 1;
  while (low <= high) {
    int mid =  low + ((high - low) >> 1);
    if (a[mid] > value) {
      high = mid - 1;
    } else if (a[mid] < value) {
      low = mid + 1;
    } else {
      if ((mid == 0) || (a[mid - 1] != value)) return mid;
      else high = mid - 1;
    }
  }
  return -1;
}

核心处理部分:当a[mid] ==value的时候要有判断,看是否前面元素和它不相等。

 if ((mid == 0) || (a[mid - 1] != value)) return mid;
      else high = mid - 1;

posted on 2019-08-02 15:44  JackKing_defier  阅读(194)  评论(0编辑  收藏  举报