二分查找的思想

查找0–99之间的数字,如果查找一个数字,我们每次取中间middle数判断,如果中间数大了,就像0–middle区间找,如果小了就像middle–99区间找,假如我们查找的是23
数据结构和算法--二分查找
二分查找是针对的有序集合,每次都跟区间中间元素的对比,将待查找的区间缩小一半,直到找到元素,或者区间缩小到0

二分查找的时间复杂度O(logn)

假设查找的区间为n,每次缩小一半,最坏情况下直到缩小到0,才结束
数据结构和算法--二分查找
当n/2k=1时,K就是总共缩小的次数,每次缩小涉及元素的一次比较,经过k此缩小,时间复杂度就是O(k),通过n/2k=1,那么k=log(n),所以时间复杂度为O(logn),这是一种极其高效的时间复杂度

二分查找的简单实现

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;
}

二分查找的局限性

1 二分查找依赖数组
是否可以使用链表,答案不可以,二分查找主要用了根据下标O(1)时间复杂度,随机访问数据

2 二分查找针对的是有序数据

3 数据量太小,不适合二分查找
太小的话,直接顺序遍历就行了

4 数据量太大,也不适合二分查找
因为我二分查找依赖数组,所以需要连续的内存空间,假如1G的数据,需要1G的连续内存空间,这个不现实

二分查找的变形

上面实现的二分查找没有考虑到,数组有重复的数据的情况,下面我们就对这种情况分析一下
数据结构和算法--二分查找
变体一 查找第一个等于这个元素的数据

数据结构和算法--二分查找
这个里面存在重复元素,我们希望找到第一个等于8的值,也就是下标为5的值,但不希望下标是6和7

看下实现

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;
}

每当数值和查找的数据相等时,如果数据已经是第一个了或者mid的上一个数据不等于这个值,就直接返回,否则就意味着有前边有重复的数据,那就把high=mid-1,继续查找

变体二 查找最后一个等于该值得元素

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 == n - 1) || (a[mid + 1] != value)) return mid;
      else low = mid + 1;
    }
  }
  return -1;
}

思路跟上方一样

变体三 查找第一个大于等于给定值的元素

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) {
      if ((mid == 0) || (a[mid - 1] < value)) return mid;
      else high = mid - 1;
    } else {
      low = mid + 1;
    }
  }
  return -1;
}

变体四 查找最后一个小于等于给定值得元素

public int bsearch7(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 ((mid == n - 1) || (a[mid + 1] > value)) return mid;
      else low = mid + 1;
    }
  }
  return -1;
}

相关文章: