查找算法
常用的查找算法有:顺序查找、二分查找、插值查找、斐波那契查找。当然查找的前提默认数据已经排序完成。
1 二分查找
二分查找的思想就是定义中间的那个值为分割点,如果恰好要找的值是中间点的值,那么就返回,否则比较大小,若是待查找的值比中间值小,则指针往前移动;若是待查找的值比中间的大,则指针往后移动。
二分查找的实现
1 | public class Demo { |
2 插值查找
插值查找相当于二分查找的一种优化,优化的是定义的分割点。插值查找的算法详解如下图所示:
插值查找的代码实现
1 | public class Demo { |
斐波那契查找
斐波那契查找算法与二分查找也类似,只是mid取值更加复杂,其基本思想如下图所示:
斐波那契查找与折半查找很相似,他是根据斐波那契序列的特点对有序表进行分割的。他要求开始表中记录的个数为某个斐波那契数小1,即n=F(k)-1;
开始将k值与第F(k-1)位置的记录进行比较(及mid=low+F(k-1)-1),比较结果也分为三种
1)相等,mid位置的元素即为所求
2)大于,low=mid+1,k-=2;说明:low=mid+1说明待查找的元素在[mid+1,hign]范围内,k-=2 说明范围[mid+1,high]内的元素个数为n-(F(k-1))= Fk-1-F(k-1)=Fk-F(k-1)-1=F(k-2)-1个,所以可以递归的应用斐波那契查找
- 小于,high=mid-1,k-=1;说明:low=mid+1说明待查找的元素在[low,mid-1]范围内,k-=1 说明范围[low,mid-1]内的元素个数为F(k-1)-1个,所以可以递归的应用斐波那契查找
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75public class Demo {
public static int maxSize = 20;
public static void main(String[] args) {
int[] arr = {1,8,10,89,1000,1234};
System.out.println(fibonacciSearch(arr,1234));
}
//首先需要得到一个斐波那契数列
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;
}
//编写斐波那契查找算法
/**
*
* @param a 数组
* @param key 需要查找的数
* @return 返回对应的下标
*/
public static int fibonacciSearch(int[] a , int key){
int low = 0;
int high = a.length - 1;
int k = 0;//k表示斐波那契分割数组的下标
int mid = 0;//存放mid值
int F[] = fib();//得到斐波那契数列
//获取到斐波那契分割数组的下标
while (high > F[k] - 1){
k++;
}
//因为f[K]值可能大于a的长度,因此需要使用Arrays类,构造一个新的数组,并指向a
//不足的用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;
/**
* 全部的元素包含前面的元素和后面的元素
* 斐波那契数组每一项与前面的项都有关系
* 这一项没有找到那么就在前面的项查找
* 下次循环的时候mid = f[k-1-1]-1
*/
k--;
}else if (key > temp[mid]){
//右边查找
low = mid + 1;
/**
* K -= 2的原因:
* 因为后面有f[k - 2]所以可以继续拆分f[k-1]=f[k-3]+f[k-4]
* 即在f[k-2]的前面进行查找k-=2
* 下次循环mid=f[k-1-2]-1
*/
k -= 2;
}else {
if (mid <= high){
return mid;
}else {
return high;
}
}
}
return -1;
}
}