有一个数列: {1,8, 10, 89, 1000, 1234} ,判断数列中是否包含此名称【顺序查找】 要求: 如果找到了,就提示找到,并给出下标值。
package com.szh.search;
public class SeqSearch {
//这里我们实现的线性查找是找到一个满足条件的值,就返回
private static int seqSearch(int[] arr, int value) {
//线性查找是逐一比对,发现有相同值,就返回下标
for (int i = 0; i < arr.length; i++) {
if (arr[i] == value) {
return i;
}
}
return -1;
}
public static void main(String[] args) {
int[] arr = { 1, 9, 11, -1, 34, 89 }; //无序数组
int index = seqSearch(arr, 34);
if (index == -1) {
System.out.println("没有找到这个值");
} else {
System.out.println("找到了这个值,对应下标为:" + index);
}
}
}
2.二分查找
二分查找:请对一个有序数组进行二分查找 {1,8, 10, 89, 1000, 1234} ,输入一个数看看该数组是否存在此数,并且求出下标,如果没有就提示"没有这个数"。
课后思考题: {1,8, 10, 89, 1000, 1000,1234} 当一个有序数组中,有多个相同的数值时,如何将所有的数值都查找到,比如这里的 1000。
package com.szh.search;
import java.util.ArrayList;
import java.util.List;
public class BinarySearch {
private static int binarySearch(int[] arr, int left, int right, int findVal) {
//当 left > right 时,说明递归整个数组,但是没有找到,此时直接返回-1
if (left > right) {
return -1;
}
int mid = (left + right) / 2;
int midVal = arr[mid];
if (findVal > midVal) {
return binarySearch(arr, mid + 1, right , findVal);
} else if (findVal < midVal) {
return binarySearch(arr, left, mid - 1, findVal);
} else {
return mid;
}
}
private static List binarySearch2(int[] arr, int left, int right, int findVal) {
//当 left > right 时,说明递归整个数组,但是没有找到,此时直接返回空list
if (left > right) {
return new ArrayList<>();
}
int mid = (left + right) / 2;
int midVal = arr[mid];
if (findVal > midVal) {
return binarySearch2(arr, mid + 1, right , findVal);
} else if (findVal < midVal) {
return binarySearch2(arr, left, mid - 1, findVal);
} else {
List resIndexList = new ArrayList<>();
//向 mid 索引值的左边扫描,将所有满足 1000 的元素的下标,加入到集合ArrayList
int temp = mid - 1;
while (true) {
//索引小于0表示已到达数组最左边,arr[temp] != findVal表示找到不等于findVal的就可以退出了
if (temp < 0 || arr[temp] != findVal) {
break;
}
resIndexList.add(temp); //找到了就加入list中
temp--; //因为是向左查找,所以索引值依次-1
}
//别忘了,还要将最先查找到的mid下标加入list中
resIndexList.add(mid);
//向mid 索引值的右边扫描,将所有满足 1000 的元素的下标,加入到集合ArrayList
temp = mid + 1;
while (true) {
//索引大于arr.length - 1表示已到达数组最右边,arr[temp] != findVal表示找到不等于findVal的就可以退出了
if (temp > arr.length - 1 || arr[temp] != findVal) {
break;
}
resIndexList.add(temp); //找到了就加入list中
temp++; //因为是向右查找,所以索引值依次+1
}
return resIndexList;
}
}
public static void main(String[] args) {
int[] arr = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 , 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 };
int resIndex = binarySearch(arr, 0, arr.length - 1, 14);
System.out.println("resIndex = " + resIndex);
System.out.println("---------------------------------");
int[] array = { 1, 8, 10, 89, 1000, 1000, 1000, 3333, 9527};
List list = binarySearch2(array, 0, array.length - 1, 1000);
System.out.println(list);
}
}
运用二分查找算法,在n个元素的数组中查找一个数,情况最遭时,需要(log2 n)步,所以二分查找的时间复杂度是O(log2 n)。
3.插值查找
改成→插值查找算法类似于二分查找,不同的是插值查找每次从自适应mid处开始查找。
将折半查找中的求mid 索引的公式 , low 表示左边索引left, high表示右边索引right. key 就是上面代码中的 findVal。
int mid = low + (high - low) * (key - arr[low]) / (arr[high] - arr[low]) ;
对应前面的代码公式: int mid = left + (right – left) * (findVal – arr[left]) / (arr[right] – arr[left])
package com.szh.search;
public class InsertValueSearch {
private static int insertValueSearch(int[] arr, int left, int right, int findVal) {
int num = 0;
System.out.println("插值查找的次数:" + (++num));
//注意:findVal < arr[0] 和 findVal > arr[arr.length - 1] 必须需要
//否则我们得到的 mid 可能越界
if (left > right || findVal < arr[0] || findVal > arr[arr.length - 1]) {
return -1;
}
//求出mid, 自适应 (插值查找的核心就是下面这行代码)
int mid = left + (right - left) * (findVal - arr[left]) / (arr[right] - arr[left]);
int midVal = arr[mid];
if (findVal > midVal) { //说明应该向右边递归
return insertValueSearch(arr, mid + 1, right, findVal);
} else if (findVal < midVal) { //说明向左递归查找
return insertValueSearch(arr, left, mid - 1, findVal);
} else {
return mid;
}
}
public static void main(String[] args) {
int[] arr = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 , 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 };
int resIndex = insertValueSearch(arr, 0, arr.length - 1, 14);
System.out.println("查找元素的下标 resIndex = " + resIndex);
}
}
插值查找注意事项:
对于数据量较大,关键字分布比较均匀的查找表来说,采用插值查找, 速度较快。关键字分布不均匀的情况下,该方法不一定比折半查找要好。



