java 查找算法

一、順序查找java

  1. public class OrderSearch {  
  2.     /**順序查找平均時間複雜度 O(n) 
  3.      * @param searchKey 要查找的值 
  4.      * @param array 數組(從這個數組中查找) 
  5.      * @return  查找結果(數組的下標位置) 
  6.      */  
  7.     public static int orderSearch(int searchKey,int... array){  
  8.         for(int i=0;i<array.length;i++){  
  9.             if(array[i]==searchKey){  
  10.                 return i;  
  11.             }  
  12.         }  
  13.         return -1;  
  14.           
  15.     }  
  16.     /**測試查找結果 
  17.      * @param args 
  18.      */  
  19.     public static void main(String[] args) {  
  20.           int[] test=new int[]{1,2,29,3,95,3,5,6,7,9,12};//升序序列  
  21.           int index=OrderSearch.orderSearch(95, test);  
  22.           System.out.println("查找到的位置 :"+ index);    
  23.     }  

 

二分查找mysql

算法思想:又叫折半查找,要求待查找的序列有序。每次取中間位置的值與待查關鍵字比較,若是中間位置的值比待查關鍵字大,則在前半部分循環這個查找的過程,若是中間位置的值比待查關鍵字小,則在後半部分循環這個查找的過程。直到查找到了爲止,不然序列中沒有待查的關鍵字。算法

 

實現:sql

 1.非遞歸代碼數據庫

複製代碼

public static int biSearch(int []array,int a){
        int lo=0;
        int hi=array.length-1;
        int mid;
        while(lo<=hi){
            mid=(lo+hi)/2;
            if(array[mid]==a){
                return mid+1;
            }else if(array[mid]<a){
                lo=mid+1;
            }else{
                hi=mid-1;
            }
        }
        return -1;
    }

複製代碼

 2.遞歸實現數組

複製代碼

public static int sort(int []array,int a,int lo,int hi){
        if(lo<=hi){
            int mid=(lo+hi)/2;
            if(a==array[mid]){
                return mid+1;
            }
            else if(a>array[mid]){
                return sort(array,a,mid+1,hi);
            }else{
                return sort(array,a,lo,mid-1);
            }
        }
        return -1;
    }

複製代碼

 時間複雜度爲 O(logN)   app

 

查找第一個元素出現的位置(元素容許重複)函數

複製代碼

public static int biSearch(int []array,int a){
        int n=array.length;
        int low=0;
        int hi=n-1;
        int mid=0;
        while(low<hi){
            mid=(low+hi)/2;
            if(array[mid]<a){
                low=mid+1;
            }else{
                hi=mid;
            }
        }
        if(array[low]!=a){
            return -1;
        }else{
            return low;
        }
    }

複製代碼

查詢元素最後一次出現的位置性能

複製代碼

public static int biSearch(int []array,int a){
        int n=array.length;
        int low=0;
        int hi=n-1;
        int mid=0;
        while(low<hi){
            mid=(low+hi+1)/2;
            if(array[mid]<=a){
                low=mid;
            }else{
                hi=mid-1;
            }
        }
    
        if(array[low]!=a){
            return -1;
        }else{
            return hi;
        }
    }

 

 有序表查找

1測試

2

3

4

5

6

7

8

/*  主函數  */

public class OrderTableSearch {

    public static void main(String[] args) {

        int [] a= {0,1,16,24,35,47,59,62,73,88,99};

        System.out.println(FibonacciSearch(a, 10, 88));

        System.out.println(InsertKeySearch(a, 10, 88));

        System.out.println(BinarySearch(a, 10, 88));

    }

1、折半查找 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

/* 折半查找  */

/* 輸出:9 */

static int BinarySearch(int [] a, int n, int key){

    int low, high, mid;

    low = 0;

    high = n;

    while(low <= high){

        mid = (low + high) / 2; /* 折半  */

        if (key < a[mid]){

            high = mid - 1;

        }

        else if (key > a[mid]){

            low = mid + 1;

        }

        else

            return mid;

    }

    return 0;

}

2、插值查找 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

/* 插值排序 */

/* 輸出:9 */

static int InsertKeySearch(int [] a, int n, int key){

    int low, high, mid;

    low = 0;

    high = n;

    while(low <= high){

        /* 插值查找的計算公式 */

        mid = low + (high - low)*

                (key - a[low])/(a[high] - a[low]);

        if (key < a[mid]){

            high = mid - 1;

        }

        else if (key > a[mid]){

            low = mid + 1;

        }

        else

            return mid;

    }

    return 0;

}

3、斐波那契查找 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

/* 斐波那契排序 */

/* 輸出:9 */

static int FibonacciSearch(int [] a, int n, int key){

    int [] F = {0,1,1,2,3,5,8,13,21,34};

    int low, high, mid, i, k;

    low = 1;

    high = n;

    k = 0;

    while (n > F[k]-1) /* 計算n位於斐波那契數列的位置 */

        k++;

     

    while (low <= high) {

        mid = low + F[k-1] -1;

        if (key < a[mid]){

            high = mid - 1;

            k = k - 1;

        }

        else if (key > a[mid]){

            low = mid + 1;

            k = k - 2;

        }

        else {

            if (mid <= n)

                return mid;

            else

                return n;

        }

    }

    return 0;

}

4、三種查找方法的比較

  平均性能:斐波那契>折半>插值,由於折半查找是加法與除法的運算,插值爲四則運算,斐波那契加減運算。

 

分塊查找

分塊查找是將順序查找與折半查找相結合的一種查找方法。

基本思想:
1. 首先將查找表分紅若干塊,在每一塊中數據元素的存放是任意的,但塊與塊之間必須是有序的(假設這種排序是按關鍵字值遞增的,也就是說在第一塊中任意一個數 據元素的關鍵字都小於第二塊中全部數據元素的關鍵字,第二塊中任意一個數據元素的關鍵字都小於第三塊中全部數據元素的關鍵字,依次類推);
2. 創建一個索引表,把每塊中最大的關鍵字值按塊的順序存放在一個輔助數組中,這個索引表也按升序排列;
3. 查找時先用給定的關鍵字值在索引表中查找,肯定知足條件的數據元素存放在哪一個塊中,查找方法既能夠是折半方法,也能夠是順序查找。
4. 再到相應的塊中順序查找,即可以獲得查找的結果。

案例分析:
一個查找表共有15個數據元素,現將它分紅三塊,每塊5個數據元素,各塊採用順序方式獨立存放在數組B一、B二、B3之中,輔助數組A的每一個元素 包含兩個域,關鍵字域中存放該塊中關鍵字的上確界(本塊中最大的關鍵字值),指針域存放該塊的數組始址,存放狀態如圖6-5所示。



若是要查找關鍵字爲66的數據元素,首先用66與A中各個元素的key比較,因爲66<74,肯定66在第三塊中(若是存在),而後按A[2].link 到數組B3中採用順序查找找到B3[2],查找成功。
/**
     * 分塊查找
     *
     * @param index 索引表,其中放的是各塊的最大值
     * @param st 順序表,
     * @param key 要查找的值
     * @param m 順序表中各塊的長度相等,爲m
     * @return
     */
  private int BlockSearch(int[ ] index, int[ ] st, int key, int m)
    {
          //  在序列st數組中,用分塊查找方法查找關鍵字爲key的記錄
         // 1.在index[ ] 中折半查找,肯定要查找的key屬於哪一個塊中 
          int i = partSearch(index, key);            
          if(i >= 0)
          {
              int j = i > 0 ? i * m : i;
              int len = (i + 1) * m;
              // 在肯定的塊中用順序查找方法查找key
              for(int k = j; k < len; k++) 
              {
                  if(key == st[k])
                  {
                      System.out.println("查詢成功");
                      return k;
                  }
              }
           }
          System.out.println("查找失敗");
          return -1;
    }
   
    public int partSearchs(int[] data, int tmpData)
    {
        int mid;
        int low = 0;
        int high = data.length - 1;
        while(low <= high)
        {
            mid = (low + high) / 2;     // 中間位置
            if(tmpData == data[mid])
            {
                return mid;            
            }
            else if(tmpData < data[mid])    
            {
                high = mid - 1;
            }
            else
            {
                low = mid + 1;
                return low;
            }
        }
        return -1;                // 沒有查找到
  }

優勢:
  ①在表中插入或刪除一個記錄時,只要找到該記錄所屬的塊,就在該塊內進行插入和刪除運算。
 ②因塊內記錄的存放是任意的,因此插入或刪除比較容易,無須移動大量記錄。
  分塊查找的主要代價是增長一個輔助數組的存儲空間和將初始表分塊排序的運算。
分塊查找算法的效率介於順序查找和二分查找之間。
若表中有10000個結點,則應把它分紅100個塊,每塊中含100個結點。用順序查找肯定塊,分塊查找平均須要作100次比較,而順序查找平均需作5000次比較,二分查找最多需14次比較。

分塊查找(索引順序查找)

它是順序查的的一種改進方法。在此查找法中,除自己外,尚需創建一個"索引表"。索引表裏有m個記錄,每一個索引n個元素,m*n等於數組的長度。其中包括兩項內容:關鍵字(其值爲該子表最大關鍵字)和指針(指示表第一個記錄在表中的位置)

過程分兩步進行:1.先用二分法查找索引表,肯定要找的記錄在哪一塊; 2.而後再在相應塊用順序查找找到目標記錄。分塊查找又稱爲索引順序查找。

使用了二分查找法和順序查找法,因此其時間複雜度應爲兩者之合。即:O(log(2m))+O(n)=O(log(2m)+n)=O(log(2m)+length/m)

 

哈希查找

哈希查找是經過計算數據元素的存儲地址進行查找的一種方法。O(1)的查找,即所謂的秒殺。哈希查找的本質是先將數據映射成它的哈希值。哈希查找的核心是構造一個哈希函數,它將原來直觀、整潔的數據映射爲看上去彷佛是隨機的一些整數。

哈希查找的操做步驟:

1)       用給定的哈希函數構造哈希表;

2)       根據選擇的衝突處理方法解決地址衝突;

