<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      算法——二分法查找

      摘要

      二分法查找算法是一種在有序數組中查找特定元素的搜索算法。首先,梳理二分查找算法實現原理;其次,提供二分查找算法的三種不同實現;最后,分析該算法的局限性。

      前言

      ??在大學上算法分析課的時候,老師就說二分查找算法是一種效率較高的、適用于數據量較大序列的搜索算法,此算法基于順序存儲結構的線性表,且要求序列中元素按關鍵字有序排列,升序和降序都可以。

      ??二分法的時間復雜度是O(logn),所以在算法中,比O(n)更優的時間復雜度幾乎只能是O(logn)的二分法。根據時間復雜度來倒推算法也是面試中的常用策略:題目中若要求算法的時間復雜度是O(logn),那么這個算法基本上就是非二分法莫屬。故本文淺析其三種實現方法,使大家對它有一個更深刻的認知。

      ??在分析二分查找算法之前,我們先梳理計算機中有哪些數據結構。常見的數據結構有數組(Array)、堆棧(Stack)、隊列(Queue)、鏈表(Linked List)、樹(Tree)、圖(Graph)、堆(Heap)、散列表(Hash)。
      常見數據結構

      算法原理

      ??二分法又可以被稱為二分查找(binary search)或者折半檢索,其基本思想是對于一個有序數組,每次都通過與數組中間元素對比,將問題規模縮小為之前的一半,直到找到目標值。廣義的二分查找是將問題的規模盡可能的縮小到原有的一半。這里用到了數組這種數據結構,它屬于常見數據結構之一。

      ??二分查找的原理如下:假設待搜索序列是按照升序排列的,則

      1. 如果序列為空,那么就返回-1,并退出算法;這表示查找不到目標值。

      2. 如果序列不為空,則將它的中間元素與目標值進行比較,看它們是否相等。

      3. 如果相等,則查找成功,返回該中間元素的索引并退出。

      4. 如果中間元素大于目標值,那么就將序列的前半部分作為新的待搜索序列;這是因為后半部分的所有元素都大于目標值,故可以被排除。

      5. 如果中間元素小于目標值,那么就將當前序列的后半部分作為新的待搜索序列;這是因為前半部分的所有元素都小于目標值,故可以被排除。

      6. 對新的待搜索序列重新執行第1步的工作。

      ??二分查找之所以是一種效率較高的檢索方法,是因為在匹配失敗的時候,每次都能排除剩余元素中一半的元素。因此可能包含目標值的有效區間就收縮得很快,而不像順序查找那樣,每次僅能排除一個元素。

      基于折半檢索尋找一個數

      ??這是折半檢索算法最簡單的應用場景,可能也是大家最熟悉的,即在指定搜索范圍內搜索一個數,如果存在,返回其索引;否則,返回 -1。下面給出兩種非遞歸方式的折半檢索實現方案:

      import java.util.Arrays;
      
      /**
       * 二分法查找
       *
       * @author Wiener 使用二分法的前提是數組已經排序
       *
       */
      public class Demo {
      
          public static void main(String[] args) {
              int[] arr = { 3, 1, 8, 2, 9, 100,200, 33, 22, 11, 18, 14, 17, 15, 3 };
              // 使用Arrays.sort()排序
              Arrays.sort(arr);
              System.out.println(Arrays.toString(arr));
              // 返回結果
              //int index = binarySearch(arr, 99);
              int index = binarySearch_2(arr, 11);
              System.out.println("index=" + index);
          }
      
          /**
           * 二分法查找一返回下標
           * @param arr 數組
           * @param key 待匹配的值,看數組中是否存在
           * @return key 在數組中的下標,如果是-1,就說明數組中不存在此元素
           */
          public static int binarySearch(int[] arr, int key) {
              int min = 0; // 最小的下標
              int max = arr.length - 1;// 最大的下標
              int mid = (min + max) / 2;// 中間的下標
              while (arr[mid] != key) { // 用于縮小查找范圍
                  if (key > arr[mid]) { //比中間數還大
                      min = mid + 1;   //使最小的下標=中間下標+1
                  } else if (key < arr[mid]) {//比中間數還小
                      max = mid - 1;   //使最大的下標=中間下標-1
                  }
                  if(max<min){
                      return -1;
                  }
                  mid=(min+max)/2; //再次計算中間下標
              }
      
              return mid;
          }
          /*
           * 二分法查找一如果返回的下標是-1,就說明沒有
           */
          public static int binarySearch_2(int[] arr, int key) {
              int min = 0; // 最小的下標
              int max = arr.length - 1;// 最大的下標
              int mid = min + (max - min) >> 1;// 中間數下標,等價于(min + max) / 2
              while(min<=max){
                  if(key>arr[mid]){
                      min=mid+1;
                  }else if(key<arr[mid]){
                      max=mid-1;
                  }else{
                      return mid;
                  }
                  mid=(min+max)/2;
              }
              //沒找到
              return -1;
          }
      }
      

      ??分析二分查找算法的一個技巧是:盡量避免出現 else,而是把所有情況用 else if 寫清楚,這樣可以清晰地展現所有細節。

      ??溫馨提示,退出循環的條件之所以是min<=max,而不是min<max,是因為 max = arr.length - 1

      ??關于mid如何取值,實際上,mid=(min + max) / 2 這種寫法是有缺陷的。因為如果min和max比較大的話,兩者之和就有可能會溢出。改進的地方是將mid的計算方式寫成min + (max - min) >> 1。因為相比除法運算來說,計算機處理位運算性能提升很多。

      二分法的遞歸實現

      ??實際上二分查找除了以循環遍歷來實現,還可以用遞歸來實現。代碼如下:

          /**
           * 遞歸思想實現二分查找
           *
           * @param orderedArray 有序數組
           * @param low      數組最小值下標
           * @param high     數組最大值下標
           * @param key      查找元素
           * @return 查找元素不存在返回-1,存在返回對應的數組下標
           */
          public static int internallyBinarySearch(int orderedArray[], int low, int high, int key) {
              int mid = (high - low) / 2 + low;
              if (orderedArray[mid] == key) {
                  return mid;
              }
              if (low >= high) {
                  return -1;
              } else if (key > orderedArray[mid]) {
                  return internallyBinarySearch(orderedArray, mid + 1, high, key);
              } else {
                  return internallyBinarySearch(orderedArray, low, mid - 1, key);
              }
          }
      

      應用場景的局限性

        
      ??二分查找的時間復雜度是 O(logn),查找數據的效率非常高。不過,并不是什么情況下都可以用二分查找,它的應用場景是有很大局限性的。那什么情況下適合用二分查找,什么情況下不適合呢?

      ??首先,二分查找依賴的是順序表結構,簡單點說就是數組。二分查找只能用在數據是通過順序表來存儲的數據結構上。如果你的數據是通過
      鏈表等其它數據結構存儲的,則無法實現二分查找。

      ??其次,二分查找針對的是有序序列。二分查找對這一點的要求比較苛刻,數據必須是有序的。如果數據沒有排序,我們需要先排序,排序的時間復雜度最低是 O(nlogn)。所以,我們如果針對的是一組靜態數據,而且沒有頻繁地插入、刪除,那么可以進行一次排序,多次二分查找。這樣排序的成本可被均攤,二分查找的邊際成本就會比較低。

      ??但是,如果我們的數序列有頻繁的插入和刪除操作,要想用二分查找,要么每次插入、刪除操作之后保證數據仍然有序,要么在每次二分查找之前都先進行排序。針對這種動態數據集合,無論哪種方法,維護有序的成本都是很高的。

      ??所以,二分查找只能用在插入、刪除操作不頻繁,一次排序多次查找的場景中。針對動態變化的數據集合,二分查找將不再適用。

      ??再次,數據量太小不適合二分查找。數據量很小時,順序遍歷就足夠了,完全沒有必要用二分查找。只有數據量比較大的時候,二分查找的優勢才會比較明顯。

      ??有一個例外。如果數據之間的比較操作非常耗時,不管數據量大小,都推薦使用二分查找。比如,數組中存儲的都是長度超過 300 的字符串,如此長的兩個字符串之間比對大小,就會非常耗時。我們需要盡可能地減少比較次數,而比較次數的減少會大大提高性能,這個時候二分查找就比順序遍歷更有優勢。

      ??最后,數據量太大也不適合二分查找。二分查找的底層需要依賴數組這種數據結構,而數組為了支持隨機訪問的特性,要求內存空間連續,對內存的要求比較苛刻。比如,我們有 1GB 大小的數據,如果希望用數組來存儲,那就需要 1GB 的連續內存空間,但是我們的內存都是離散的,可能電腦沒有這么多的內存。

      ??注意這里的“連續”二字,也就是說,即便有 2GB 的內存空間剩余,但是如果這剩余的 2GB 內存空間都是零散的,沒有連續的 1GB 大小的內存空間,那照樣無法申請一個 1GB 大小的內存空間,那照樣無法申請一個 1GB 大小的數組。而我們的二分查找是作用在數組這種數據結構之上的,所以太大的數據用數組存儲就比較吃力了,也就不能用二分查找了。

      如何在 1000 萬個整數中快速查找某個整數?

      ??假設內存限制是 100MB,每個數據大小是 8 字節,最簡單的辦法就是將數據存儲在數組中,內存占用差不多是 10000000/1024/1024 ≈ 76.3MB,符合內存的限制。我們可以先對這 1000 萬數據進行排序,然后再利用二分查找算法,就可以快速地查找想要的數據了。

      ??歡迎點贊閱讀,一同學習交流;若有疑問,請在文章下方留下你的神評妙論!

      Reference

      https://zhuanlan.zhihu.com/p/65610304
      https://blog.csdn.net/weixin_41923658/article/details/86090645
      http://www.rzrgm.cn/gshao/p/13489436.html#_label3

      posted @ 2021-07-31 13:58  樓蘭胡楊  閱讀(2392)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 国产精品久久蜜臀av| 亚洲国产在一区二区三区| 亚洲春色在线视频| 日本丰满白嫩大屁股ass| 夜夜影院未满十八勿进| 一卡2卡三卡4卡免费网站| 通山县| 日本高清不卡一区二区三| 久久精品岛国AV一区二区无码| 夜夜爽日日澡人人添| 九九热在线精品视频观看| 亚洲一区二区三区18禁| 曰批免费视频播放免费| 99久久久国产精品消防器材| 国产精品多p对白交换绿帽| 精品国产这么小也不放过| 天堂影院一区二区三区四区| 国产欧美精品一区二区三区四区| 欧美牲交a欧美牲交aⅴ免费真| 国产97人人超碰CAO蜜芽PROM| 中年国产丰满熟女乱子正在播放 | 午夜久久一区二区狠狠干| av综合网男人的天堂| 国产毛片三区二区一区| japanese无码中文字幕| 性欧美三级在线观看| 四虎国产精品永久在线| 在线a级毛片无码免费真人| 色综合久久人妻精品日韩| 日本强好片久久久久久aaa| 亚洲精品一区二区三区不| 亚洲VA中文字幕无码久久不卡| 国产线播放免费人成视频播放| 亚洲一区二区三区啪啪| 黔东| 色爱av综合网国产精品| 丰满老熟妇好大bbbbb| 亚洲日韩性欧美中文字幕| 91中文字幕在线一区| 精品一区二区不卡免费| 久久国产精品色av免费看|