四种查找算法
顺序/线性查找
概念和思路加代码:
折半查找/二分查找
概念:
例子:
思路:
代码实现:
public class DoubleBreakSearch {
public static void main(String[] args) {
int[] arr={1,3,5,7,8,10,15,46,15};
doubleBreakSearch(arr,3,0,arr.length-1);
}
public static void doubleBreakSearch(int[] arr,int temp,int start,int end){
if(start<=end){
int mid = (start+end)/2;
int arr[mid];
if (temp<arr[mid]){
doubleBreakSearch(arr,temp,start,mid);
}else if (temp>arr[mid]){
doubleBreakSearch(arr,temp,mid+1,end);
}else {
System.out.println(temp);
return ;
}
}
}
}
差值查找
概念:
差值查找算法说白了就是换了一下公式哈,公式变为
temp=start + (end-start)*(temp - arr[start]/arr[end] - arr[start]) 即可!
public class DoubleBreakSearch {
public static void main(String[] args) {
int[] arr={1,3,3,7,8,10,46,15};
int data = doubleBreakSearch(arr, 3, 0, arr.length - 1);
System.out.println(data);
}
private static int doubleBreakSearch(int[] arr, int temp, int start, int end) {
if (start > end || temp < arr[0] || temp > arr[arr.length - 1]) {
return -1;
}
int mid = start + (end - start) * ((temp - arr[start]) / (arr[end] - arr[start]));
int midValue = arr[mid];
if (temp < midValue) {
return doubleBreakSearch(arr, temp, start, mid);
} else if (temp > midValue) {
return doubleBreakSearch(arr, temp, mid + 1, end);
} else {
return mid;
}
}
}
斐波拉契查找/黄金分割法查找
概念:
原理:
1、算法介绍
斐波那契搜索(Fibonacci search) ,又称斐波那契查找,是区间中单峰函数的搜索技术。
斐波那契搜索就是在二分查找的基础上根据斐波那契数列进行分割的。在斐波那契数列找一个等于略大于查找表中元素个数的数F[n],将原查找表扩展为长度为Fn,完成后进行斐波那契分割,即F[n]个元素分割为前半部分F[n-1]个元素,后半部分F[n-2]个元素,找出要查找的元素在那一部分并递归,直到找到。
2、算法思路说明
F(k)=F(k-1)+F(k-2) ==> F(k)-1=(F(k-1)-1)+(F(k-2)-1)+1
mid=low+F(k-1)-1
斐波那契查找与折半查找很相似,他是根据斐波那契序列的特点对有序表进行分割的。他要求开始表中记录的个数为某个斐波那契数小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,high]范围内,k-=2 说明范围[mid+1,high]内的元素个数为n-(F(k-1))=Fk-1-F(k-1)=Fk-F(k-1)-1=F(k-2)-1个,所以可以递归的应用斐波那契查找。
(3)<,则high=mid-1,k-=1。
说明:low=mid+1说明待查找的元素在[low,mid-1]范围内,k-=1 说明范围[low,mid-1]内的元素个数为F(k-1)-1个,所以可以递归的应用斐波那契查找。
import java.util.Arrays;
public class FibonacciSearch {
public static int maxSize = 20;
public static void main(String[] args) {
int[] arr = { 9, 25, 34, 89, 1000, 1645};
int key = 34;
System.out.println(fibSearch(arr, key));
}
//用非递归的方法获取一个斐波那契数列
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 若找到则返回对应下标,没找到,则返回-1
*/
public static int fibSearch(int[] a, int key) {
int low = 0;
int high = a.length - 1;
int k = 0;//表示斐波纳挈分割数值的下标
int mid = 0;//存放mid的值
int[] f = fib();//获取斐波那契数列
//获取到斐波那契而数列的下标
while(high > f[k] - 1) {
k ++;
}
//f[k]的值可能会大于数组a的长度,所以需要新定义一个数组,指向temp
//不足的部分系统自动用0填充
//temp={ 9, 25, 34, 89, 1000, 1645, 0, 0}
//实际上我们需要用原数组的最后一个数填充0的地方
//temp={ 9, 25, 34, 89, 1000, 1645, 0, 0} ==> temp={ 9, 25, 34, 89, 1000, 1645, 1645, 1645}
int[] temp = Arrays.copyOf(a,f[k]);
for (int i = high + 1; i < temp.length; i++) {
temp[i] = a[high];
}
//找我们的关键数
while(low <= high) {
mid = low + f[k - 1] - 1;
//全部的元素=前面的元素+后面的元素
//f[k]=f[k-1]+f[k-2]
//前面有f[k-1]个元素,继续拆分为f[k-1]=f[k-2]+f[k-3],即在f[k-1]的前面继续查找,k--
//后面有f[k-2]个元素,继续拆分为f[k-1]=f[k-3]+f[k-4],即在f[k-2]的前面继续查找,k=k-2
if(key < temp[mid]) {
high = mid - 1;
k--;
//即下次循环时mid=f[k-1-1]-1
} else if(key > temp[mid]) {
low = mid + 1;
k -= 2;
//即下次循环时mid=f[k-1-2]-1
} else {
//找到了,但是要确定是哪个下标
if(mid <= high) {
return mid;
} else {
return high;
}
}
}
return -1;
}
}
算法的复杂度分析
在最坏情况下,斐波那契查找的时间复杂度还是O(log2n),且其期望复杂度也为O(log2n),但是与折半查找相比,斐波那契查找的优点是它只涉及加法和减法运算,而不用除法,而除法比加减法要占用更多的时间,因此,斐波那契查找的运行时间理论上比折半查找小,但是还是得视具体情况而定。