3)       在哈希表的基礎上執行哈希查找。

創建哈希表操做步驟:

1)       step1 取數據元素的關鍵字key,計算其哈希函數值(地址)。若該地址對應的存儲空間尚未被佔用,則將該元素存入;不然執行step2解決衝突。

2)       step2 根據選擇的衝突處理方法,計算關鍵字key的下一個存儲地址。若下一個存儲地址仍被佔用,則繼續執行step2,直到找到能用的存儲地址爲止。

哈希查找步驟爲:

1)       Step1 對給定k值,計算哈希地址 Di=H(k);若HST爲空,則查找失敗;若HST=k,則查找成功;不然,執行step2(處理衝突)。

2)       Step2 重複計算處理衝突的下一個存儲地址 Dk=R(Dk-1),直到HST[Dk]爲空,或HST[Dk]=k爲止。若HST[Dk]=K,則查找成功,不然查找失敗。

 

好比說:」5「是一個要保存的數,而後我丟給哈希函數,哈希函數給我返回一個」2",那麼此時的」5「和「2」就創建一種對應關係,這種關係就是所謂的「哈希關係」,在實際應用中也就造成了」2「是key,」5「是value。

那麼有的朋友就會問如何作哈希,首先作哈希必需要遵照兩點原則:

①: key儘量的分散,也就是我丟一個「6」和「5」給你,你都返回一個「2」,那麼這樣的哈希函數不盡完美。

