倒霉的菜鸟

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

顺序查找?

所谓顺序查找,就是从第一个元素开始,遍历表中的元素,以找到对应的节点

对于线性表来说, 如果该表是无序表, 那么不管它采用的是顺序存储还是链式存储, 都必须使用顺序查找。

如果该表是有序的,但是采用链式存储, 也必须使用顺序查找

当该表有序且顺序存储时, 我们可以采用二分查找

二分查找?

所谓二分查找就是说,针对一个有序数组,我们先取数组的中间值和要查找的目标值比较,如果比目标值大,就在左边的一半中查找,查找方式还是先取中间值比较。。。

 

 这样对于一个长度为n的有序数组, 查找一个数所花费的时间最多为log2n

如长度为8的数组,最多3次就可以定位到

 1 /**
 2      * 使用二分查找在array数组中查询target的位置
 3      * @param array
 4      * @param startIndex
 5      * @param endIndex
 6      * @param target
 7      * @return
 8      */
 9     private static int binarySearch(int[] array, int startIndex, int endIndex, int target) {
10         int low = startIndex;
11         int high = endIndex-1;
12         while (low<=high) {
13             //取中间
14             int middle = (low + high)>>1;
15             int midValue = array[middle];
16             //如果中间值比target小, 就在右边查找
17             if (midValue < target) {
18                 //移动低位指针到middle+1的位置
19                 //+1是为了避免重复查找,因为Middle位置其实已经比较过了,相等的话就会返回
20                 //另外,如果不加1, 每次都会重复查找一个数据,那么最后剩下2个数据时,如array[10], array[11], 
21                 //要查找array[11], low = 10, high = 11, 那么middle=10,low=middle进入死循环
22                 low = middle+1;
23             } else if (midValue > target) {
24                 //移动高位指针到middle-1的位置
25                 high = middle-1;
26             } else {
27                 return middle;
28             }
29         }
30         //通常返回最后一次查找的低位指针的位置 
31         return -(low+1);
32     }
1 public static void main(String[] args) {
2         int[] array = {4,7,8,10,14,21,22,36,62,77,81,91};
3         int index = binarySearch(array, 0, array.length, 91);
4         System.out.println(index);
5     }

 

网上流传一种说法: 90%的程序员都写不出没有Bug的二分查找

其实这里的问题在于

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

这一行,如果low和high的值很大,可能会有内存溢出的问题 

所以我们修改这一行代码为:
int middle = low + ((high-low)>>1);

注意,由于移位运算的优先级较低, 要用括号括起来

 

这里有个疑惑, 我们之前了解过递归, 所谓递归就是指一个程序调用自身的编程思想。那么很明显二分查找应该是可以用递归实现的

 直接上代码试一下

 1 private static int binarySearchWithRecursion(int[] array, int startIndex, int endIndex, int target) {
 2         //取中间
 3         int middle = startIndex + ((endIndex-startIndex)>>1);
 4         int midValue = array[middle];
 5         if (midValue < target) {
 6             binarySearchWithRecursion(array, middle+1, endIndex, target);
 7         } else if(midValue > target){
 8             binarySearchWithRecursion(array, startIndex, middle-1, target);
 9         } else {
10             return middle;
11         }
12         return -1;
13     }
1 public static void main(String[] args) {
2         int[] array = {4,7,8,10,14,21,22,36,62,77,81,91};
3         binarySearchWithRecursion(array, 0, array.length-1, 36);
4     }

看看结果

 

 居然没找到?

带着一脸问号进行了debug,发现查找过程中确实找到了36这个元素,但由于我们调用递归方法时(如执行到第6行)下面的代码(7-12行)会被压栈,我们知道栈内的执行顺序是先进后出, 所以最后都会执行12行 return -1 的操作

为了验证这个猜想, 我修改了一下代码, 删掉了return的操作

 1 private static void binarySearchWithRecursion(int[] array, int startIndex, int endIndex, int target) {
 2         //取中间
 3         int middle = startIndex + ((endIndex-startIndex)>>1);
 4         int midValue = array[middle];
 5         if (midValue < target) {
 6             binarySearchWithRecursion(array, middle+1, endIndex, target);
 7         } else if(midValue > target){
 8             binarySearchWithRecursion(array, startIndex, middle-1, target);
 9         } else {
10             System.out.println(middle +" ");
11         }
12     }

测试结果:

 

 everything works fine

 

但是看到网上有大量的利用递归去写二分查找的博客,像这样:

 

 同样的代码我在本地运行始终是查找不到的,看了半天 不知道是哪里的问题,还希望路过的朋友们指点一二。

 

posted on 2021-10-08 14:24  倒霉的菜鸟  阅读(79)  评论(0编辑  收藏  举报