文章目录
一、查找算法是什么?
查找算法简介
- 查找是在大量的信息中寻找一个特定的信息元素,在计算机应用中,查找是常用的基本运算
- 比较常见的有顺序查找(线性查找)
- 二分查找/折半查找
- 插入查找
- 斐波那契(黄金比例)查找
二、查找算法介绍及实现
1.顺序查找
算法描述
- 对数据进行逐一对比
- 检索到指定数据,则停止检索,返回其下标
代码实现:
package com.lingo.search;
/**
* 线性查找/顺序查找 最基本最基础的循环查找 也是效率最低的查找方式
*/
public class SequentialSearch {
public static void main(String[] args) {
int[] arr = {1, 5, 8, 66, 55, 1, 2, 33, 555, 156, 498, 512, 223, 156};
int result = sequentialSearch(arr, 555);
System.out.println(result);
}
public static int sequentialSearch(int[] arr, int value) {
for (int i = 0; i < arr.length; i++) {
if (value == arr[i]) {
return i;
}
}
return -1;
}
}
输出结果:
8
2.二分查找/折半查找
算法描述
- 进行二分查找或折半查找的前提是当前数组一定是有序的
- 取出数组的中间值:mid = left + (right - left)/2
- 这里为什么不直接用left+right呢?(可能会存在数据大小越界问题)
- 若待查找数据小于中间值 则向左递归查询
- 若待查找数据大于中间值 则向右递归查询
- 最终返回待查找数据的下标,若无数据则返回-1
代码实现:
package com.lingo.search;
public class BinarySearchT {
private static int search(int[] arr, int left, int right, int value) {
//递归中止条件
if (left > right) {
return -1;
}
int mid = left + (right - left) / 2;
if (value < arr[mid]) {
return search(arr, left, mid, value);
} else if (value > arr[mid]) {
return search(arr, mid + 1, right, value);
} else {
return mid;
}
}
public static int search(int[] arr, int value) {
return search(arr, 0, arr.length - 1, value);
}
public static void main(String[] args) {
int[] arr = {1, 5, 8, 15, 55, 212, 333, 411, 555};
int result = search(arr, 333);
System.out.println(result);
}
}
输出结果:
6
3.插值查找
算法描述
- 插值查找相当于是二分查找的一个plus版本
- 插值查找的mid是一个自适应的mid
- mid = low + (high - low)*(value-arr[low])/(arr[high] - arr[low])
- 其他算法流程同二分查找
代码实现:
package com.lingo.search;
public class InsertionSearchT {
private static int search(int[] arr, int left, int right, int value) {
//递归中止条件
if (left > right) {
return -1;
}
//这里如果不加判断会导致空指针异常
if (value > arr[arr.length - 1] || value < arr[0]) {
return -1;
}
int mid = left + (right - left) * (value - arr[left]) / (arr[right] - arr[left]);
if (value < arr[mid]) {
return search(arr, left, mid, value);
} else if (value > arr[mid]) {
return search(arr, mid + 1, right, value);
} else {
return mid;
}
}
public static int search(int[] arr, int value) {
return search(arr, 0, arr.length - 1, value);
}
public static void main(String[] args) {
int[] arr = {1, 5, 8, 15, 55, 212, 333, 411, 555};
int result = search(arr, 212);
System.out.println(result);
}
}
输出结果:
5
4.斐波那契查找
算法描述
- 黄金比例
- 斐波那契数列{1,1,2,3,5,8,13,21,34,55,…}
- 斐波那契数列的特点是从第三位开始 数值等于 前两位数值的加和
- 正是采用这种思想将待排序数组的数量对应于大于或等于该数组数量且最接近的数值,然后copyOf到新数组
- 将新数组中大于原数组长度的数值更新为原数组的最大值
- mid = low + F[k-1] - 1
- 因为F[k]为数组长度 F[k-1]为左侧元素数组 F[k-2]为右侧元素数组
- 这里的-1 是因为数组的下标从0开始
- 这里采用了迭代的查找
代码实现:
package com.lingo.search;
import java.util.Arrays;
public class FibonaciiSearchT {
private static int maxSize = 20;
public static int search(int[] arr, int value) {
if (arr[0] > value || arr[arr.length - 1] < value) {
return -1;
}
int[] f = getFibonaciiArr();
int low = 0;
int k = 0;//斐波那契数列下标
int high = arr.length - 1;
while (high > f[k]) {
k++;
}
int[] copyArr = Arrays.copyOf(arr, f[k]);
for (int i = high + 1; i < copyArr.length; i++) {
copyArr[i] = arr[high];
}
while (low <= high) {
int mid = low + f[k - 1] - 1;//下标0开始
if (value > copyArr[mid]) {
//f[k] = f[k-1]+f[k-2]
low = mid + 1;
k -= 2;
} else if (value < copyArr[mid]) {
high = mid - 1;
k -= 1;
} else {
if (mid <= high) {
return mid;
} else {
return high;
}
}
}
return -1;
}
private static int[] getFibonaciiArr() {
int[] f = new int[maxSize];
f[0] = 1;
f[1] = 1;
for (int i = 2; i < maxSize - 1; i++) {
f[i] = f[i - 1] + f[i - 2];
}
return f;
}
public static void main(String[] args) {
int[] arr = {1, 5, 8, 15, 55, 212, 333, 411, 555};
int result = search(arr, 212);
System.out.println(result);
}
}
输出结果:
5