二分查找
普通版
//二分查找的前提是“这个数组是有序的”
public class BinarySearch {
public static void main(String[] args) {
int arr[]={1, 8, 10, 89, 1000, 1234};
int resIndex=binarySearch(arr, 0, arr.length, 8);
System.out.println("resIndex = "+resIndex);
}
public static int binarySearch(int[] arr, int left, int right, int findVal){
System.out.println("查找次数");//只需要查找一次就能找到了
//当left>right时,说明递归整个数组,但是没有找到
//当这个值不存在的时候,抛出结果为-1
if (left>right){
return -1;
}
int mid=(left+right)/2;
int midVal=arr[mid];
if (findVal>midVal){
//向右递归
return binarySearch(arr, mid+1, right, findVal);
}else if (findVal<midVal){
//向左递归
return binarySearch(arr, left, mid-1, findVal);
}else {
return mid;
}
}
}
升级版
一个有序数组里,有多个相同的数值,如何把所有的数值都查找到
public class BinarySearchUpdate {
public static void main(String[] args) {
int arr[]={1, 8, 10, 89, 1000, 1000, 1000, 1234};
List resIndexList=binarySearch(arr, 0, arr.length-1, 1000);
System.out.println("resIndexList = "+resIndexList);
}
public static ArrayList<Integer> binarySearch(int[] arr, int left, int right, int findVal){
//当left>right时,说明递归整个数组,但是没有找到
//当这个值不存在的时候,抛出结果为-1
if (left>right){
return new ArrayList<Integer>();
}
int mid=(left+right)/2;
int midVal=arr[mid];
if (findVal>midVal){
//向右递归
return binarySearch(arr, mid+1, right, findVal);
}else if (findVal<midVal){
//向左递归
return binarySearch(arr, left, mid-1, findVal);
}else {
ArrayList<Integer> resIndexlist =new ArrayList<Integer>();
int temp=mid-1;
while (true){
if (temp<0 || arr[temp]!=findVal){//退出
break;
}
//否则把temp放到resIndexlist里
resIndexlist.add(temp);
temp-=1;
}
resIndexlist.add(mid);
//向mid索引值的右边扫描,把所有满足1000,的元素的下标,加入到集合里
temp=mid+1;
while (true){
if (temp>arr.length-1 || arr[temp]!=findVal){
break;
}
resIndexlist.add(temp);
temp+=1;
}
return resIndexlist;
}
}
}
插值查找
//插值查找就是在二分查找的基础上改写的,也需要数组是有序的
//对于数据量较大,关键字分布比较均匀的查找来说,使用插值查找,速度比较快
//如果关键字分布不均匀,则这个方法不一定比折半查找好
public class InsertValueSearch {
public static void main(String[] args) {
int arr[] = new int[100];
for (int i = 0; i < 100; i++) {
arr[i] = i + 1;
}
// System.out.println(Arrays.toString(arr));
int index=insertValueSearch(arr, 0, arr.length-1, 1);
System.out.println(index);
}
public static int insertValueSearch(int arr[], int left, int right, int findVal) {
System.out.println("查找次数");//只需要查找一次就能找到了,比二分查找少很多
//排除错误情况
//注意:findVal<arr[0] 和 findVal>arr[arr.length-1] 必须要有,否则得到的mid可能会越界
if (left > right || findVal < arr[0] || findVal > arr[arr.length - 1]) {
return -1;
}
//求出mid
int mid = left + (right - left) * (findVal - arr[left]) / (arr[right] - arr[left]);
int midVal = arr[mid];
if (findVal > midVal) {
//应该向右边递归
return insertValueSearch(arr, mid + 1, right, findVal);
} else if (findVal < midVal) {
return insertValueSearch(arr, left, mid - 1, findVal);
} else {
return mid;
}
}
}
斐波那契查找
public class FibonacciSearch {
public static int maxSize=20;
public static void main(String[] args) {
int arr[]={1,8,10,89,1000,1234};
System.out.println("index="+fibSearch(arr,1234));
}
//因为后面我们的mid=low+F(k-1)-1,需要使用到斐波那契数列
//因此我们需要先获取到一个斐波那契数列
//非递归方法得到一个斐波那契数列
public static int[] fib(){
int f[]=new int[maxSize];
f[0]=1;
f[1]=1;
for (int i = 2; i < maxSize; i++) {
f[i]=f[i-1]+f[i-2];
}
return f;
}
//编写斐波那契查找算法
//使用非递归的方式编写算法
public static int fibSearch(int a[], int key){
int low=0;
int high=a.length-1;
int k=0;//表示斐波那契分割数值的下标
int mid=0;//存放mid值
int f[]=fib();//获取到斐波那契数列
//获取到分割数值的下标
while (high > f[k]-1) {
k++;
}
//因为放f[k]值可能大于a的长度,因此我们需要使用Arrays类,构造一个新的数组,并指向a[]
//不足的部分使用0填充
int temp[]= Arrays.copyOf(a, f[k]);
//实际上需求使用a数组最后的数值填充temp
for (int i = high+1; i < temp.length; i++) {
temp[i]=a[high];
}
//使用while来循环处理,找到我们的数key
while (low<=high){//只要这个条件满足,就可以找
mid=low+f[k-1]-1;
if (key<temp[mid]){//我们应该继续向数组的前面查找(左边)
high=mid-1;
//为什么是k--
k--;
}else if(key>temp[mid]){
low=mid+1;
k-=2;
}else {
//找到,需要确定,返回的是哪个下标
if (mid<=high){
return mid;
}else {
return high;
}
}
}
return -1;
}
}