1.线性查找的思路
线性查找是一种最简单粗暴的查找法了,采用逐一比对的方式进行对数组的遍历,如果发现了匹配值,返回数组下标即可
package com.liz.seq_search;
public class SeqSearchDemo {
private static int count=0;
public static void main(String[] args) {
//无序序列
int arr[] = {1, 9, 11, -1, 34, 55};
int index=seqSearch(arr,55);
if(index==-1){
System.out.println("未找到");
}
System.out.println("代码执行了"+count+"次"+" "+"找到的位置为"+index);
}
//线性查找: 逐一比对,发现有相同的值时,返回下标
public static int seqSearch(int[] arr, int value) {
for (int i = 0; i < arr.length; i++) {
count++;
if(arr[i]==value){
return i;
}
}
return -1;
}
}
2.二分查找法的思路
2-1: 首先要确定该数组中间的 下标
mid=(left+right)/2
2-2:然后让需要查找的数findVal和arr[mid]做比较
findVal>arr[mid],说明了你要查找的数在mid的右边,因此需要递归向右查找
findVal<arr[mid],说明了你要查找的数在mid的左边,因此需要递归向左查找
findVal==arr[mid],说明找到了,需要返回
2-3:确定递归结束的条件
*找到目标数就结束递归
*递归完整个数组依旧没有找到目标数,也要结束递归
2-4: 举个栗子
public static int binarySearch(int[] arr, int left, int right, int findVal) {
count++;
int mid = (left + right) / 2;
int midVal = arr[mid];
//如果没有找到
if (left > right) {
return -1;
}
//向右递归
if (findVal > midVal) {
return binarySearch(arr, mid + 1, right, findVal);
} else if (findVal < midVal) {//向左递归
return binarySearch(arr, left, mid - 1, findVal);
} else {
return mid;
}
}
public static void main(String[] args) {
int arr[] = {1, 8, 10, 89, 1000,1000, 1234};
int resultIndex = binarySearch(arr, 0, arr.length, 10);
if (resultIndex == -1) {
System.out.println("未找到当前数据");
return;
}
System.out.println(resultIndex);
// ArrayList<Integer>list=binarySearchUp(arr,0,arr.length,12);
// if(list.size()==0){
// System.out.println("未找到当前数据");
// return;
// }
// System.out.println(list);
}
注:使用这种方式进行数据的寻找虽然可行,但是如果在数组存在重复的目标值,只能定位一个下标,无法定位所有的值。
(在这里反应的是,虽然有两个1000 位置分别是4 和 5 ,但是只定位了一个5)
所以,我们可以采用一些方法进行优化,将原来方法中返回一个具体的mid,改成返回一个带有mid标志位的容器即可
(本栗子中采用了ArrayList进行存储中间值)
public static ArrayList binarySearchUp(int[] arr, int left, int right, int findVal) {
int mid = (left + right) / 2;
int midVal = arr[mid];
//如果没有找到
if (left > right) {
return new ArrayList<Integer>();
}
//向右递归
if (findVal > midVal) {
return binarySearchUp(arr, mid + 1, right, findVal);
} else if (findVal < midVal) {//向左递归
return binarySearchUp(arr, left, mid - 1, findVal);
} else {
//这里已经找到了mid值
ArrayList<Integer> resIndexList=new ArrayList<Integer>();
//向左扫描
int temp=mid-1;
while(true){
//已经无法再向左扫描了
if(temp<0 || arr[temp]!=findVal){
break;
}
//否则就把temp放入到集合中
resIndexList.add(temp);
temp--;
}
resIndexList.add(mid);
//向右扫描
temp=mid+1;
while(true){
//已经无法再向右扫描了
if(temp>arr.length-1 || arr[temp]!=findVal){
break;
}
//否则就把temp放入到集合中
resIndexList.add(temp);
temp++;
}
return resIndexList;
}
}
public static void main(String[] args) {
int arr[] = {1, 8, 10, 89, 1000,1000, 1234};
// int resultIndex = binarySearch(arr, 0, arr.length, 1000);
// if (resultIndex == -1) {
// System.out.println("未找到当前数据");
// return;
// }
// System.out.println("代码执行了"+count+"次"+" "+"找到的位置为:"+resultIndex);
ArrayList<Integer>list=binarySearchUp(arr,0,arr.length,12);
if(list.size()==0){
System.out.println("未找到当前数据");
return;
}
System.out.println("找到的索引值为"+list);
}
3.基数查找的思路
基数查找和二分查找执行原理上差不多,但是和二分查找的区别在于对于mid的定位
基数查找定位mid:
mid= (left+right)/2
二分查找定位mid:
mid= left + (right - left) * (findVal - arr[left]) / (arr[right] - arr[left]);
举个栗子:
package com.liz.insertval_search;
//采取自适应mid的方法进行
//自适应公式: left+(right-low)*(findVal-arr[left])/(arr[high]-arr[low])
/**
* 注意事项:
* 对于数据量较大,关键词分布比较均匀的查找而言,采用插值查找速度较快
* 关键字分布不均匀的情况下,该方法不一定比折半查找法好
* */
public class InsertValSearchDemo {
public static int count=0;
public static void main(String[] args) {
int arr[] = new int[100];
for (int i = 0; i < 100; i++) {
arr[i] = i + 1;
}
int midValue=insertValSearch(arr,0,arr.length-1,20);
System.out.println("代码执行了"+count+"次"+" "+"找到的位置为"+midValue);
}
public static int insertValSearch(int[] arr, int left, int right, int findVal) {
count++;
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 insertValSearch(arr, mid + 1, right, findVal);
} else if (findVal < midVal) {//说明应该向左进行递归
return insertValSearch(arr,left,mid-1,findVal);
}else{
return mid;
}
}
}
(在本栗子中对100个连续数字采用插值查找,通过自适应mid,仅仅用了一次就将结果查询出来了)
如果将相同的测试用例放在二分法中,大家不妨试试
注:插值查找法可以说是二分查找法在既定条件下的一种优化,对于数据量较大,数据分布比较均匀的查找而言,采用插值查找速度较快。但是如果数据分布不均,二分查找法不一定比插值查找法差。