查找算法介绍
在 java 中,我们常用的查找有四种:
1) 顺序(线性)查找
2) 二分查找/折半查找
3) 插值查找
4) 斐波那契查找
一、线性(顺序)查找算法
源代码:OrderSearch.java
1、题意说明
有一个数列: {1,8,10, 89,1000,1234} ,判断数列中是否包含此名称【顺序查找】 要求: 如果找到了,就提
示找到,并给出下标值。
2、代码实现
说明:就是普通的遍历查找,找到返回下标,没有找到返回-1,之后判断即可
package search;
public class OrderSearch {
public static void main(String[] args) {
int[] arr = {1,8,10, 89,1000,1234};
int search = orderSearch(arr, 134);
if(search != -1) {
System.out.println("找到对应下标,下标为:"+search);
}else {
System.out.println("没有找到对应下标");
}
}
/**
*
* @Description 顺序查找
* @auther changlu
* @date Aug 21, 202010:16:13 AM
* @param arr 数组
* @param value 查找值
* @return 返回下标
*/
public static int orderSearch(int[] arr,int value) {
for(int i=0;i<arr.length;i++) {
if(value == arr[i]) {
return i;//找到返回下标
}
}
return -1;//没有找到
}
}
运行结果:
二、二分查找算法
源代码(优化前+优化后):BinarySearch.java
1、二分查找算法的思路
2、题意描述
请对一个有序数组进行二分查找 {1,8,10,89,1000,1234} ,输入一个数看看该数组是否存在此数,并且求出下 标,如果没有就提示”没有这个数”。
3、代码实现(递归解决,只能查找一个指定值的下标)
说明:找到值返回下标,没有找到返回-1
package search;
public class BinarySearch {
public static void main(String[] args) {
int[] arr = {1,8,10, 89,1000,1234};
int binarySearch = binarySearch(arr, 0, arr.length-1, 1234);
if(binarySearch != -1) {
System.out.println("找到该值,下标为:"+binarySearch);
}else {
System.out.println("没有找到该值!");
}
}
public static int binarySearch(int[] arr,int left,int right,int findValue) {
if(left>right) {
return -1;
}
int mid = (left+right)/2;
if(findValue == arr[mid]) {
return mid;
}else if(findValue < arr[mid]) {
return binarySearch(arr, left, mid-1, findValue);
}else {
return binarySearch(arr, mid+1, right, findValue);
}
}
}
运行结果:
4、代码优化(递归,能够查找多个指定值的下标)
情况说明:
对于上一个代码实现还有着缺陷的地方,只能查找最左边第一个的值,如果有连续多个相同值的话就无法找到,所以这里进行优化:
在找到第一个值的情况下,通过左右依次向前向后循环判断添加到list集合中,再进行返回。
思路分析:
代码实现:
说明:可以看到在第三个else也就是访问到第一个指定值时进行前后循环判断遍历即可
package search;
import java.util.ArrayList;
import java.util.List;
public class BinarySearch {
//能够将多个相同的值的下标存放到list集合中返回
public static List<Integer> binarySearch2(int[] arr,int left,int right,int findValue) {
if(left>right) {
return new ArrayList<>();//如果没有找到对应值,返回空的list集合
}
int mid = (left+right)/2;
if(findValue > arr[mid]) {
return binarySearch2(arr, mid+1, right, findValue);
}else if(findValue < arr[mid]) {
return binarySearch2(arr, left, mid-1, findValue);
}else {
//创建一个list集合用来存放对应值下标
List<Integer> list = new ArrayList<>();
//向左进行查找
int temp = mid-1;
while(true) {
//如果temp值小于0或不等于查找的值直接break退出
if(temp<0||arr[temp] != findValue) {
break;
}
list.add(temp--);//符合要求添加下标
}
list.add(mid);//添加mid之前符合的值的下标再添加mid的下标
//向右进行查找
temp = mid+1;
while(true) {
//如果temp值小于0或不等于查找的值直接break退出
if(temp>=arr.length||arr[temp] != findValue) {
break;
}
list.add(temp++);//符合要求添加下标
}
//返回集合
return list;
}
}
}
测试代码:
package search;
import java.util.ArrayList;
import java.util.List;
public class BinarySearch {
public static void main(String[] args) {
int[] arr = {1,8,10, 1000,1000,1000,1234};
List<Integer> list = binarySearch2(arr, 0, arr.length-1, 1111);
System.out.println("list中的下标为:"+list);
}
}
运行结果:
三、插值查找算法(优化二分法)
1、原理介绍
主要核心:int mid = left+(findValue-arr[left])*(right-left)/(arr[right]-arr[left]);
**
2、 举例说明插值查找算法 1-100 的数组
3、代码实现
说明:主要是对于mid查找作了优化,是根据查找值通过斜率的方式来查找,两个注意点说明。
① 对于判断left>right这里,增加两个条件必须有就是判断查找值是否越界,如果不做处理会出现越界情况
② 对于mid求值更加复杂一些,可以看上面原理介绍进行记忆
//使用差值查找
public static int binarySearch3(int[] arr, int left, int right, int findValue) {
//在差值查找中不能设置超过指定范围的值,可能会出现越界问题
if (left > right || findValue<arr[0] || findValue>arr[arr.length-1]) {//修改点1
return -1;
}
int mid = left+(findValue-arr[left])*(right-left)/(arr[right]-arr[left]);//修改点2
if (findValue == arr[mid]) {
return mid;
} else if (findValue < arr[mid]) {
return binarySearch1(arr, left, mid - 1, findValue);
} else {
return binarySearch1(arr, mid + 1, right, findValue);
}
}
测试代码:
package search;
import java.util.ArrayList;
import java.util.List;
public class BinarySearch {
public static void main(String[] args) {
int[] arr = {1,8,10, 89,1000,1234};
int binarySearch = binarySearch3(arr, 0, arr.length-1, 1);
if(binarySearch != -1) {
System.out.println("找到该值,下标为:"+binarySearch);
}else {
System.out.println("没有找到该值!");
}
}
}
运行结果:
四、斐波那契(黄金分割法)查找算法(不太明白)
1、斐波那契(黄金分割法)查找基本介绍
2、斐波那契(黄金分割法)原理
3、斐波那契查找应用案例
题目说明:请对一个有序数组进行斐波那契查找 {1,8,10,89,1000,1234} ,输入一个数看看该数组是否存在此数,并且求 出下标,如果没有就提示”没有这个数”。
说明:这里包含两个方法,一个方法是获取到前20位斐波那契数,第二个方法是通过斐波那契数组来寻找黄金分割点进行值的查找。
package search;
import java.util.Arrays;
public class FibonacciSearch {
private static int maxSize = 20;
//创建一个斐波那契数组
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;
int[] f = fib();// 获取到斐波那契数组
// 获取到斐波那契
while (high > f[k] - 1) {
k++;
}
// 重新生成一个新的指定为f数组中的长度大小数组,多余的使用a数组的最后一位填充
int[] temp = Arrays.copyOf(a, f[k]);
// 举例:
// temp={1,8,10,89,1000,1234,0,0} =>{1,8,10,89,1000,1234,1234,1234,}
for (int i = high + 1; i < temp.length; i++) {
temp[i] = temp[high];
}
while (low <= high) {
System.out.println("查找");
mid = low + f[k - 1] - 1;
if (key < temp[mid]) {// 如果实际值再左边
high = mid-1;
k--;
}else if(key>temp[mid]) {//这是往后面查找
low = mid+1;
k-=2;
}else {//找到的情况
//需要确定,返回的是哪个下标
if(mid<=high) {
return mid;
}else {
return high;
}
}
}
return -1;//没有找到
}
}
测试代码:
package search;
import java.util.Arrays;
public class FibonacciSearch {
public static void main(String[] args) {
int[] arr = {1,8,10,89,1000,1234};
int fibSearch = fibSearch(arr, 1234);
System.out.println(fibSearch);
}
}
运行结果:5
整理者:长路 时间:2020/8/21-2020/8/24