你們好,我是阿濠,今篇內容跟你們分享的是查找算法之插值查找法,很高興分享到segmentfault與你們一塊兒學習交流,初次見面請你們多多關照,一塊兒學習進步.
二分查找算法
根據折半進行查找
,可是還能根據二分查找
進行優化嗎
?算法
假設咱們如今有數組arr={1,2,3,4,5,6,7,8,10,11,12}
,咱們使用二分法查找:1
segmentfault
那麼根據特性
執行會執行幾回操做
:先是找到中間值
、二分
、再進行二分
...數組
那麼能不能經過自適應的方案
,快速定位
到須要查找的值呢
?app
那麼就可使用插值查找算法
性能
1.插值查找算法相似於二分查找
,不一樣
的是插值查找
每次從自適應mid處開始
查找。學習
2.將折半查找中
的求mid索引的公式
進行優化
,key
表明查找的值findValue
優化
公式爲:int midIndex = low + (high - low) * (key - arr[low]) / (arr[high]- arr[low]);
spa
對應代碼:int mid= left+(right-left) *(findvalue -arr[left])/ (arr[right]-arr[left])
code
二分查找法
爲何是 left + right / 2
呢?由於二分法查找的思想
:基於數組的有序性,每次都將當前的數組分爲兩半,經過關鍵字和中間元素的比較,當即排除掉其中不可能存在和鍵值相等的元素的那一半
。blog
因此使用經過 left + right / 2
,並比較Key
和arr[mid]大小
,丟掉"一半的元素
"
(從 left + right / 2
能夠看出被排除的一半元素
不會歸入到下一次的比較中
了)
插值查找
爲何是(findvalue-arr[left])/(arr[right]-arr[left])
?首先咱們根據基於數組的有序性
,想想查找的位置
必定要從中間開始查找嗎
?
打個比方:咱們在一本英文字典裏
面查找apple
這個單詞的時候, 你確定不會從字典中間開始查找
, 而是從字典開頭部分開始翻
,由於以爲這樣
的找法纔是比較快
的。
那麼爲何
你會從頭部分開始翻呢
?由於知道字典
是按照字母有序排序
的,而且apple
這個單詞是a開頭
,因此從頭開始翻
,對嘛?
那麼這時
就有了一個思路
: 若是能在查找前
較準確地預測關鍵字
在數組中的位置
的話,這樣的查找方法能比二分查找提升更多的性能
!
因此根據差值公式( key - arr[low]) / (arr[high] -arr[low])
,將要查找的關鍵字
key 與查找表中的最大、最小記錄的關鍵字比較
的查找方法。
舉例:有一數組arr=[1,2,3,4,5,6,7,8......100]
假設咱們須要查找
的值爲:1
按照二分法查找
:須要 mid = (left + right ) / 2
,折半...再折半...才找到1
按照插值查找算法
int mid = left+(right-left) \* (findvalue -arr[left]) / (arr[right]-arr[left])
對應的代碼:int mid= 0+(99-0) * (1- 1) / (100-1) = 0+99 * 0 / 99 = 0
直接找到值:1
好比咱們查找的值爲:100
對應的代碼:int mid=0 + (99-0) * (100-1) /(100-1)= 0+99 * 99/99 = 0+99=99
/** * @param arr 數組 * @param left 左邊索引 * @param right 右邊索引 * @param findValue 查找值 * @return 若是找到則返回對應的下標,沒有找到返回-1 便可 */ //編寫插值查找方法 public static int insertValueSearch(int[] arr,int left,int right,int findValue){ //1、沒有找到的狀況或者查找的值(小於數組最小值或者大於數組最大值) if(left>right||findValue<arr[0]||findValue>arr[arr.length-1]){ return -1; } //找出預測數組中的位置 int mid=left+(right - left) * (findValue - arr[left]) / (arr[right]-arr[left]); //對應的預測值 int midValue=arr[mid]; //若查找的值比定位的值大,則須要向右遞歸 if(findValue>midValue){ //若`findVale>arr[mid]`,則說明查找的數`findValue在右邊`,進行遞歸`向右查詢` return insertValueSearch(arr,mid+1,right,findValue); }else if(findValue<midValue){ //若`findVale<arr[mid]`,則說明查找的數`findValue在左邊`,進行遞歸`向左查詢` return insertValueSearch(arr,left,mid -1,findValue); }else{ //若`findVale = =arr[mid]`,則說明`查找的數已找到並返回下標` return mid; } }
int[] arr = new int[100]; for (int i = 0; i < 100; i++) { arr[i] = i + 1; } /** * 在元素數值均勻分佈的有序數組裏面, 用這種方法查找是很快的。 * 特別的,對絕對均勻分佈的數組(相鄰元素差值相同), 插值查找用一次比較就能查找成功 * 固然了,前提是數組中元素數值是均勻分佈的 * 若是是對 1,2,40,99,1000這種分佈很不均勻的數組, 插值查找的計算會起到反效果, 就不如二分查找了 */ int index=insertValueSearch(arr,0,arr.length-1,100); System.out.println("查找的值對應下標是:"+index); 運行結果以下: 查找的值對應下標是:99
在元素數值均勻分佈的有序數組裏面
, 用這種方法查找是很快
的。特別的,對絕對均勻分佈的數組(相鄰元素差值相同)
, 插值查找用一次比較就能查找成功:
固然了, 前提是數組中元素數值是均勻分佈的
, 若是是對 1,2,40,99,1000
這種分佈很不均勻的數組
, 插值查找的計算會起到反效果
, 就不如二分查找了
時間複雜度平均爲:O(logn)