在Java中常用的查找有四种:
(1)顺序(线性)查找
(2)二分查找(折半查找)
(3)插值查找
(4)斐波那契查找(黄金分割点查找)
一、线性查找:
public class SeqSearch {
public static void main(String[] args) {
int[] arr = {1,9,11,-1,43,89};
int index = seqSearch(arr, 11);
if (index==-1){
System.out.println("没有找到!");
}else{
System.out.println("找到,下标为" + index);
}
int[] arr = {1,9,11,-1,43,89,11};
// List<Integer> indexList = seqSearch2(arr, 11);
// if (indexList.size() > 0){
// System.out.println("符合条件的值的索引为:" + indexList);
// }else{
// System.out.println("没有符合条件的值!");
// }
/**
* 查找到一个满足条件的值就返回
* @param arr 待查找的数组
* @param value 要查找的值
* @return 返回元素在数组中的下标
*/
public static int seqSearch(int[] arr, int value){
for (int i = 0; i < arr.length; i++) {
if (arr[i] == value){
return i;
}
}
return -1;
}
/**
* 找到数组中所有满足条件的数字下标,然后返回
* @param arr
* @param value
* @return
*/
public static List<Integer> seqSearch2(int[] arr, int value){
//用于存储符合的值的索引
ArrayList<Integer> list = new ArrayList<Integer>();
for (int i = 0; i < arr.length; i++) {
if (arr[i] == value){
list.add(i);
}
}
return list;
}
}
二、二分查找:
(1)递归实现:
/*
二分查找:前提,数组必须是有序的
*/
public class BinarySearch {
public static void main(String[] args) {
int[] arr = {1,9,11,-1,43,89};
int index = binarySearch(arr, 0,5,11);
if (index==-1){
System.out.println("没有找到!");
}else{
System.out.println("找到,下标为" + index);
}
}
/**
* 递归实现二分查找
* @param arr 待查找数组
* @param left 左边索引
* @param right 右边索引
* @param findVal 需查找的值
* @return 找到就返回索引,没找到就返回-1
*/
public static int binarySearch(int[] arr,int left, int right, int findVal){
if (left > right){
return -1;
}
int mid = (left + right) / 2;//中间索引
int midVal = arr[mid];
if (midVal > findVal){//中间值大,需要向左递归
return binarySearch(arr,left,mid - 1, findVal);
}else if (midVal < findVal){//中间值小,需要向右递归
return binarySearch(arr,mid + 1,right,findVal);
}else {
return mid;
}
}
}
/**
* 返回数组中所有符合条件的值得索引
* @param arr
* @param left
* @param right
* @param findVal
* @return
*/
public static List binarySearch2(int[] arr, int left, int right, int findVal){
if (left > right){
return new ArrayList();
}
int mid = (left + right) / 2;//中间索引
int midVal = arr[mid];
if (midVal > findVal){//中间值大,需要向左递归
return binarySearch2(arr,left,mid - 1, findVal);
}else if (midVal < findVal){//中间值小,需要向右递归
return binarySearch2(arr,mid + 1,right,findVal);
}else {
ArrayList<Integer> list = new ArrayList<>();
int temp = mid - 1;//向左查找重复的
while (true){
if (temp < 0 || arr[temp] != findVal){
break;
}
list.add(temp);
temp--;
}
list.add(mid); //添加当前的
temp = mid + 1; //向右查找重复的
while (true){
if (temp > arr.length || arr[temp] != findVal){
break;
}
list.add(temp);
temp++;
}
return list;
}
}
/**
* 返回数组中所有符合条件的值得索引,方法2 的另一种实现
* @param arr
* @param left
* @param right
* @param findVal
* @return
*/
public static List binarySearch3(int[] arr, int left, int right, int findVal){
if (left > right){
return new ArrayList();
}
int mid = (left + right) / 2;//中间索引
int midVal = arr[mid];
if (midVal > findVal){//中间值大,需要向左递归
return binarySearch3(arr,left,mid - 1, findVal);
}else if (midVal < findVal){//中间值小,需要向右递归
return binarySearch3(arr,mid + 1,right,findVal);
}else {
ArrayList<Integer> list = new ArrayList<>();
for (int i = mid - 1; i >= 0 ; i--) {//向左找
if (arr[i] == findVal){
list.add(i);
}else{
break;
}
}
list.add(mid);
for (int j = mid + 1; j < arr.length; j++) {
if (arr[j] == findVal){
list.add(j);
}else{
break;
}
}
return list;
}
}
(2)非递归实现:
//非递归实现二分查找
public static int binarySearchNoRecur(int[] arr, int findVal){
int left = 0;
int right = arr.length-1;
while (left <= right){
int mid = (left + right) / 2;
if (arr[mid] == findVal){
return mid;
} else if (arr[mid] < findVal){ //向右找,改变的是left
left = mid +1;
}else {
right = mid-1;
}
}
return -1;
}
三、插值查找:
重要的是中间索引的优化:int mid = left + (right - left)*(findVal - arr[left]) / (arr[right] - arr[left]);
注意:(1)对于数据量较大,关键字分布比较均匀的查找表来说,采用差值查找,速度较快(2)关键字分布不均匀的情况下,该方法不一定比折半查找要好。
package search;
/**
* 插值查找
*/
public class InsertValueSearch {
public static void main(String[] args) {
int[] arr = new int [100];
for (int i = 0; i < 100; i++) {
arr[i] = i + 1;
}
int index = insertValueSreach(arr, 0, 99, 50);
if (index==-1){
System.out.println("没有找到!");
}else{
System.out.println("找到,下标为" + index);
}
}
public static int insertValueSreach(int[] arr, int left, int right, int findVal){
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 (midVal > findVal){//中间值大,需要向左递归
return insertValueSreach(arr,left,mid - 1, findVal);
}else if (midVal < findVal){//中间值小,需要向右递归
return insertValueSreach(arr,mid + 1,right,findVal);
}else {
return mid;
}
}
}