在 java 中,我们常用的查找有四种:
/**
* 线性查找
* 最简单的查找
* 其实就是遍历整个数组,一个个的去进行值的比对,找到就返回结果
*/
public class SeqSearch {
/**
* 从数组中查找key的索引
*
* @param arr
* @param key
* @return
*/
public int search(int[] arr, int key) {
if (null == arr || arr.length == 0) {
return -1;
}
for (int i = 0; i < arr.length; i++) {
if (key == arr[i]) {
return i;
}
}
return -1;
}
}
/**
* 二分法查找
* <p>
* 其实就是对半查找,每次缩小一半的范围,直到找完整个数组
* 需要数组是有序的
*/
public class BinarySearch {
/**
* 普通方式搜索
* 从数组中查找key的索引
*
* @param arr
* @param key
* @return
*/
public int simpleSearch(int[] arr, int key) {
if (null == arr || arr.length == 0) {
return -1;
}
//定义中间点
int left = 0;
int right = arr.length - 1;
while (left < right) {
int mid = (left + right) / 2;
if (key == arr[mid]) {
return mid;
}
if (key > arr[mid]) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return -1;
}
/**
* 递归方法搜索
* 从数组中查找key的索引
*
* @param arr
* @param key
* @return
*/
public int recursionSearch(int[] arr, int key) {
if (null == arr || arr.length == 0) {
return -1;
}
return search(arr, key, 0, arr.length - 1);
}
/**
* 递归方法搜索
* 从数组中查找key的索引
*
* @param arr
* @param key
* @return
*/
public int search(int[] arr, int key, int left, int right) {
if (left > right) {
return -1;
}
int mid = (left + right) / 2;
if (key == arr[mid]) {
return mid;
}
if (key > arr[mid]) {
left = mid + 1;
} else {
right = mid - 1;
}
return search(arr, key, left, right);
}
}
/**
* 插值查找
* 跟二分法比较类似,区别就是二分法对半来
* 这个就是根据值来动态计算
* 数组比较均匀的时候效果好
*/
public class InsertValueSearch {
/**
* 普通方式搜索
* 从数组中查找key的索引
*
* @param arr
* @param key
* @return
*/
public int simpleSearch(int[] arr, int key) {
if (null == arr || arr.length == 0) {
return -1;
}
//定义中间点
int left = 0;
int right = arr.length - 1;
while (left < right) {
int mid = left + (key - arr[left]) * (right - left) / (arr[right] - arr[left]);
if (key == arr[mid]) {
return mid;
}
if (key > arr[mid]) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return -1;
}
/**
* 递归方法搜索
* 从数组中查找key的索引
*
* @param arr
* @param key
* @return
*/
public int recursionSearch(int[] arr, int key) {
if (null == arr || arr.length == 0) {
return -1;
}
return search(arr, key, 0, arr.length - 1);
}
/**
* 递归方法搜索
* 从数组中查找key的索引
*
* @param arr
* @param key
* @return
*/
public int search(int[] arr, int key, int left, int right) {
if (left > right) {
return -1;
}
int mid = left + (key - arr[left]) * (right - left) / (arr[right] - arr[left]);
if (key == arr[mid]) {
return mid;
}
if (key > arr[mid]) {
left = mid + 1;
} else {
right = mid - 1;
}
return search(arr, key, left, right);
}
}
参考文章
/**
* 其实也是二分查找的一个升级版,
* 根据黄金分割比的特性来查找
**/
public class FibonacciSearch {
/**
* 查找
*
* @param arr
* @param key
* @return
*/
public int search(int[] arr, int key) {
//获取获取斐波那契数列
int[] fiboArray = fiboArray();
System.out.println("fiboArray=" + Arrays.toString(fiboArray));
int left = 0;
int right = arr.length - 1;
int mid = 0;
//找到斐波那契数列数列分割的下标
//F(n)=F(n-1)+F(n-2) 所以是找比right 略大的F(n) ,那么黄金点的位置就是F(n--1)
//位置对应的查找索引就是F(n-1)-1 ,因为arr的索引从0开始,需要减去一位
int k = 0;
while (right > fiboArray[k] - 1) {
k++;
}
//因为fiboArray[k] - 1 很可能大于right,那么需要对数组进行补全
//数组拷贝
int[] temp = Arrays.copyOf(arr, fiboArray[k]);
//比原数组长的部分,用原数组的最大值补全
for (int i = right + 1; i < temp.length; i++) {
temp[i] = temp[right];
}
System.out.println("temp=" + Arrays.toString(temp));
//开始搜索
while (left <= right) {
mid = left + fiboArray[k - 1] - 1;
//找到了
if (key == arr[mid]) {
if (mid > right) {
return right;
}
return mid;
}
//在左边,那么取下个个黄金分割点
else if (key < arr[mid]) {
//开始位置左移
right=mid-1;
k--;
} else {
//开始位置右移动
left=mid+1;
k -= 2;
}
}
return -1;
}
/**
* 获取斐波那契数列
*
* @return
*/
private int[] fiboArray() {
int arr[] = new int[20];
arr[0] = 1;
arr[1] = 1;
for (int i = 2; i < arr.length; i++) {
arr[i] = arr[i - 1] + arr[i - 2];
}
return arr;
}
}