一文说尽“二分查找”

一文说尽“二分查找”

本文总结了二分查找算法及其变种。

查找指定大小的值(无重复)

int BinarySearch::binary_search_unique(std::vector<int> v, int target) {
  int low = 0;
  int high = v.size() - 1;
  int middle;

  while (low <= high) {

    middle = low + ((high - low) >> 1);

    if (target < v[middle]) {
      high = middle - 1;
    } else if (target > v[middle]) {
      low = middle + 1;
    } else {
      return middle;
    }
  }

  return -1;
}

查找第一个值等于定值的元素(有重复)

int BinarySearch::bin_search_first_eq(std::vector<int> v, int target) {
  int low = 0;
  int high = v.size() - 1;
  int middle;

  while (low <= high) {
    middle = low + ((high - low) >> 1);

    if (target < v[middle]) {
      high = middle - 1;
    } else if (target > v[middle]) {
      low = middle + 1;
    } else {
      // 不直接返回,而是判断自己是否为所有相等元素中的第一个元素
      if (0 == middle || v[middle] != v[middle - 1]) {
        return middle;
      } else {
        high = middle - 1;
      }
    }
  }

  return -1;
}

查找最后一个值等于定值的元素

int BinarySearch::bin_search_last_eq(std::vector<int> v, int target) {
  int low = 0;
  int high = v.size() - 1;
  int middle;

  while (low <= high) {
    middle = low + ((high - low) >> 1);

    if (target < v[middle]) {
      high = middle - 1;
    } else if (target > v[middle]) {
      low = middle + 1;
    } else {
      // 不直接返回,而是判断自己是否为所有相等元素中的最后一个元素
      if ((v.size() - 1) == middle || v[middle] != v[middle + 1]) {
        return middle;
      } else {
        low = middle + 1;
      }
    }
  }

  return -1;
}

查找第一个大于等于定值的元素

int BinarySearch::bin_search_first_ge(std::vector<int> v, int target) {
  int low = 0;
  int high = v.size() - 1;
  int middle;

  while (low <= high) {
    middle = low + ((high - low) >> 1);

    if (target > v[middle]) {
      low = middle + 1;
    } else {
      // 判断自己是否为所有符合要求的元素中的第一个
      if (0 == middle || v[middle - 1] < target) {
        return middle;
      } else {
        high = middle - 1;
      }
    }
  }

  return -1;
}

查找最后一个小于等于定值的元素

int BinarySearch::bin_search_last_le(std::vector<int> v, int target) {
  int low = 0;
  int high = v.size() - 1;
  int middle;

  while (low <= high) {
    middle = low + ((high - low) >> 1);

    if (target < v[middle]) {
      high = middle - 1;
    } else {
      // 判断自己是否为所有符合要求的元素中的最后一个
      if ((v.size() - 1) == middle || v[middle + 1] > target) {
        return middle;
      } else {
        low = middle + 1;
      }
    }
  }

  return -1;
}

循环数组上的二分查找(无重复)

leetcode: search-in-rotated-sorted-array

int BinarySearch::bin_search_unique_cycle(std::vector<int> v, int target) {
  int low = 0;
  int high = v.size() - 1;
  int middle;

  while (low <= high) {
    middle = low + ((high - low) >> 1);

    if (v[low] <= v[high]) {
      if (v[middle] > target) {
        high = middle - 1;
      } else if (v[middle] < target) {
        low = middle + 1;
      } else {
        return middle;
      }
    } else {
      if (v[low] <= v[middle]) {
        if (target > v[middle]) {
          low = middle + 1;
        } else if (target < v[middle]) {
          if (target > v[low]) {
            high = middle - 1;
          } else if (target < v[low]) {
            low = middle + 1;
          } else {
            return low;
          }
        } else {
          return middle;
        }
      } else {
        if (target > v[high]) {
          high = middle - 1;
        } else if (target < v[high]) {
          if (target > v[middle]) {
            low = middle + 1;
          } else if (target < v[middle]) {
            high = middle - 1;
          } else {
            return middle;
          }
        } else {
          return high;
        }
      }
    }
  }

  return -1;
}

循环数组上的查找最小元素(无重复)

leetcode: find-minimum-in-rotated-sorted-array

int BinarySearch::find_min_unique_cycle(std::vector<int> v) {
  int low = 0;
  int high = v.size() - 1;
  int middle;

  while (low <= high) {
    middle = low + ((high - low) >> 1);

    if (v[low] <= v[high]) {
      return v[low];
    } else {
      if (v[low] <= v[middle]) {
        low = middle + 1;
      } else {
        if (0 == middle || v[middle - 1] > v[middle]) {
          return v[middle];
        } else {
          high = middle - 1;
        }
      }
    }
  }

  return 0;
}

循环数组上的二分查找

leetcode: search-in-rotated-sorted-array-ii

bool BinarySearch::bin_search_cycle(std::vector<int> v, int target) {
  if (v.empty()) {
    return false;
  }

  int low = 0;
  int high = v.size() - 1;
  int middle;

  while (low <= high) {
    middle = low + ((high - low) >> 1);

    if (target == v[middle]) {
      return true;
    }

    if (v[low] == v[middle] && v[middle] == v[high]) {
      low++;
      high--;
      continue;
    }

    if (v[low] <= v[middle]) {
      if (target >= v[low] && target < v[middle]) {
        high = middle - 1;
      } else {
        low = middle + 1;
      }
    } else {
      if (target > v[middle] && target <= v[high]) {
        low = middle + 1;
      } else {
        high = middle - 1;
      }
    }
  }

  return false;
}

循环数组上的查找最小元素

leetcode: find-minimum-in-rotated-sorted-array-ii

int BinarySearch::find_min_cycle(std::vector<int> v) {
  if (v.empty()) {
    throw std::invalid_argument("元素个数不能为0");
  }

  int low = 0;
  int high = v.size() - 1;
  int middle = 0;

  if (high == 0) {
    return v[0];
  }

  while (v[low] >= v[high]) {
    middle = low + ((high - low) >> 1);

    if (1 == high - low) {
      return v[high];
    }

    if (v[low] == v[middle] && v[middle] == v[high]) {
      return min_in_order(v);
    }

    if (v[low] <= v[middle]) {
      low = middle;
    } else if (v[middle] <= v[high]) {
      high = middle;
    }
  }

  return v[low];
}

int BinarySearch::min_in_order(std::vector<int> v) {
  if (v.empty()) {
    throw std::invalid_argument("参数不能为空!");
  }

  int min = v[0];

  for (auto &item : v) {
    if (item < min) {
      min = item;
    }
  }

  return min;
}

应用

求一个数的平方根

double BinarySearch::sqrt(double n) {
  double epsilon = 0.000001;

  double low = 0.0;
  double high = n;
  double middle;

  while (low <= high) {
    middle = low + ((high - low) / 2.0);

    if (std::abs(middle * middle - n) < epsilon) {
      return middle;
    }

    if (middle * middle > n) {
      high = middle;
    } else {
      low = middle;
    }
  }
}

当然,这里使用“牛顿迭代法”更合适,下面也给出它的实现

double BinarySearch::sqrt_newton(double n) {
  double epsilon = 0.000001;

  double x_0 = n / 2.0;
  double x = n / 2.0;

  while (true) {
    if (std::abs(x_0 * x_0 - n) < epsilon) {
      return x_0;
    }

    x = x_0 - ((x_0 * x_0 - n) / (2.0 * x_0));

    x_0 = x;
  }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值