对于一个排好序的数据集合,对某一个数进行查找的时候,我们考虑先和中间角标(因为排好序就是中间大小的数比较,之后即可确定在”一个新的”数据集合里面再这样查找),采用循环和递归方式来实现这个算法。
非递归实现(循环)
思路:
有两种情况下会结束循环,一是找到了,一是找完了也没找到,我们来看研究对象,一个是待查找的key,一个是数据集合,这也应该是查找函数的参数,返回值应该是key的类型。
而数据集合(数组)我们考虑采用角标来描述(算法中的区间),确定好变量(区间的头尾,key)之后在循环里加以大小比较和折半的核心处理代码即可。
import java.util.Arrays;
public class BinarySearch {
public static int rank(int key,int[] a)
{
int low = 0;
int high = a.length - 1;
while(low <= high)
{
int mid = low + (high - low)/2;
//high – low 的方式比 (high+low)/2安全
if(key < a[mid])
high = mid - 1; //显然是不包括mid的
else if(key > a[mid])
low = mid + 1;
else
return mid;
}
return -1;
}
public static void main(String args[])
{
int[] arr = {4,5,6,1,2,3,9,8,7};
Arrays.sort(arr); //调用静态方法
int key = 3;
System.out.println(rank(key,arr));
}
}
递归实现:
思路:
递归的点应该在if(在左边/右边的新区间),因为这是重复的部分,那么,递归最重要的参数应该是什么呢?key显然是需要的,数组本身显然是不行了,因为数组本身并不会变化,我们递归的一定是一个变化的参数,那么,应该是新的区间,而区间是由首尾角标描述的,显然数组需要被处理,也是必要的参数对象。注意递归需要有结束的条件判断
import java.util.Arrays;
public class BinarySearch {
public static int rank(int key,int[] arr)
{
return rank(key,arr,0,arr.length-1);
}
public static int rank(int key,int[] arr,int low,int high)
{
if(low > high)
return -1;
int mid = low + (high - low)/2;
if(key < arr[mid])
return rank(key,arr,low,mid-1);
else if(key > arr[mid])
return rank(key,arr,mid+1,high);
else
return mid;
}
public static void main(String args[])
{
int[] arr = {4,5,6,1,2,3,9,8,7};
Arrays.sort(arr);
int key = 3;
System.out.println(rank(key,arr));
}
}
书上讲递归非常好的三句话:
1. 方法的第一条语句总是包含一个return 语句
2. 递归调用总是在尝试解决一个规模更小的问题,以上第三四个参数一直在缩小
3. 递归调用的符问题和尝试解决的子问题不应该有交集,以上两个字问题各自操作的数组部分是不同的