②:哈希函數儘量的簡單,也就是說丟一個「6」給你,你哈希函數要搞1小時才能給我,這樣也是很差的。

其實經常使用的作哈希的手法有「五種」:

第一種:」直接定址法「。

很容易理解,key=Value+C;這個「C"是常量。Value+C其實就是一個簡單的哈希函數。

第二種:「除法取餘法」。

很容易理解, key=value%C;解釋同上。

第三種:「數字分析法」。

這種蠻有意思,好比有一組value1=112233,value2=112633,value3=119033,

針對這樣的數咱們分析數中間兩個數比較波動,其餘數不變。那麼咱們取key的值就能夠是

key1=22,key2=26,key3=90。

第四種:「平方取中法」。此處忽略,見名識意。

第五種:「摺疊法」。

這種蠻有意思,好比value=135790,要求key是2位數的散列值。那麼咱們將value變爲13+57+90=160,而後去掉高位「1」,此時key=60,哈哈,這就是他們的哈希關係,這樣作的目的就是key與每一位value都相關,來作到「散列地址」儘量分散的目地。

影響哈希查找效率的一個重要因素是哈希函數自己。當兩個不一樣的數據元素的哈希值相同時,就會發生衝突。爲減小發生衝突的可能性,哈希函數應該將數據儘量分散地映射到哈希表的每個表項中。

