常見查找算法Java實現

  • 順序(線性)查找
  • 二分查找/折半查找
  • 插值查找
  • 斐波那契查找

線性查找

判斷數列是否包含要求,如果找到了,就提示找到了,并給出下標值

// 線性查找
public static ArrayList<Integer> seqSearch(int[] arr, int value) {ArrayList<Integer> list = new ArrayList<>();for (int i = 0; i < arr.length; i++) {if (value == arr[i]) {list.add(i);}}return list;
}

二分查找

需要對一個有序數組進行二分查找 {1, 8, 10, 89, 1000, 1234},輸入一個數
看看該數組是否存在此數,并且求出下標,如果沒有就提示”沒有這個數”。

思路

  1. 確定該數組的中間的下標

    可以向下取整,也可以向上取整。e.g:4.5向上取整為 5;向下去整為4,此處演示為向下取整
    

    mid=(left+right)/2

  2. 讓需要查找的數findVal和arr[mid]比較

    • findVal>arr[mid,說明你要查找的數在mid的右邊,因此需要遞歸的向右查找
    • findVal<arr[mid],說明你要查找的數在mid的左邊,因此需要遞歸的向左查找
    • findVal==arr[mid說明找到,就返回
  3. 遞歸結束

    • 找到就結束遞歸
    • 遞歸完整個數組,仍然沒有找到findVal,也需要結束遞歸當Ieft>right就需要退出
/**
* 二分查找 ---要求數組為有序數組
* @param arr 需要查詢的數組
* @param left 數組的最左側下標
* @param right 數組的最右側下標
* @param findVal 需要查詢的值
* @return
*/
public static int binarySearch(int[] arr, int left, int right, int findVal) {// 當 left > right 時,整個數組遍歷后并未找到值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;}
}

二分優化—多索引返回

// 二分查找 ---要求數組為有序數組
public static ArrayList<Integer> binarySearch(int[] arr, int left, int right, int findVal) {// 當 left > right 時,整個數組遍歷后并未找到值if (left > right) {return new ArrayList<Integer>();}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 {// 找到值ArrayList<Integer> resIndexList = new ArrayList<>();// 向 mid 的左右兩邊掃描
//            int temp = mid - 1;
//            while (true) {// 向左
//                if (temp < 0 || arr[temp] != findVal) {// 退出
//                    break;
//                }
//                // 否則,就temp 放入到resIndexList
//                resIndexList.add(temp);
//                temp -= 1; // temp左移
//            }
//            resIndexList.add(mid); // 將中間索引加入
//
//            temp = mid + 1;
//            while (true) {// 向右
//                if (temp > arr.length - 1 || arr[temp] != findVal) {// 退出
//                    break;
//                }
//                // 否則,就temp 放入到resIndexList
//                resIndexList.add(temp);
//                temp += 1; // temp右移
//            }// 再優化resIndexList.add(mid); // 將中間索引加入for (int i = mid - 1; i >= 0; i--) {// 向左if (arr[i] != findVal) {break;}resIndexList.add(i);}for (int i = mid + 1; i <= arr.length - 1; i++) {// 向右if (arr[i] != findVal) {break;}resIndexList.add(i);}return resIndexList;}
}

插值查找

需要數組是有序,效率比二分查找更高效

  • 插值查找算法類似于二分查找,不同的是插值查找每次從自適應mid處開始查找。

  • 將折半查找中的求mid索引的公式,low表示左邊索引,high表示右邊索引right

  • m i d = l o w + h i g h 2 = l o w + 1 2 ( h i g h ? l o w ) mid=\frac{low+high}{2}=low+\frac{1}{2}(high-low) mid=2low+high?=low+21?(high?low) ?? m i d = l o w + k e y ? a [ l o w ] a [ h i g h ] ? a [ l o w ] ( h i g h ? l o w ) mid=low+\frac{key-a[low]}{a[high]-a[low]}(high-low) mid=low+a[high]?a[low]key?a[low]?(high?low) 【其中key為需要查找的值】

  • 公式優化:int m i d I n d e x = l o w + ( h i g h ? l o w ) ? ( k e y ? a r r [ l o w ] ) / ( a r r [ h i g h ] ? a r r [ l o w ] ) ; midIndex=low+(high-low)*(key-arr[low])/(arr[high]-arr[low]); midIndex=low+(high?low)?(key?arr[low])/(arr[high]?arr[low]);

// 插值查找 ---要求數組為有序數組
// 其中key為需要查找的值
public static int insertValueSearch(int[] arr, int left, int right, int key) {// 注意:key < arr[0] || key > arr[arr.length - 1]必須要有(優化作用),否則可能會造成midIndex越界if (left > right || key < arr[0] || key > arr[arr.length - 1]) {return -1;}int midIndex = left + (right - left) * (key - arr[left]) / (arr[right] - arr[left]);int midVal = arr[midIndex];if (key > midVal) {// 向右掃描遞歸return insertValueSearch(arr, midIndex + 1, right, key);} else if (key < midVal) {// 向左掃描遞歸return insertValueSearch(arr, left, midIndex - 1, key);} else {return midIndex;}}
總結
  • 對于數據量較大,關鍵字分布比較均勻的查找表來說,采用插值查找,速度較快
  • 關鍵字分布不均勻的情況下,該方法不一定比折半查找要好

斐波那契查找(黃金分割法)

需要數組是有序

  • 黃金分割點是指把一條線段分割為兩部分,使其中一部分與全長之比等于另一部分與這部分之比。取其前三位數字的近似值是0.618。由于按此比例設計的造型十分美麗,因此稱為黃金分割,也稱為中外比。這是一個神奇的數字,會帶來意向不大的效果。
  • 斐波那契數列{1,1,2,3,5,8,13,21,34,55}發現斐波那契數列的兩個相鄰數的比例,無限接近黃金分割值0.618

原理

在這里插入圖片描述

斐波那契查找原理與前兩種相似,僅僅改變了中間結點(mid)的位置,mid不再是中間或插值得到,而是位于黃金分割點附近,即 m i d = l o w + F ( k ? 1 ) ? 1 mid=low+F(k-1)-1 mid=low+F(k?1)?1 (F代表斐波那契數列。k代表斐波那契個數)

對F(k-1)-1的理解:

  • 由斐波那契數列 F [ K ] = F [ k ? 1 ] + F [ k ? 2 ] F[K]=F[k-1]+F[k-2] F[K]=F[k?1]+F[k?2]的性質,可以得到 ( F [ k ] ? 1 ) = ( F [ k ? 1 ] ? 1 ) + ( F [ k ? 2 ] ? 1 ) + 1 (F[k]-1)=(F[k-1]-1)+(F[k-2]-1)+1 (F[k]?1)=(F[k?1]?1)+(F[k?2]?1)+1
    該式說明:只要順序表的長度為 F [ k ] ? 1 F[k]-1 F[k]?1,則可以將該表分成長度為 F [ k ? 1 ] ? 1 F[k-1]-1 F[k?1]?1 F [ k ? 2 ] ? 1 F[k-2]-1 F[k?2]?1的兩段,從而中間位置為 m i d = l o w + F ( k ? 1 ) ? 1 mid=low+F(k-1)-1 mid=low+F(k?1)?1

  • 類似的,每一子段也可以用相同的方式分割

  • 但順序表長度 n n n不一定剛好等于 F [ K ] ? 1 F[K]-1 F[K]?1,所以需要將原來的順序表長度n增加至 F [ K ] ? 1 F[K]-1 F[K]?1。這里的 k k k值只要能使得 F [ k ] ? 1 F[k]-1 F[k]?1恰好大于或等于 n n n即可,由以下代碼得到,順序表長度增加后,新增的位置(從 n + 1 n+1 n+1 F [ K ] ? 1 F[K]-1 F[K]?1位置),都賦為 n n n位置的值即可。

    while (high > f[k] - 1) {// 如果大于,則k++k++;
    }
    

注意:因為黃金分割點是第三段的前一段除以整段,之所以減1是因為數組是從0開始,所以 F [ k ] ? 1 = ( F [ k ? 1 ] ? 1 ) + ( F [ k ? 2 ] ? 1 ) + 分割點 F[k]-1=(F[k-1]-1)+(F[k-2]-1)+分割點 F[k]?1=(F[k?1]?1)+(F[k?2]?1)+分割點,第三點,由于f(k) 有可能小于n(也就是high),就不滿足斐波那契數列要求

// 使用非遞歸方法得到一個斐波那契數列
public static int maxSize = 20;// 后面需要mid=low+F(k-1)-1,因此先獲取一個斐波那契數列
public static int[] fib() {int[] f = new int[maxSize];f[0] = 1;f[1] = 1;for (int i = 2; i < maxSize; i++) {f[i] = f[i - 1] + f[i - 2];}return f;
}// 斐波那契查找 --- 非遞歸
// key為需要查找的關鍵碼(值)
public static int fibSearch(int[] a, int key) {int low = 0;int high = a.length - 1;int k = 0; // 表示斐波那契分割數值的下標int mid = 0; // 存放a數組分割點int[] f = fib(); // 獲取到斐波那契數列// 獲取到斐波那契分割數值的下標// f[k] - 1 為臨時數組的長度,不得小于a數組的長度while (high > f[k] - 1) {// 如果大于,則k++k++;}// f[k] 可能大于a 的長度,因此需要使用Arrays類構造一個新的數組,并指向temp[]// 不足的部分會使用0填充int[] temp = Arrays.copyOf(a, f[k]);// 實際上需要使用a數組的數填充temp// temp = {1, 8, 10, 80, 1000, 0, 0, 0} => {1, 8, 10, 80, 1000, 1000, 1000, 1000}for (int i = high + 1; i < temp.length; i++) {temp[i] = a[high];}// 使用while 來循環處理找到我們的數keywhile (low <= high) {mid = low + f[k - 1] - 1;if (key < temp[mid]) {// 向左邊查找high = mid - 1;// f[k] = f[k-1] + f[k-2],之后f[k-1]繼續拆分,因此k--k--;} else if (key > temp[mid]) { // 向右查找low = mid + 1;// f[k] = f[k-1] + f[k-2],之后f[k-2]繼續拆分// f[k-1] = f[k-3] + f[k-4],因此k -=2k -= 2;} else {// 找到if (mid <= high) {return mid;} else {return high;}}}return -1;
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/712487.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/712487.shtml
英文地址,請注明出處:http://en.pswp.cn/news/712487.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

解決 npm install 報錯的問題

在使用 npm 安裝依賴包時&#xff0c;有時候會遇到各種報錯問題&#xff0c;以下是一些常見的報錯及解決方法&#xff1a; 1. ENOENT: no such file or directory 如果出現類似 ENOENT: no such file or directory 的報錯&#xff0c;可能是因為某些文件或目錄缺失或路徑錯誤…

動態規劃課堂3-----簡單多狀態問題(買賣股票最佳時機)

目錄 引入&#xff1a; 例題1&#xff1a;按摩師&#xff08;打家劫舍I&#xff09; 例題2&#xff1a;打家劫舍II 例題3&#xff1a;刪除并獲得點數 例題4&#xff1a;粉刷房子 例題5&#xff1a;買賣股票的最佳時機含冷凍 結語&#xff1a; 引入&#xff1a; 相信看到…

深度學習 精選筆記(8)梯度消失和梯度爆炸

學習參考&#xff1a; 動手學深度學習2.0Deep-Learning-with-TensorFlow-bookpytorchlightning ①如有冒犯、請聯系侵刪。 ②已寫完的筆記文章會不定時一直修訂修改(刪、改、增)&#xff0c;以達到集多方教程的精華于一文的目的。 ③非常推薦上面&#xff08;學習參考&#x…

帶你快速初步了解Python列表

1.列表 列表主要是用來存儲多個數據&#xff0c;是有序的集合 2.創建列表 """ 語法&#xff1a;變量名 [數據1,數據2,數據3......] 注意&#xff1a;列表中的數據類型可以是各種不同的數據類型 """ 創建空列表 list1 [] print(list1) …

Gitlab: 私有化部署

目錄 1. 說明 2. 資源要求 3. 安裝 4. 配置實踐 4.1 服務器 4.2 人員與項目 4.2 部署準備 4.2.1 訪問變量及用戶賬號設置 4.2.2 Runner設置 4.2.3 要點 5. 應用項目 CI/CD 6. 參考 1. 說明 gitlab是一個強大且免費的代碼管理/部署工具&#xff0c;能統一集成代碼倉…

AngularJS入門

1. AngularJS簡介 AngularJS是一個JavaScript框架,用js編寫的庫 <script src="https://cdn.staticfile.org/angular.js/1.4.6/angular.min.js"></script> <!-- 放在<body> 元素的底部。提高網頁加載速度 -->1.1. AngularJS 擴展了 HTML …

Freesia項目目錄結構

目錄結構 前端目錄&#xff1a; &#xff08;目錄結構來自layui-vue-admin&#xff09; src文件下 api&#xff08;前端請求后端服務的路由&#xff09;assert&#xff08;一些內置或必要的資源文件&#xff09;layouts&#xff08;全局框架樣式組件&#xff09;router&…

Unity(第十九部)射線

在Unity中&#xff0c;射線檢測通常用于碰撞檢測&#xff0c;比如&#xff1a;在游戲中&#xff0c;開槍射擊時&#xff0c;需要判斷擊中的物體、子彈擊中的位置&#xff1b;用鼠標來控制物體的移動&#xff1b;用鼠標拾取某個物體。 射線&#xff0c;顧名思義&#xff0c;在數…

【轉載】深度學習筆記——詳解損失函數

原文鏈接: https://blog.csdn.net/weixin_53765658/article/details/136360033 CSDN賬號: Purepisces github賬號: purepisces 希望大家可以Star Machine Learning Blog https://github.com/purepisces/Wenqing-Machine_Learning_Blog 損失函數 根據您使用的神經網絡類型和數…

第四十七回 一丈青單捉王矮虎 宋公明二打祝家莊-強大而靈活的python裝飾器

四面全是埋伏&#xff0c;宋江和眾人一直繞圈跑不出去。正在慌亂之時&#xff0c;石秀及時趕到&#xff0c;教大家碰到白楊樹就轉彎走。走了一段時間&#xff0c;發現圍的人越來越多&#xff0c;原來祝家莊以燈籠指揮號令。花榮一箭射下來紅燈龍&#xff0c;伏兵自己就亂起來了…

Northwestern University-844計算機科學與技術/軟件工程-復試注意事項【考研復習】

本文提到的西北大學是位于密歇根湖泊畔的西北大學。西北大學&#xff08;英語&#xff1a;Northwestern University&#xff0c;簡稱&#xff1a;NU&#xff09;是美國的一所著名私立研究型大學。它由九人于1851年創立&#xff0c;目標是建立一所為西北領地地區的人服務的大學。…

【力扣白嫖日記】550.游戲玩法分析IV

前言 練習sql語句&#xff0c;所有題目來自于力扣&#xff08;https://leetcode.cn/problemset/database/&#xff09;的免費數據庫練習題。 今日題目&#xff1a; 550.游戲玩法分析IV 表&#xff1a;Activity 列名類型player_idintdevice_idintevent_datedategames_played…

從 iOS 設備恢復數據的 20 個iOS 數據恢復工具

作為 iPhone、iPad 或 iPod 用戶&#xff0c;您可能普遍擔心自己可能會丟失存儲在珍貴 iOS 設備中的所有寶貴數據。數據丟失的原因多種多樣&#xff0c;這里列出了一些常見原因&#xff1a; 1. iOS 軟件更新 2. 恢復出廠設置 3. 越獄 4. 誤操作刪除數據 5. iOS 設備崩潰 …

C++筆記(五)--- 虛函數(virtual)

目錄 虛函數介紹 虛函數、覆蓋和重載區別 虛函數介紹 C的虛函數是多態性的表現 1.構造函數不能為虛函數2.子類繼承時虛函數仍為虛函數3.虛函數類外實現時&#xff0c;不需要加virtual4.有虛函數的類&#xff0c;析構函數一定要寫成虛函數&#xff08;否則可能會造成內存泄漏&…

【代碼隨想錄python筆記整理】第十六課 · 出現頻率最高的字母

前言:本筆記僅僅只是對內容的整理和自行消化,并不是完整內容,如有侵權,聯系立刪。 一、哈希表初步 在之前的學習中,我們使用數組、字符串、鏈表等等,假如需要找到某個節點,則都要從頭開始,逐一比較,直到找到為止。為了能夠直接通過要查找的記錄找到其存儲位置,我們選…

設備像素、css像素、設備獨立像素、dpr、ppi 之間的區別

設備像素、CSS 像素、設備獨立像素 (DIP)、設備像素比 (DPR) 和每英寸像素密度 (PPI) 是與屏幕分辨率和顯示質量相關的概念。它們之間的區別如下&#xff1a; 設備像素&#xff1a;設備像素是物理屏幕上的最小可見單元&#xff0c;用于實際渲染圖像或文本。它表示硬件像素點的數…

、JMETER與它的組件們

os進程取樣器 這個取樣器可以讓jmeter直接調用python寫的測試數據 這樣就可以調用python寫的測試數據給到jmeter進行調用 注意&#xff1a;1建議python返回轉json格式dumps一下&#xff1b;2py文件中需要把結果打印出來&#xff0c;可以不用函數直接編寫 傳到jmeter之后可以用…

你真的了解C語言中的【柔性數組】嗎~

柔性數組 1. 什么是柔性數組2. 柔性數組的特點3. 柔性數組的使用4. 柔性數組的優勢 1. 什么是柔性數組 也許你從來沒有聽說過柔性數組這個概念&#xff0c;但是它確實是存在的。 C99中&#xff0c;結構體中的最后?個元素允許是未知大小的數組&#xff0c;這就叫做柔性數組成員…

MyBatis 學習(五)之 高級映射

目錄 1 association 和 collection 介紹 2 案例分析 3 一對一關聯和一對多關聯 4 參考文檔 1 association 和 collection 介紹 在之前的 SQL 映射文件中提及了 resultMap 元素的 association 和 collection 標簽&#xff0c;這兩個標簽是用來關聯查詢的&#xff0c;它們的屬…

算法--時空復雜度分析以及各個數據量對應的可使用的算法(C++;1s內)

這里寫目錄標題 由數據范圍反推算法時間復雜度以及算法內容分析時間復雜度看循環實例1實例2 固定時間復雜度快排和歸并排序二分高精度算法雙指針算法單鏈表插入刪除操作棧和隊列的操作單調棧和單調隊列KMPTire并查集堆哈希表BFS、DFS圖的深度優先、寬度優先遍歷dijkstra算法樸素…