極客時間課程《數據結構與算法之美》筆記08 - 二分查找

二分查找

普通循環代碼:java

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

應用場景:

  • 依賴順序表結構,最好是數組,能夠根據下標快速訪問。
  • 有序數據。
  • 數據量過小太大都不適合二分查找。

二分查找底層依賴數組,不須要存儲額外的其餘信息。code

二分查找的變形與改進

常見問題:遞歸

  • 查找第一個,值(等於)給定值的元素
  • 查找最後一個,值(等於)給定值的元素
  • 查找第一個,值(大於等於)給定值的元素
  • 查找最後一個,值(大於等於)給定值的元素
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的時候要有判斷,看是否前面元素和它不相等。class

if ((mid == 0) || (a[mid - 1] != value)) return mid;
      else high = mid - 1;
相關文章
相關標籤/搜索