解決衝突的方法有如下兩種:  

(1)   開放地址法  

若是兩個數據元素的哈希值相同,則在哈希表中爲後插入的數據元素另外選擇一個表項。當程序查找哈希表時,若是沒有在第一個對應的哈希表項中找到符合查找要求的數據元素,程序就會繼續日後查找,直到找到一個符合查找要求的數據元素,或者遇到一個空的表項。  

(2)   鏈地址法

將哈希值相同的數據元素存放在一個鏈表中,在查找哈希表的過程當中,當查找到這個鏈表時,必須採用線性查找方法。

 

實現哈希函數爲「除法取餘法」,解決衝突爲「開放地址線性探測法」,代碼以下:

 

[java] view plain copy

 

  1. public class HashSearch {  
  2.   
  3.     public static void main(String[] args) {  
  4.         //「除法取餘法」  
  5.         int hashLength = 13;  
  6.   
  7.         int [] array  = { 13, 29, 27, 28, 26, 30, 38 };  
  8.   
  9.         //哈希表長度  
  10.         int[] hash = new int[hashLength];  
  11.         //建立hash  
  12.         for (int i = 0; i < array.length; i++)  
  13.         {  
  14.             insertHash(hash, hashLength, array[i]);  
  15.         }  
  16.           
  17.         int result = searchHash(hash,hashLength, 29);  
  18.   
  19.         if (result != -1)  
  20.             System.out.println("已經在數組中找到,索引位置爲:" + result);  
  21.         else  
  22.             System.out.println("沒有此原始");  
  23.     }  
  24.   
  25.     /**** 
  26.      * Hash表檢索數據 
  27.      *  
  28.      * @param hash 
  29.      * @param hashLength 
  30.      * @param key 
  31.      * @return 
  32.      */  
  33.     public static int searchHash(int[] hash, int hashLength, int key) {  
  34.         // 哈希函數  
  35.         int hashAddress = key % hashLength;  
  36.   
  37.         // 指定hashAdrress對應值存在但不是關鍵值,則用開放尋址法解決  
  38.         while (hash[hashAddress] != 0 && hash[hashAddress] != key) {  
  39.             hashAddress = (++hashAddress) % hashLength;  
  40.         }  
  41.   
  42.         // 查找到了開放單元,表示查找失敗  
  43.         if (hash[hashAddress] == 0)  
  44.             return -1;  
  45.         return hashAddress;  
  46.   
  47.     }  
  48.   
  49.     /*** 
  50.      * 數據插入Hash表 
  51.      *  
  52.      * @param hash 哈希表 
  53.      * @param hashLength 
  54.      * @param data 
  55.      */  
  56.     public static void insertHash(int[] hash, int hashLength, int data) {  
  57.         // 哈希函數  
  58.         int hashAddress = data % hashLength;  
  59.   
  60.         // 若是key存在,則說明已經被別人佔用,此時必須解決衝突  
  61.         while (hash[hashAddress] != 0) {  
  62.             // 用開放尋址法找到  
  63.             hashAddress = (++hashAddress) % hashLength;  
  64.         }  
  65.   
  66.         // 將data存入字典中  
  67.         hash[hashAddress] = data;  
  68.     }  
  69. }  
  70.   
  71. 運行結果:  
  72. 已經在數組中找到,索引位置爲:3 

 

索引查找是在索引表和主表(即線性表的索引存儲結構)上進行的查找。

索引查找的過程是:

1)       首先根據給定的索引值K1,在索引表上查找出索引值等於KI的索引項,以肯定對應予表在主表中的開始位置和長度,

2)       而後再根據給定的關鍵字K2,茬對應的子表中查找出關鍵字等於K2的元素(結點)。對索引表或子表進行查找時,若表是順序存儲的有序表,則既可進行順序查找,也可進行二分查找,不然只能進行順序查找。

 

一提到「索引」,估計你們第一反應就是「數據庫索引」,對的,其實主鍵創建「索引」,就是方便咱們在海量數據中查找。

 

實現索引查找時常使用的三個術語:

1)       主表:這個很簡單,要查找的對象。

2)       索引項:通常咱們會用函數將一個主表劃分紅幾個子表,每一個子表創建一個索引,這個索引叫作索引項。

3)       索引表:索引項的集合也就是索引表。

 

