#四大查找方法
java 中常用的查找的四种
- 1.顺序查找
- 2.二分查找
- 3.插值查找
- 4.斐波那契查找
1 顺序查找
/**
* 顺序查找
*
* @param arr
* @param value
* @return
*/
public static int seqSearch(int[] arr, int value) {
//找到返回下标,没找到返回 -1
for (int i = 0; i < arr.length; i++) {
if (arr[i] == value) {
return i;
}
}
return -1;
}
2 二分查找
1.二分查找 返回一个值
/**
* 二分查找
* 1.首先确定该数组的中间的下标
* mid = (left + right)/2
* 2.然后让查找的数据 findVal与arr[mid] 进行比较
* 2.1 findVal> arr[mid] 说明查找的数在右边,故在右边递归查找
* 2.2 findVal> arr[mid] 说明查找的数在左边,故在向左边递归查找
* 2.3 findVal == arr[mid] 说明找到了,直接返回
* <p>
* //递归说明时候结束
* 结束条件为
* 1) 找到了
* 2) 整个完整数组,都没有找到,结束条件为 left>right
*
* @param arr 查找的数组
* @param left 左边索引
* @param right 右边索引
* @param findVal 要查找的数
* @return
*/
public static int binarySearch(int[] arr, int left, int right, int findVal) {
//当left>right时,说明整个数组没有找想要的值
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 < arr[mid]) {
return binarySearch(arr, left, mid - 1, findVal);
} else {
return mid;
}
}
2.二分查找所有值
//查找所有相同的值
public static List<Integer> binarySearchAll(int[] arr, int left, int right, int findVal) {
//当left>right时,说明整个数组没有找想要的值
if (left > right) {
return new ArrayList<Integer>();
}
int mid = (left + right) / 2;
int midVal = arr[mid];
if (findVal > midVal) {
return binarySearchAll(arr, mid + 1, right, findVal);
} else if (findVal < arr[mid]) {
return binarySearchAll(arr, left, mid - 1, findVal);
} else {
/**
* 1.在找到mid 索引值,暂时不马上返回.
* 2.先向 mid 的左边 进想递归扫描 将所有等于查找值 findVal 的元素的下标,添加到List中,
* 3.先向 mid 的右边 进想递归扫描 将所有等于查找值 findVal 的元素的下标,添加到List中,
* 4. 最后将list返回
*/
ArrayList<Integer> reslist = new ArrayList<>();
//2先向 mid 的左边 进想递归扫描 将所有等于查找值 findVal 的元素的下标,添加到List中
int temp = mid -1;
while(true){
if(temp < 0 || arr[temp] != findVal){// temp < 0 说明左边数组没有了, arr[temp] != findVal 说明左边没有查找的值了
break;
}
//否则,就将temp存到list
reslist.add(temp);
temp -= 1;//向左递归
}
//3.先向 mid 的右边 进想递归扫描 将所有等于查找值 findVal 的元素的下标,添加到List中,
temp = mid + 1;
while(true){
if(temp > arr.length -1 || arr[temp] != findVal){// temp < arr.length -1 说明右边数组没有了, arr[temp] != findVal 说明右边没有查找的值了
break;
}
//否则,就将temp存到list
reslist.add(temp);
temp += 1;//向右递归
}
//4. 最后将list返回
return reslist;
}
}
3 插值查找算法
/**
* 插值查找算法
* @param arr 要查找的有序数组
* @param left
* @param right
* @param findVal
* @return 找到返回下标,找不到返回 -1
*/
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;
}
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 static void main(String[] args) {
int arr[] = {12,345,243,65,3534,246,354,25,676,87};
//int index = insertValueSearch(arr, 0, arr.length - 1, 3534);
int index = binarySearch11(arr, 0, arr.length - 1, 3534);
System.out.println(index);
}
注意:
1 ) 对于数据量较大,关键字分布比较均匀的查找表来说,采用插值查找, 速度较快.
2 ) 关键字分布不均匀的情况下,该方法不一定比折半查找要好
4 斐波那契查找 待续
import java.util.Arrays;
public class FibonacciSearch {
public static int maxSize = 20;
public static void main(String[] args) {
int[] arr = {1, 5, 18, 100, 189, 1860, 1234};
System.out.println("index=" + fibSearch(arr, 189));
}
//因为后面我们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;
}
//编写斐波那契查找算法
//使用非递归的方式编写算法
/**
* @return 返回对应的下标,如果没有- 1
* @parama 数组
* @paramkey 我们需要查找的关键码(值)
*/
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类,构造一个新的数组,并指向temp[]
//不足的部分会使用 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--
//说明
// 1. 全部元素 =前面的元素 + 后边元素
// 2 .f[k]=f[k- 1 ]+f[k- 2 ]
//因为 前面有 f[k- 1 ]个元素,所以可以继续拆分 f[k- 1 ]=f[k- 2 ]+f[k- 3 ]
//即 在 f[k- 1 ] 的前面继续查找 k--
//即下次循环 mid=f[k- 1 - 1 ]- 1
k--;
} else if (key > temp[mid]) {// 我们应该继续向数组的后面查找(右边)
low = mid + 1;
//为什么是k-= 2
//说明
// 1. 全部元素 =前面的元素 + 后边元素
// 2 .f[k]=f[k- 1 ]+f[k- 2 ]
// 3. 因为后面我们有f[k- 2 ] 所以可以继续拆分 f[k- 1 ]=f[k- 3 ]+f[k- 4 ]
// 4. 即在f[k- 2 ] 的前面进行查找 k-= 2
// 5. 即下次循环 mid=f[k- 1 - 2 ]- 1
k -= 2;
} else {//找到
//需要确定,返回的是哪个下标
if (mid <= high) {
return mid;
} else {
return high;
}
}
}
return -1;
}
}
查找算法解析:顺序、二分、插值与斐波那契
本文介绍了四种查找算法:顺序查找、二分查找的两种应用、插值查找及其适用场景,以及未展开讨论的斐波那契查找。对于数据量大且关键字分布均匀的查找表,插值查找可能优于折半查找。
1066

被折叠的 条评论
为什么被折叠?



