關(guān)于二分法查找Java的實現(xiàn)及解析
二分法查找
概述
二分查找也稱折半查找(Binary Search),它是一種效率較高的查找方法。
但是,折半查找要求線性表必須采用順序存儲結(jié)構(gòu),而且表中元素按關(guān)鍵字有序排列。
歸并排序即運用了二分法的思想。首先需要一個由小到大排序好的數(shù)組,先對比中間的值,如果比要找的大,則向前找,取中間值前面的一半再找中間值再對比。
如果比要找的小,則向后找,取中間值后面的一半再取中間值再對比。

遞歸實現(xiàn)
這里,我使用了遞歸的方法進行實現(xiàn)。
首先需要確認(rèn)查找的范圍,即有一個左索引和右索引,每次取(left+right)/2為中間值,比較要查找的元素和中間值的大小,若中間值大,則向前找,即遞歸范圍為left ,mid-1。反之向右找,即遞歸范圍mid+1,right。若相等即為找到。
但是需要繼續(xù)向此索引的前后找找看有沒有和其相等的值,一并加入到集合中,最后返回這個集合。
遞歸實現(xiàn)代碼
package search;
import java.util.ArrayList;
import java.util.List;
public class BinarySearch {
public static void main(String[] args) {
int[] array = {1,1,1,2,3,4,5,6,7};
List<Integer> integers = binarySearch(array, 0, array.length - 1, 1);
// for (Integer integer : integers) {
// System.out.print(integer+ " ");
// }
System.out.println(integers);
}
public static List<Integer> binarySearch(int[] array, int left, int right, int value){
//如果左索引大于右索引,則說明全部遍歷完了,也沒有找到相應(yīng)的值,返回空集合即可
if (left>right){
return new ArrayList<Integer>();
}
//獲取中間值的下標(biāo)(二分)
int mid = (left+right)/2;
//如果要找的值比中間值小,則繼續(xù)向左找
if (value < array[mid]){
return binarySearch(array, left, mid-1, value);
//要找的值比中間值小大,則向右找
}else if (value > array[mid]){
return binarySearch(array, mid+1, right, value);
//否則,說明相等,找到了
}else {
//找到一個,還需要向左右找找看有沒有相同的值
List<Integer> resultList = new ArrayList();
//向左循環(huán)找,如果有,則加入到集合中
int temp = mid - 1;
while (temp>=0 && array[temp] == value){
resultList.add(temp);
temp -= 1;
}
//向右循環(huán)找,如果有,則加入到集合中
temp = mid + 1;
while (temp < array.length && array[temp] == value){
resultList.add(temp);
temp += 1;
}
//將一開始找到的那個索引頁加入到集合中。
resultList.add(mid);
return resultList;
}
}
//以下這段代碼來自百度百科,供大家參考。
public static int binarySearch(Integer[] srcArray, int des) {
//定義初始最小、最大索引
int start = 0;
int end = srcArray.length - 1;
//確保不會出現(xiàn)重復(fù)查找,越界
while (start <= end) {
//計算出中間索引值
int middle = (end + start)>>>1 ;//防止溢出
if (des == srcArray[middle]) {
return middle;
//判斷下限
} else if (des < srcArray[middle]) {
end = middle - 1;
//判斷上限
} else {
start = middle + 1;
}
}
//若沒有,則返回-1
return -1;
}
}
循環(huán)實現(xiàn)代碼(非遞歸)
package search;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* @Author: sshdg
* @Date: 2020/9/21 9:22
*/
public class BinarySearch2 {
public static void main(String[] args) {
int[] array = {1,1,1,1,1,2,3,4,5,6,7};
System.out.println(BinarySearch2.binarySearch(array, 7));
}
public static List<Integer> binarySearch(int[] array, int key){
List<Integer> resultList = new ArrayList<>();
int start = 0;
int end = array.length - 1;
while (start <= end){
int mid = (start + end) / 2;
int midValue = array[mid];
if (key > midValue){
//key比中間值大。向右找
start = mid + 1;
} else if (key < midValue){
//key比中間值小。向左找
end = mid - 1;
} else {
//否則就找到了
//先向左找有沒有相同值
int temp = mid -1;
while (temp >= start && array[temp] == key){
resultList.add(temp);
temp -= 1;
}
//將一開始找到的加入結(jié)果集
resultList.add(mid);
//再向右找找有沒有相同值
temp = mid + 1;
while (temp <= end && array[temp] == key){
resultList.add(temp);
temp += 1;
}
break;
}
}
return resultList;
}
}
二分法查找(遞歸、循環(huán))
public class BinarySearch {
/**
* @author JadeXu
* @// TODO: 2020/12/7 二分查找
* 思路:
* 1、獲取數(shù)組的中間值,先獲取下標(biāo),方便多次查找
* 奇數(shù)位的數(shù)組直接獲取中間位,偶數(shù)位的數(shù)組獲取中間的第一位或第二位都可,一般獲取第一位(因為與奇數(shù)位獲取中間值的方法一樣)
* 2、獲取查找的區(qū)間范圍,start:區(qū)間開始的下標(biāo),end:區(qū)間結(jié)束的下標(biāo)
* 3、判斷查找的數(shù)和中間位的數(shù)是否相同
* 相同時,直接返回需要的數(shù)據(jù),跳出方法
* 大于時,即數(shù)可能在中間值右邊的區(qū)間內(nèi),此時start = mid+1,即mid往后移一位,就得到了中間值右邊區(qū)間的開始下標(biāo)
* 小于時,即數(shù)可能在中間值左邊的區(qū)間內(nèi),此時end = mid-1,即mid往前移一位,就得到了中間值左邊區(qū)間的結(jié)束下標(biāo)
* 當(dāng)一個區(qū)間里,開始下標(biāo)小于等于結(jié)束下標(biāo)時,該區(qū)間才是有效區(qū)間,才能繼續(xù)查找。否則無效,返回找不到,跳出方法
*/
//循環(huán)
/**
* @param arr 已經(jīng)升序好的int[]
* @param num 需要查找的數(shù)字
* @return 找到則返回下標(biāo),沒找到則返回-1
*/
private static int binarySearchByCycle(int[] arr,int num) {
int start = 0;
int end = arr.length - 1;
while (start <= end){
int mid = (start + end) / 2;
if(num == arr[mid]){
return mid;
}else if(num > arr[mid]){
start = mid + 1;
}else {
end = mid - 1;
}
}
return -1;
}
//遞歸
/**
* @param arr 已經(jīng)升序好的int[]
* @param num 需要查找的數(shù)字
* @param start 區(qū)間開始下標(biāo)
* @param end 區(qū)間結(jié)束下標(biāo)
* @return 找到則返回下標(biāo),沒找到則返回-1
*/
private static int binarySearchByRecursion(int[] arr,int num,int start,int end) {
int mid = (start + end) / 2;
if(num == arr[mid]){
return mid;
}else if(num > arr[mid]){
start = mid + 1;
}else {
end = mid - 1;
}
if(start <= end){
mid = binarySearchByRecursion(arr,num,start,end); //遞歸繼續(xù)尋找
}else {
mid = -1;
}
return mid;
}
}
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
Spring Boot啟動過程(四)之Spring Boot內(nèi)嵌Tomcat啟動
這篇文章主要介紹了Spring Boot啟動過程(四)之Spring Boot內(nèi)嵌Tomcat啟動的相關(guān)資料,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2017-04-04
基于spring?@Cacheable?注解的spel表達(dá)式解析執(zhí)行邏輯
這篇文章主要介紹了spring?@Cacheable?注解的spel表達(dá)式解析執(zhí)行邏輯,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-01-01
Java反射通過Getter方法獲取對象VO的屬性值過程解析
這篇文章主要介紹了Java反射通過Getter方法獲取對象VO的屬性值過程解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-02-02
springboot整合shiro登錄失敗次數(shù)限制功能的實現(xiàn)代碼
這篇文章主要介紹了springboot整合shiro-登錄失敗次數(shù)限制功能,實現(xiàn)此功能如果是防止壞人多次嘗試,破解密碼的情況,所以要限制用戶登錄嘗試次數(shù),需要的朋友可以參考下2018-09-09
Spring動態(tài)配置計時器觸發(fā)時間的實例代碼
這篇文章主要介紹了Spring動態(tài)配置計時器觸發(fā)時間的實例代碼,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下2018-06-06

