在java中,我们常用的查找有四种
- 顺序(线性查找)
- 二分查找/折半查找
- 插值查找
- 斐波那契查找
1)顺序线性查找
有一个数列{1,8,10,89,1000,1234},判断数列中是否包含此名称,要求:如果找到了,就提示找到,并给出下标值
//线性查找
public class SeqSearch {
public static void main(String[] args) {
int[] array = {1,34,23,-5,6};
int index = seqSearch(array, 6);
if(index == -1){
System.out.println("没有找到");
}else {
System.out.println("找到了下标为"+index+"的值");
}
}
//这里实现线性查找是找到一个满足条件的值,就返回
public static int seqSearch(int[] array,int value){
//线性查找是逐一比对,发现有相同值,就返回下标
for(int i = 0; i < array.length; i++){
if(array[i] == value){
return i;
}
}
return -1;
}
}
结果:
2)二分查找
请对一个有序数组进行二分查找, {1,8,10,89,1000,1234},输入一个数看看该数组是否有此数,并求出下标,如果没有就提示”没有此数“,
二分查找的思路:
1.首先确定该数组的中间的下标,
mid = (left+right) / 2
2.然后让需要查找的数findVal和array[i] 比较
2.1findVal > array[i],说明你要查找的数在mid的右边,因此需要递归的向右查找
2.2findVal < array[i],说明你要查找的数在mid的左边,因此需要递归的向左查找
2.findVal == array[i],说明找到,就返回
//什么时候我们需要结束递归
1.我们找到就结束递归
2.递归完整个数组,仍然没有找到,也需要结束递归,当left > right就需要退出
代码实现
//二分查找
public class BinarySearch {
public static void main(String[] args) {
int[] array = {1,8,10,89,1000,1024};
int index = binarySearch(array, 809, 0, array.length);
if(index == -1){
System.out.println("没有找到!");
}else {
System.out.println("index="+index);
}
}
//二分查找
public static int binarySearch(int[] array,int findValue,int left,int right){
//当 left > right时,说明递归了整个数组,没有找到
if(left > right){
return -1;
}
int mid = (left + right) / 2;
int midValue = array[mid];
if(findValue > midValue){ //向右递归
return binarySearch(array,findValue,mid+1,right);
}else if(findValue < midValue){
return binarySearch(array,findValue,left,mid-1);
}else {
return mid;
}
}
}
结果:
要查找的数为809时
要查找的数为89时
当一个有序数组中有多个相同的数值时,如何将所有数值都查到{1,8,10,89,1000,1000,1234}
public static void main(String[] args) {
int[] array = {1,8,10,89,1000,1000,1000,1024};
List<Integer> list = binarySearch2(array, 1000, 0, array.length-1);
System.out.println("indexList"+list);
}
//完成当一个有序数组中有多个相同的数值时,如何将所有数值都查到{1,8,10,89,1000,1000,1234}
/*
* 思路:
* 1.在找到mid索引值,不要马上返回
* 2.向mid索引值左边扫描,将所有满足findValue的下标值加入到ArrayList中
* 3.向mid索引值右边扫描,将所有满足findValue的下标值加入到ArrayList中
* 4.将ArrayList返回
* */
public static List<Integer> binarySearch2(int[] array, int findValue, int left, int right){
//当 left > right时,说明递归了整个数组,没有找到
if(left > right){
return new ArrayList<Integer>();
}
int mid = (left + right) / 2;
int midValue = array[mid];
if(findValue > midValue){ //向右递归
return binarySearch2(array,findValue,mid+1,right);
}else if(findValue < midValue){
return binarySearch2(array,findValue,left,mid-1);
}else {
List<Integer> arrayList = new ArrayList<Integer>();
//向mid索引值左边扫描,将所有满足findValue的下标值加入到ArrayList中
int temp = mid-1;
while(true){
if(temp < 0 || array[temp] != findValue){ //退出,如果找到最左边或者有一个不等于findValue
break;
}
arrayList.add(temp);
temp -= 1;
}
arrayList.add(mid);
//向mid索引值右边扫描,将所有满足findValue的下标值加入到ArrayList中
temp = mid+1;
while (true){
if(temp > array.length-1 || array[temp] != findValue){
break;
}
arrayList.add(temp);
temp += 1;
}
return arrayList;
}
}
结果:
3). 插值查找
代码实现:
//插值查找
public class InsertValueSearch {
public static void main(String[] args) {
int[] array = new int[100];
for(int i = 0; i < 100; i++){
array[i] = i+1;
}
// System.out.println(Arrays.toString(array));
int index = insertValSearch(array, 0, array.length - 1, 100);
System.out.println("index="+index);
}
//插值查找算法也要求数组是有序的
public static int insertValSearch(int[] array,int left,int right,int findValue){
//注意:findValue < array[0] || findValue > array[array.length-1]必须需要
//否则我们得到的mid可能越界
if(left > right || findValue < array[0] || findValue > array[array.length-1]){
return -1;
}
//求出mid
int mid = left + (right - left) * (findValue - array[left]) / (array[right] - array[left]);
int midValue = array[mid];
if(findValue > midValue){ //向右查找
return insertValSearch(array,mid+1,right,findValue);
}else if(findValue < midValue){ //向左查找
return insertValSearch(array,left,mid-1,findValue);
}else {
return mid;
}
}
}
结果:
4)斐波那契查找
斐波那契查找应用案例:
请对一一个有序数组进行斐波那契查找{1,8, 10, 89, 1000, 1234} ,输入一个数看看该数组是否存在此数,并且求出下标,如果没有就提示"没有这个数"。
代码实现:
import java.util.Arrays;
//斐波那契查找
public class FibonacciSearch {
public static int maxSize = 20;
public static void main(String[] args) {
int[] array = {1,8,10,89,1000,1024};
System.out.println(fibSearch(array, 10));
}
//因为后面我们mid = low + F[k-1]-1,需要使用到斐波那契数列,因此我们需要先获取到一个斐波那契数列
//非递归得到一个斐波那契数列
public static int[] getFib(){
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;
}
//编写斐波那契查找算法
//使用非递归的方式编写算法
public static int fibSearch(int[] array,int findValue){
int left =0;
int right = array.length-1;
int k = 0; //表示斐波那契分割数值的下标
int mid = 0; //存放mid值
int[] f = getFib(); //获取到斐波那契数列
//获取到斐波那契分割数值的下标
while (right > f[k] -1){
k++;
}
//因为f[k]可能大于数组array[]的长度,因此我们需要使用Arrays类,构造一个新的数组,并且指向temp[]
//不足的部分会使用0填充
int[] temp = Arrays.copyOf(array,f[k]);
//实际上需要使用array[]最后的数填充temp
//举例:temp={1,8,10,89,1000,1024,0,0,0} => {1,8,10,89,1000,1024,1024,1024,1024}
for(int i = right+1; i < temp.length; i++){
temp[i] = array[right];
}
//使用while来循环处理,找到我们的数findValue
while(left <= right){ //只要这个条件满足,就可以找
mid = left + f[k-1]-1;
if(findValue < temp[mid]){ //我们应该继续向数组的前面(左边)查找
right = mid -1;
//为什么是k--?
//1.全部元素 = 前面的元素+后面的元素
//2.f[k] = f[k-1] + f[k-2]
//因为前面有f[k-1]个元素,所以我们可以继续拆分f[k-1] = f[k-2] + f[k-3]
//即在 f[k-1] 的前面继续查找 k--
//即下次循环的mid = f[k-1-1]-1
k--;
}else if(findValue > temp[mid]){ //我们应该继续向数组的后面(右边)查找
left = mid +1;
//为什么是k -= 2;
//1.全部元素 = 前面的元素+后面的元素
//2.f[k] = f[k-1] + f[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 <= left){
return mid;
}else {
return right;
}
}
}
return -1;
}
}
结果展示: