1. 顺序查找(无序查找)
算法:
1. 序列无序(有序),适合遍历的数据结构
2. 遍历比对
public static int sequenceSearch(int[] arr, int a) {
for (int i = 0; i < arr.length; i++) {
if (a == arr[i]) return i + 1;
}
return -1;
}
2. 折半查找(有序查找)
算法:
1. 首先数列有序,该算法针对的是有序数列
2. 折半查找,给定值a与中间参考值(mid = low + 1/2 * (high - low),即(low + high) / 2)相比,若小于中间参考值,则给定值存在左侧,否则给定值存在右侧,通过迭代或者递归方式查询元素所在索引
//二分查找,迭代版本
public static Integer biSearch(int array[], int a) {
int low = 0;
int high = array.length - 1;
int mid;
while (low <= high) {
mid = (low + high) / 2;
if (array[mid] == a) {
return mid + 1;
} else if (a > array[mid]) {
low = mid + 1; //向右查找
} else {
high = mid - 1;//向左查找
}
}
return -1;
}
//二分查找,递归版本
public static int biSearch2(int array[], int a, int low, int high) {
if (low <= high) {
int mid = (low + high) / 2;
if (array[mid] == a)
return mid;
if (a < array[mid])
return biSearch2(array, a, low, mid - 1);
if (a > array[mid])
return biSearch2(array, a, mid + 1, high);
}
return -1;
}
3. 插值查找(有序查找)
算法:
1. 插值查找是折半查找的优化版本,自适应:mid = low + (key - arr[low]) / (arr[high] - arr[low]) * (high - low)
public static int insertionSearch(int[] arr, int key, int low, int high) {
if (low <= high) {
if (arr[low] == key) return low + 1;
if (arr[high] == key) return high + 1;
int mid = low + (key - arr[low]) / (arr[high] - arr[low]) * (high - low);
if (arr[mid] == key)
return mid + 1;
if (arr[mid] > key)
return insertionSearch(arr, key, low, mid - 1);
if (arr[mid] < key)
return insertionSearch(arr, key, mid + 1, high);
}
return -1;
}
说明:插值查找又叫自适应查找,和折半查找相比,在数列元素均匀分布时,效率更高
4. 斐波那契查找(有序查找)
算法:
1. 构造斐波那契数列,选出一个合适的容量(选择一个比要排序的数列元素数量大且最近的一个)
2. 构建一个临时数列,将待排序数列放入,若不足用最高位填充
3. 构建参考元素mid=low + f[k - 1] - 1(见图知意,其实就是右侧那部分)
4. 若查找元素比参考元素小,说明查找元素落在左侧子序列,反之则落在右侧子序列
5. 重复步骤3、4,指导找到该查找元素(找不到返回-1)
public static int fibonacciSearch(int[] arr, int key) {
//获取一个合适的斐波那契F[k]值
int f[] = fibonacci();
int k = 0;
while (arr.length - 1 > f[k] - 1) {
k++;
}
// 构建一个临时数组,若原始数列填充不满,则用原始数列最后一位进行填充
int[] temp = Arrays.copyOf(arr, f[k]);
for (int i = arr.length; i < temp.length; i++) {
temp[i] = arr[arr.length - 1];
}
int low = 0;
int high = arr.length - 1;
int mid;
while (low <= high) {
mid = low + f[k - 1] - 1;
if (key < temp[mid]) { //目标数据在左侧子序列
high = mid - 1;
k = k - 1;
} else if (key > temp[mid]) { //目标数据在右侧子序列
low = mid + 1;
k = k - 2;
} else {// 找到目标
if (mid <= arr.length - 1) {
return mid;
} else {
return arr.length - 1;//目标找到,但是是用最高位填充的数据,所以返回arr.length - 1
}
}
}
return -1;
}
public static final int MAXSIEZE = 20;
// 构建一个斐波那契数列(K=20时,F[k]=6765,表示可以容纳6765个元素)
public static int[] fibonacci() {
int[] f = new int[MAXSIEZE];
f[0] = 1;
f[1] = 1;
for (int i = 2; i < MAXSIEZE; i++) {
f[i] = f[i - 1] + f[i - 2];
}
return f;
}
说明:
1. 构建一个斐波那契,一般选择K就够测试的了,生产上则要根据数据量进行选择
2. 当斐波那契F[k]时,mid=low + f[k - 1] - 1,是因为一个数列其实是分成了两部分(如上图)
【说明】梳理知识用,有些地方未做验证,请保持怀疑态度。