通常「索引項」包含三種內容:index,start,length

第一: index,也就是索引指向主表的關鍵字。

第二:start,也就是index在主表中的位置。

第三:length, 也就是子表的區間長度。

 

代碼實現:

 

[java] view plain copy

 

  1. public class IndexSearch {  
  2.   
  3.     // 主表  
  4.     static int[] students = { 101, 102, 103, 104, 105, 0, 0, 0, 0, 0, 201, 202,  
  5.             203, 204, 0, 0, 0, 0, 0, 0, 301, 302, 303, 0, 0, 0, 0, 0, 0, 0 };  
  6.     // 索引表  
  7.     static IndexItem[] indexItem = { new IndexItem(1, 0, 5),  
  8.             new IndexItem(2, 10, 4), new IndexItem(3, 20, 3), };  
  9.   
  10.     // 查找數據  
  11.     public static int indexSearch(int key) {  
  12.         IndexItem item = null;  
  13.   
  14.         // 創建索引規則  
  15.         int index = key / 100;  
  16.   
  17.         // 首先去索引找  
  18.         for (int i = 0; i < indexItem.length; i++) {  
  19.             if (indexItem[i].index == index) {  
  20.                 item = new IndexItem(index, indexItem[i].start,  
  21.                         indexItem[i].length);  
  22.                 break;  
  23.             }  
  24.         }  
  25.   
  26.         // 若是item爲null,則說明在索引中查找失敗  
  27.         if (item == null)  
  28.             return -1;  
  29.   
  30.         for (int i = item.start; i < item.start + item.length; i++) {  
  31.             if (students[i] == key) {  
  32.                 return i;  
  33.             }  
  34.         }  
  35.         return -1;  
  36.     }  
  37.   
  38.     // / 插入數據  
  39.     public static int insert(int key) {  
  40.         IndexItem item = null;  
  41.         // 創建索引規則  
  42.         int index = key / 100;  
  43.         int i = 0;  
  44.         for (i = 0; i < indexItem.length; i++) {  
  45.             // 獲取到了索引  
  46.             if (indexItem[i].index == index) {  
  47.                 item = new IndexItem(index, indexItem[i].start,  
  48.                         indexItem[i].length);  
  49.                 break;  
  50.             }  
  51.         }  
  52.         if (item == null)  
  53.             return -1;  
  54.         // 更新主表  
  55.         students[item.start + item.length] = key;  
  56.         // 更新索引表  
  57.         indexItem[i].length++;  
  58.         return 1;  
  59.     }  
  60.   
  61.     public static void main(String[] args) {  
  62.         int value = 205;  
  63.         // 將205插入集合中,過索引  
  64.         int index = insert(value);  
  65.         insert(308);  
  66.   
  67.         // 若是插入成功,獲取205元素所在的位置  
  68.         if (index == 1) {  
  69.             System.out.println("\n插入後數據:" + Arrays.toString(students));  
  70.             System.out.println("\n數據元素:205在數組中的位置爲 " + indexSearch(205) + "位");  
  71.         }  
  72.   
  73.     }  
  74.   
  75. }  
  76.   
  77. // 索引項實體  
  78. class IndexItem {  
  79.     // 對應主表的值  
  80.     public int index;  
  81.     // 主表記錄區間段的開始位置  
  82.     public int start;  
  83.     // 主表記錄區間段的長度  
  84.     public int length;  
  85.   
  86.     public IndexItem() {  
  87.     }  
  88.   
  89.     public IndexItem(int index, int start, int length) {  
  90.         this.index = index;  
  91.         this.start = start;  
  92.         this.length = length;  
  93.     }  
  94. }  
  95.   
  96. 運行結果:  
  97. 原數據爲:[101, 102, 103, 104, 105, 0, 0, 0, 0, 0, 201, 202, 203, 204, 0, 0, 0, 0, 0, 0, 301, 302, 303, 0, 0, 0, 0, 0, 0, 0]  
  98.   
  99. 插入後數據:[101, 102, 103, 104, 105, 0, 0, 0, 0, 0, 201, 202, 203, 204, 205, 0, 0, 0, 0, 0, 301, 302, 303, 308, 0, 0, 0, 0, 0, 0]  
  100.   
  101. 數據元素:205在數組中的位置爲 14位  

時間複雜度爲O(1);

相關文章
相關標籤/搜索