基础数据结构—查找

二分查找(折半查找)

public class BinarySearch {
    public int search(int[] arr, int findVal) {
        int left = 0;
        int right = arr.length - 1;
        return binary(arr, left, right, findVal);
    }

    public int binary(int[] arr, int left, int right, int findVal) {
        if (left > right) {
            return -1;
        }
        int mid = (left + right) / 2;
        int midVal = arr[mid];
        if (findVal > midVal) {
        	//目标值小于中轴值向左递归
            return binary(arr, mid + 1, right, findVal);
        } else if (findVal < midVal) {
        	//目标值小于中轴值向右递归
            return binary(arr, left, mid - 1, findVal);
        } else {
            return mid;
        }
    }
}
  1. 传入目标数组,左边界,右边界和目标值
  2. 左右边界相加对 2 取整获得中轴值索引
  3. 如果目标值小于中轴值向左递归大于中轴值向右递归
  4. 找到目标值返回其下标

如果数组中存在相同的目标值如何返回所有索引

public class BinarySearch {
    public List<Integer> search(int[] arr, int findVal) {
        int left = 0;
        int right = arr.length - 1;
        return binary(arr, left, right, findVal);
    }

    public List<Integer> binary(int[] arr, int left, int right, int findVal) {
        if (left > right) {
            return null;
        }
        int mid = (left + right) / 2;
        int midVal = arr[mid];
        if (findVal > midVal) {
            return binary(arr, mid + 1, right, findVal);
        } else if (findVal < midVal) {
            return binary(arr, left, mid - 1, findVal);
        } else {
        	//创建结果集
            List<Integer> resIndexList = new ArrayList<Integer>();
            //从目标值左边开始遍历
            int temp = mid - 1;
            while (true) {
            	//遍历目标值左边所有的值
                if (temp < 0 || arr[temp] != findVal) {
                    break;
                }
                resIndexList.add(temp);
                --temp;
            }
            //添加当前目标值
            resIndexList.add(mid);
            temp = mid + 1;
            while (true) {
            	//遍历目标值右边所有的值
                if (temp > arr.length - 1 || arr[temp] != findVal) {
                    break;
                }
                resIndexList.add(temp);
                temp++;
            }
            //返回结果集
            return resIndexList;
        }
    }
}

插值查找

public class InsertValSearch {
    public int search(int[] arr, int findVal) {
        int left = 0;
        int right = arr.length - 1;
        return insertVal(arr, left, right, findVal);
    }

    public int insertVal(int[] arr, int left, int right, int findVal) {
        if (left > right) {
            return -1;
        }
        // mid自适应
        int mid = left + (findVal - arr[left]) / (arr[right] - arr[left]) * (right - left);
        int midVal = arr[mid];
        if (findVal > midVal) {
            return insertVal(arr, mid + 1, right, findVal);
        } else if (findVal < midVal) {
            return insertVal(arr, left, mid - 1, findVal);
        } else {
            return mid;
        }
    }
}

相较于二分查找唯一的不同点在于 mid 的取值策略不同
mid自适应公式:
在这里插入图片描述
注:对于数据量较大,关键字分布较均匀的表来说采用插值查找速度较快。
但在关键字分布不均匀的情况下,该方法不一定要比二分查找好。

斐波那契查找

public class FibSearch {
	//创建斐波那契数组
    public int[] fib() {
        int[] f = new int[20];
        f[0] = 1;
        f[1] = 1;
        for (int i = 2; i < 20; ++i) {
            f[i] = f[i - 1] + f[i - 2];
        }
        return f;
    }

    public int serach(int[] arr, int findVal) {
        int left = 0;
        int right = arr.length - 1;
        //获取一个长度为20的斐波那契数组,最大数为4181
        int[] fib = fib();
        //中轴值索引
        int mid = 0;
        //计数器
        int k = 0;
        //选择合适的斐波那契数
        while (right + 1 > fib[k] - 1) {
            k++;
        }
        //把原数组拷贝到长度为fib[k]的辅助数组中
        int[] temp = Arrays.copyOf(arr,fib[k]);
        //把辅助数组中含0位置用原数组最后一位补齐
        for (int i = right + 1; i < temp.length; ++i) {
            temp[i] = arr[right];
        }
     
        while (left <= right) {
        	 //斐波那契中轴值索引
             mid = left + fib[k - 1] - 1;
             if (findVal < temp[mid]) {
                 right = mid - 1;
                 k--;
             } else if (findVal > temp[mid]) {
                 left = mid + 1;
                 k-=2;
             } else {
                 if (mid > right) {
                     return right;
                 } else {
                     return mid;
                 }
             }
        }
        return -1;
    }
}
  1. 事先准备一个长度为20的斐波那契数组,最大值为4181
  2. 从斐波那契数组中选一个合适的值(至少大于等于原数组的长度)作为辅助数组的长度
    并把原数组的内容copy到辅助数组,辅助数组多出部分的0用原数组最右边的值填充
  3. mid 取值策略如图
    mid取值策略
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值