1、迭代法查询(顺序查找)

迭代遍历法查询无序集合非常简单粗暴,直接遍历检查是否是需要查找的值,发现等于的值后则直接返回即可,因此其时间复杂度为 快速查找的算法实现 - 图1

  1. private static int find(int targetValue, Integer[] numbers) {
  2. for (int i = 0; i < numbers.length; i++) {
  3. if (targetValue == numbers[i]) {
  4. return i;
  5. }
  6. }
  7. return -1;
  8. }

2、二分法查找有序集合

二分法对于查询有序集合效率非常高,其算法特别简单,但细节上可能让人错误百出,比如边界问题以及终止条件,

其时间复杂度为 第一次查询为 N/2 次,第二次查询为 N/4 次,所以当查询到元素集合等于1 的时候结束,假设执行K次,即 快速查找的算法实现 - 图2 经过计算可知 快速查找的算法实现 - 图3

  1. /**
  2. * 二分法查找
  3. *
  4. * @apiNote 时间复杂度: O(logN)
  5. */
  6. private static int binSearch(int target, Integer[] nums) {
  7. int startIndex = 0, endIndex = nums.length;
  8. while ((startIndex <= endIndex)) {
  9. int minIndex = (startIndex + endIndex) / 2;
  10. if (minIndex >= nums.length) {
  11. return -1;
  12. }
  13. int mid = nums[minIndex];
  14. if (mid == target) {
  15. return minIndex;
  16. }
  17. if (target < mid) {
  18. endIndex = minIndex - 1;
  19. } else {
  20. startIndex = minIndex + 1;
  21. }
  22. }
  23. return -1;
  24. }

至于为什么 startIndex = mid + 1endIndex = mid - 1? 这也是二分查找的一个难点,不过只要你能理解前面的内容,就能够很容易判断。需要明确了「搜索区间」这个概念,而且本算法的搜索区间是两端都闭的,即 [left, right]。那么当我们发现索引 mid 不是要找的 target 时,应该直接去掉midIndex去搜索 [left, mid-1] 或者 [mid+1, right] 对不对?因为 mid 已经搜索过,应该从搜索区间中去除
**
同样的,二分法也有缺点,比如我们需要查询出[1,2,3,3,3,4] 中3的最左边界以及最右边界,那么二分法此时是不适合的,需要经过改造下,改造的对象就在于边界上,这里不过多的赘述,有兴趣的读者可以访问 链接https://github.com/labuladong/fucking-algorithm/blob/master/数据结构系列/单调栈.md 学习