原理很简单,网上很多解释,这里就不叙述了
/** * 二分查找 * @author * @date 2019/10/3112:54 */ public class BinarySearch { public static void main(String[] args) { //必须是有序的 int arr[]={2,5,7,8,10,22,22}; int i = binarySearch(arr, 0, arr.length - 1, 8); System.out.println(i); } public static int binarySearch(int[]arr, int left, int right, int value){ //当left>right时,说明完成整个数组的递归,仍然没有找到,结束递归 if (left>=right){ return -1; } int mid=(left+right)/2; int midVal=arr[mid]; if (value>midVal){//向右递归 return binarySearch(arr,mid+1,right,value); }else if (value<midVal){ return binarySearch(arr,left,mid-1,value); }else { return mid; } }第一种方法当碰到目标值时就会立刻返回,但如果有多个值相同,则无法全部返回
当找到目标值是不立刻返回,循环向其左右扫描,查找相同值的数据,存到List集合后返回
public static void main(String[] args) { //必须是有序的 int arr[]={2,5,7,8,10,22,22}; List<Integer> list = binarySearch(arr, 0, arr.length, 22); System.out.println(list); } public static List<Integer> binarySearch(int[]arr, int left, int right, int value){ //当left>right时,说明完成整个数组的递归,仍然没有找到,结束递归 if (left>=right){ return new ArrayList<Integer>(); } int mid=(left+right)/2; int midVal=arr[mid]; if (value>midVal){//向右递归 return binarySearch(arr,mid+1,right,value); }else if (value<midVal){ return binarySearch(arr,left,mid-1,value); }else { //找到mid值,向mid左边扫描,将所有满足满足value的元素下标加到集合中 List<Integer>list=new ArrayList<Integer>(); int temp = mid -1; while (true){ if (temp<0 || arr[temp] !=value){ break; } //放入集合 list.add(temp); temp-=1; } list.add(mid); //同样道理向右扫描 temp = mid +1; while (true){ if (temp>arr.length-1 || arr[temp] !=value){ break; } //放入集合 list.add(temp); temp+=1; } return list; } }结果:[5, 6]
二分查找问题: 当查找的数是边界值时,需要递归数次才可以查到
插值原理: 1.插值查找算法类似于二分查找,不同的是插值查找每次从自适应mid处开始查找 2.修改二分查找求mid的公式
int mid = left + (right – left) * (targetValue– arr[left]) / (arr[right] – arr[left])代码实现:
/** * 插值查找 * @author * @date 2019/10/3112:54 */ public class insertValueSearch { public static int insertValueSearch(int[]arr, int left, int right, int value){ int count=0; System.out.println(count++); if (left>right || value<arr[0] ||value>arr[arr.length-1]){ return -1; } int mid=left + (right -left) * (value - arr[left]) / (arr[right]- arr[left]); int midVal=arr[mid]; if (value>midVal){ return insertValueSearch(arr,mid+1,right,value); }else if (value<midVal){ return insertValueSearch(arr,left,mid-1,value); }else { return mid; } } }其他都和二分相同,只是修改了求mid的公式
测试:
public static void main(String[] args) { //必须是有序的 //int[]arr={0,1,2,3,4,5}; int arr[]=new int[100]; for (int i=0;i<100;i++){ arr[i]=i; } int i = insertValueSearch(arr, 0, arr.length - 1, 2); System.out.println(i); }结果: count:1 2
只查了1次
同样,使用插值法也是有限制的:
1.对于数据量较大,关键字分布均匀的数据来说,采用插值查找, 速度较快. 2.关键字分布不均匀的情况下,该方法未必比折半查找要好