常用四种
** 线性(顺序)查找:就是将需要查找的数列进行遍历挨个比对即可 (无序有序均可)
** 二分查找/折半查找 (需要在有序的前提下)
** 插值查找 (需要有序)
** 斐波那契查找 (需要有序)
二分查找
思路:将数列的中间值与需要查找的值进行比较,如果大于,则向左递归,如果小于,则向右递归,分别再进行与中间
值的对比,循环往复,直到找到这个数,将其位置返回或者循环结束返回没有找到
代码实现
public class BinarySelect {
public static void main(String[] args) {
int[] arr = {1, 2, 3, 3, 3, 8, 9, 10, 545};
System.out.println(select(arr, 0, arr.length - 1, 3));
}
public static List<Integer> select(int[] arr, int left, int right, int value) {
int midden = (left + right) / 2;
int middenValue = arr[midden];
List<Integer> indexList = new ArrayList<>();
if (left > right) {
return indexList;
}
if (middenValue > value) {
return select(arr, left, midden - 1, value);
} else if (middenValue < value) {
return select(arr, midden + 1, right, value);
} else {
int temp = midden - 1;
while (true) {
if (temp < 0 || arr[temp] != value) {
break;
} else {
indexList.add(0, temp);
temp--;
}
}
indexList.add(midden);
temp = midden + 1;
while (true) {
if (temp > arr.length - 1 || arr[temp] != value) {
break;
} else {
indexList.add(temp);
temp++;
}
}
return indexList;
}
}
}
插值查找
一个线性增长数列,如果需要查找的值位于左边的话,二分查找会查找很多次,而插值查找可以通过自适应获取中值
来减少查找次数,其它与二分查找一致
中值获取公式:midden = left + (right - left) * (value - arr[left]) / (arr[right] - arr[left])
代码示例(以查找到一个就返回索引为例,返回多个与二分查找一致)
public class InsertSelect {
public static void main(String[] args) {
int[] arr = new int[100];
for (int i = 0; i < 100; i++) {
arr[i] = i + 2;
}
System.out.println(select(arr, 0, arr.length - 1, 2));
}
public static int select(int[] arr, int left, int right, int value) {
if (left > right || value > arr[right] || value < arr[left]) {
return -1;
}
int midden = left + (right - left) * (value - arr[left]) / (arr[right] - arr[left]);
int middenValue = arr[midden];
if (value > middenValue) {
return select(arr, midden + 1, right, value);
} else if (value < middenValue) {
return select(arr, left, midden - 1, value);
} else {
return midden;
}
}
}
斐波那契查找
算法思想:相对于二分查找,仅改变了获取中值的方法,借助斐波那契数列的特殊性质(每一项都等于前两项的和)
将原数列分为左右两项,进行比对,根据比对结果再向左右一边继续比对,直到找到或者没找到,算法结束
中值获取:midden=left+f(k-1)-1
代码实现(找到一个即返回,查找全部相同值与二分法类似)
public class FibonacciSelect {
public static void main(String[] args) {
int[] arr = {1, 2, 6, 8, 10, 16, 18, 26};
System.out.println(select(arr, 18));
}
public static int[] fibonacci() {
int[] fibonacciArray = new int[20];
fibonacciArray[0] = 1;
fibonacciArray[1] = 1;
for (int i = 2; i < fibonacciArray.length; i++) {
fibonacciArray[i] = fibonacciArray[i - 1] + fibonacciArray[i - 2];
}
return fibonacciArray;
}
public static int select(int[] arr, int value) {
int left = 0;
int right = arr.length - 1;
int k = 0;
int[] f = fibonacci();
int midden;
while (f[k] < arr.length) {
k++;
}
int[] temp = Arrays.copyOf(arr, f[k]);
for (int i = arr.length + 1; i < temp.length - arr.length; i++) {
temp[i] = arr[right];
}
while (left <= right) {
midden = left + f[k - 1] - 1;
if (value < temp[midden]) {
right = midden - 1;
k--;
} else if (value > temp[midden]) {
left = midden + 1;
k -= 2;
} else {
return Math.min(midden, right);
}
}
return -1;
}
}