常用查找算法(順序、二分、插值、分塊、斐波那契)

順序查找

基本思想

  • 屬於線性查找和無序查找,從一端開始順序掃描,直到找到與目標值value相等的元素。
  • 這是最基本的查找方法,也是時間複雜度最高的查找算法。
  • 在數據過多時,這種方法並不適用。

代碼實現

//第一種:順序查找
    public Type SequenceSearch(Type[] list,Type t)
    {
        for(Type temp : list)
        {
            if(temp.equals(t))
                return temp;
        }
        return null;
    }

分塊查找

基本思想

  • 屬於順序查找的改進方法,又叫索引順序查找。
  • 將n個元素分成m塊(m<=n),每個塊中元素可以沒有順序,但是m個塊之間是有序排列,所以特別適合於節點動態變化的情況
  • 分塊查找的速度雖然不如二分查找算法,但比順序查找算法快得多,同時又不需要對全部節點進行排序。當節點很多且塊數很大時,對索引表可以採用折半查找,這樣能夠進一步提高查找的速度。
  • 那麼索引表的構成就是每個塊中的最大元素。
  • 查找方式是先對索引表進行二分或順序查找,選出目標值應該所在的塊,然後在塊內進行順序查找。

二分查找

基本思想

  • 屬於有序查找算法,也叫折半查找,就是將數組每次選取一半進行查找,怎麼選取一半就需要讓中間值與目標值value進行比較,因爲有序,所以中間值小於目標值則選取後半部分,大於目標值則選取前半部分,依此類推,直到找出與目標值相等的元素,否則返回-1或null。
  • 這種方法有效的縮減查找次數和查找範圍,適用於數據量比較大的有序表。
  • 因爲前提是有序表,所以對於插入刪除等操作過多的數據集並不適用,因爲在排序算法上浪費的時間會比較多。
  • 一般的時間複雜度是O(log2n)

代碼實現

//第二種:二分查找,這裏用int類型數組舉例,找到中間元素的索引
    //非遞歸
    public int BinarySearch(int[] list,int value)
    {
        int low = 0,high = list.length-1,mid;
        while (low<=high)
        {
            mid = (low+high)/2;
            if(list[mid] == value)//如果是尋找String,就用equal
                return mid;
            if(list[mid]>value)
                high = mid-1;
            if(list[mid]<value)
                low=mid+1;
        }
        return -1;
    }
    //遞歸
    public int BinarySearch(int[] list,int value,int low,int high)
    {
        int mid = (low+high)/2;
        if(list[mid] == value)//如果是尋找String,就用equal
            return mid;
        if(list[mid]>value)
            return BinarySearch(list,value,low,mid-1);
        if(list[mid]<value)
            return BinarySearch(list,value,mid+1,high);
        else
            return -1;
    }

插值查找

基本思想

  • 屬於二分查找的改進版,二分查找一直重複一半一半的操作,這種操作比較固定,並不會根據目標值的大小進行自適應分段和選擇,而插值查找可以根據目標值value進行自適應。
  • 下面是百度詞條對插值的解釋:插值類似於平常查英文字典的方法,在查一個以字母C開頭的英文單詞時,決不會用二分查找,從字典的中間一頁開始,因爲知道它的大概位置是在字典的較前面的部分,因此可以從前面的某處查起。
  • 既然是二分查找的改進版,那麼就要找關鍵點進行改進,二分是取1/2的有序表進行查找,那麼mid就是關鍵點,二分中mid=(low+high)/2,可以轉化成mid=low+(high-low)/2,所以相當於(high-low)/2中的1/2就是所分的比例,那麼可以對mid進行改進,mid=low+low+(value-list[low])/(list[high]-list[low])*(high-low),(value-list[low])/(list[high]-list[low])就是所分的比例
  • 根據目標值在整個有序表中所處的位置,讓mid的變化更靠近目標值value,這樣也就間接地減少了比較次數。
  • 這種方法適用於關鍵字分佈均勻的有序表。
  • 複雜度爲O(log2(log2n))

代碼實現

//第三種:插值查找,用int類型數組舉例
    public int InsertSearch(int[] list,int value,int low,int high)
    {
        int mid = low+(value-list[low])/(list[high]-list[low])*(high-low);
        if(list[mid] == value)//如果是尋找String,就用equal
            return mid;
        if(list[mid]>value)
            return InsertSearch(list,value,low,mid-1);
        if(list[mid]<value)
            return InsertSearch(list,value,mid+1,high);
        else
            return -1;
    }

斐波那契查找

基本思想

  • 斐波那契數列與0.618有着奇妙的關聯,隨着斐波那契數列的遞增,前後兩個數的比值會越來越接近0.618,所以可以將黃金比例運用到查找中。
  • 百度詞條:斐波那契搜索斐波那契搜索就是在二分查找的基礎上根據斐波那契數列進行分割的。在斐波那契數列找一個等於略大於查找表中元素個數的數F(n),將原查找表擴展爲長度爲F(n)(如果要補充元素,則補充重複最後一個元素,直到滿足F[n]個元素),完成後進行斐波那契分割,即F[n]個元素分割爲前半部分F[n-1]個元素,後半部分F[n-2]個元素,找出要查找的元素在那一部分並遞歸,直到找到。
  • 這個方法比較重要,所以百度詞條上講的很清楚!

代碼實現

package Searching;

import java.util.Arrays;

/**
 * @Author: 胡奇夫
 * @QQ: 1579328766
 * @CreateTime: 2020-05-17-14-05
 * @Descirption: 斐波那契查找算法
 */
public class Fibonaccialo {
    public static void main(String[] args) {
        int arr[] = {2,4,9,10,13,15,16,19,34};
        System.out.println(FibonacciSearch(arr,34)+1);
    }

    //創建斐波那契數列
    public static int[] Fibonacci(int n) {
        int[] FibonacciList = new int[n];
        FibonacciList[0] = 0;
        FibonacciList[1] = 1;
        for (int i = 2; i < n; i++) {
            FibonacciList[i] = FibonacciList[i - 1] + FibonacciList[i -2];
        }
        return FibonacciList;
    }

    //斐波那契查找,返回的是value在list中的索引值,所以在最後可以加一,爲了看出效果,我在上面打印的時候再加一
    public static int FibonacciSearch(int[] list,int value)
    {
        int low = 0;
        int high = list.length -1;
        int k = 0;//表示斐波那契分割的值
        int mid = 0;//存放黃金分割點的值
        int f[] = Fibonacci(20);//斐波那契數列
        //找k值
        while (high>f[k] - 1){
            k++;
        }
        //複製到新的數組
        int temp[] = Arrays.copyOf(list,f[k]);
        //得到f[k]的值可能會大於a的長度,將新數組的多餘的部分用數組中的最後一個數字填充
        for (int i = high+1; i <temp.length ; i++) {
            temp[i] = list[high];
        }
        //使用while循環,找到value的位置
        while (low<=high){//滿足這個條件就可以繼續找
            mid = low+f[k-1]-1;//找到的黃金分割點
            if(value<temp[mid]){
                high = mid - 1;
                k--;
            }else if(value>temp[mid]){
                low = mid + 1;
                k-=2;
            }else{
                if(mid<=high){
                    return mid;
                }else {
                    return high;
                }
            }
        }
        return -1;
    }

}

總結

  • 還剩下兩種非常重要的查找算法,就是樹表和哈希,這兩種我就單獨寫,ball ball大佬們不要嫌棄!
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章