【整理】七大查找算法 淺談算法和數據結構: 七 二叉查找樹 淺談算法和數據結構: 十一 哈希表

轉載地址:http://www.cnblogs.com/maybe2030/p/4715035.html
html

      查找是在大量的信息中尋找一個特定的信息元素,在計算機應用中,查找是經常使用的基本運算,例如編譯程序中符號表的查找。本文簡單歸納性的介紹了常見的七種查找算法,說是七種,其實二分查找、插值查找以及斐波那契查找均可以歸爲一類——插值查找。插值查找和斐波那契查找是在二分查找的基礎上的優化查找算法。樹表查找和哈希查找會在後續的博文中進行詳細介紹。java

  查找定義:根據給定的某個值,在查找表中肯定一個其關鍵字等於給定值的數據元素(或記錄)。node

  查找算法分類:
  1)靜態查找和動態查找;
    注:靜態或者動態都是針對查找表而言的。動態表指查找表中有刪除和插入操做的表。
  2)無序查找和有序查找。
    無序查找:被查找數列有序無序都可;
    有序查找:被查找數列必須爲有序數列。
  平均查找長度(Average Search Length,ASL): 需和指定key進行比較的關鍵字的個數的指望值,稱爲查找算法在查找成功時的平均查找長度。
  對於含有n個數據元素的查找表,查找成功的平均查找長度爲:ASL = Pi*Ci的和。
  Pi:查找表中第i個數據元素的機率。
  Ci:找到第i個數據元素時已經比較過的次數。

1. 順序查找

  說明:順序查找適合於存儲結構爲順序存儲或連接存儲的線性表。
  基本思想:順序查找也稱爲線形查找,屬於無序查找算法。從數據結構線形表的一端開始,順序掃描,依次將掃描到的結點關鍵字與給定值k相比較,若相等則表示查找成功;若掃描結束仍沒有找到關鍵字等於k的結點,表示查找失敗。
   複雜度分析:  
  查找成功時的平均查找長度爲:(假設每一個數據元素的機率相等) ASL = 1/n(1+2+3+…+n) = (n+1)/2 ;
  當查找不成功時,須要n+1次比較,時間複雜度爲O(n);
  因此,順序查找的時間複雜度爲O(n)。
  C++實現源碼:
<pre style="margin-top: 0px; margin-bottom: 0px; line-height: 22.5px; padding: 0px; white-space: pre-wrap; word-wrap: break-word; font-family: 'Courier New' !important;"><span style="margin: 0px; padding: 0px; color: rgb(0, 128, 0); line-height: 1.5 !important;">//</span><span style="margin: 0px; padding: 0px; color: rgb(0, 128, 0); line-height: 1.5 !important;">順序查找</span>
int SequenceSearch(int a[], int value, int n){ int i; for(i=0; i<n; i++) if(a[i]==value) return i; return -1;}
 
  

2. 二分查找

  說明:元素必須是有序的,若是是無序的則要先進行排序操做。mysql

  基本思想:也稱爲是折半查找,屬於有序查找算法。用給定值k先與中間結點的關鍵字比較,中間結點把線形表分紅兩個子表,若相等則查找成功;若不相等,再根據k與該中間結點關鍵字的比較結果肯定下一步查找哪一個子表,這樣遞歸進行,直到查找到或查找結束髮現表中沒有這樣的結點。ios

  複雜度分析:最壞狀況下,關鍵詞比較次數爲log2(n+1),且指望時間複雜度爲O(log2n)算法

  注:折半查找的前提條件是須要有序表順序存儲,對於靜態查找表,一次排序後再也不變化,折半查找能獲得不錯的效率。但對於須要頻繁執行插入或刪除操做的數據集來講,維護有序的排序會帶來不小的工做量,那就不建議使用。——《大話數據結構》sql

  C++實現源碼:數據庫

//二分查找(折半查找),版本1
int BinarySearch1(int a[], int value, int n)
{
    int low, high, mid;
    low = 0;
    high = n-1;
    while(low<=high)
    {
        mid = (low+high)/2;
        if(a[mid]==value)
            return mid;
        if(a[mid]>value)
            high = mid-1;
        if(a[mid]<value)
            low = mid+1;
    }
    return -1;
}

//二分查找,遞歸版本
int BinarySearch2(int a[], int value, int low, int high)
{
    int mid = low+(high-low)/2;
    if(a[mid]==value)
        return mid;
    if(a[mid]>value)
        return BinarySearch2(a, value, low, mid-1);
    if(a[mid]<value)
        return BinarySearch2(a, value, mid+1, high);
}

3. 插值查找

  在介紹插值查找以前,首先考慮一個新問題,爲何上述算法必定要是折半,而不是折四分之一或者折更多呢?
  打個比方,在英文字典裏面查「apple」,你下意識翻開字典是翻前面的書頁仍是後面的書頁呢?若是再讓你查「zoo」,你又怎麼查?很顯然,這裏你絕對不會是從中間開始查起,而是有必定目的的往前或日後翻。
  一樣的,好比要在取值範圍1 ~ 10000 之間 100 個元素從小到大均勻分佈的數組中查找5, 咱們天然會考慮從數組下標較小的開始查找。
  通過以上分析,折半查找這種查找方式,不是自適應的(也就是說是傻瓜式的)。二分查找中查找點計算以下:
  mid=(low+high)/2, 即mid=low+1/2*(high-low);
  經過類比,咱們能夠將查找的點改進爲以下:
  mid=low+(key-a[low])/(a[high]-a[low])*(high-low),
  也就是將上述的比例參數1/2改進爲自適應的,根據關鍵字在整個有序表中所處的位置,讓mid值的變化更靠近關鍵字key,這樣也就間接地減小了比較次數。
  基本思想:基於二分查找算法,將查找點的選擇改進爲自適應選擇,能夠提升查找效率。固然,差值查找也屬於有序查找。
  注: 對於表長較大,而關鍵字分佈又比較均勻的查找表來講,插值查找算法的平均性能比折半查找要好的多。反之,數組中若是分佈很是不均勻,那麼插值查找未必是很合適的選擇。
  複雜度分析:查找成功或者失敗的時間複雜度均爲O(log2(log2n))。
  C++實現源碼:
<pre style="margin-top: 0px; margin-bottom: 0px; line-height: 22.5px; padding: 0px; white-space: pre-wrap; word-wrap: break-word; font-family: 'Courier New' !important;"><span style="margin: 0px; padding: 0px; color: rgb(0, 128, 0); line-height: 1.5 !important;">//</span><span style="margin: 0px; padding: 0px; color: rgb(0, 128, 0); line-height: 1.5 !important;">插值查找</span>
int InsertionSearch(int a[], int value, int low, int high){ int mid = low+(value-a[low])/(a[high]-a[low])*(high-low); if(a[mid]==value) return mid; if(a[mid]>value) return InsertionSearch(a, value, low, mid-1); if(a[mid]<value) return InsertionSearch(a, value, mid+1, high);}
 
  

4. 斐波那契查找

  在介紹斐波那契查找算法以前,咱們先介紹一下很它緊密相連而且你們都熟知的一個概念——黃金分割。編程

  黃金比例又稱黃金分割,是指事物各部分間必定的數學比例關係,即將總體一分爲二,較大部分與較小部分之比等於總體與較大部分之比,其比值約爲1:0.618或1.618:1。數組

  0.618被公認爲最具備審美意義的比例數字,這個數值的做用不只僅體如今諸如繪畫、雕塑、音樂、建築等藝術領域,並且在管理、工程設計等方面也有着不可忽視的做用。所以被稱爲黃金分割。

  你們記不記得斐波那契數列:1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89…….(從第三個數開始,後邊每個數都是前兩個數的和)。而後咱們會發現,隨着斐波那契數列的遞增,先後兩個數的比值會愈來愈接近0.618,利用這個特性,咱們就能夠將黃金比例運用到查找技術中。

  基本思想:也是二分查找的一種提高算法,經過運用黃金比例的概念在數列中選擇查找點進行查找,提升查找效率。一樣地,斐波那契查找也屬於一種有序查找算 法。
   相對於折半查找,通常將待比較的key值與第mid=(low+high)/2位置的元素比較,比較結果分三種狀況:

  1)相等,mid位置的元素即爲所求

  2)>,low=mid+1;

     3)<,high=mid-1。

  斐波那契查找與折半查找很類似,他是根據斐波那契序列的特色對有序表進行分割的。他要求開始表中記錄的個數爲某個斐波那契數小1,及n=F(k)-1;

 開始將k值與第F(k-1)位置的記錄進行比較(及mid=low+F(k-1)-1),比較結果也分爲三種

  1)相等,mid位置的元素即爲所求

  2)>,low=mid+1,k-=2;

  說明:low=mid+1說明待查找的元素在[mid+1,high]範圍內,k-=2 說明範圍[mid+1,high]內的元素個數爲n-(F(k-1))= Fk-1-F(k-1)=Fk-F(k-1)-1=F(k-2)-1個,因此能夠遞歸的應用斐波那契查找。

  3)<,high=mid-1,k-=1。

  說明:low=mid+1說明待查找的元素在[low,mid-1]範圍內,k-=1 說明範圍[low,mid-1]內的元素個數爲F(k-1)-1個,因此能夠遞歸 的應用斐波那契查找。

  複雜度分析:最壞狀況下,時間複雜度爲O(log2n),且其指望複雜度也爲O(log2n )。

  C++實現源碼:

// 斐波那契查找.cpp 

#include "stdafx.h"
#include <memory>
#include  <iostream>
using namespace std;

const int max_size=20;//斐波那契數組的長度

/*構造一個斐波那契數組*/ 
void Fibonacci(int * F)
{
    F[0]=0;
    F[1]=1;
    for(int i=2;i<max_size;++i)
        F[i]=F[i-1]+F[i-2];
}

/*定義斐波那契查找法*/  
int FibonacciSearch(int *a, int n, int key)  //a爲要查找的數組,n爲要查找的數組長度,key爲要查找的關鍵字
{
  int low=0;
  int high=n-1;
  
  int F[max_size];
  Fibonacci(F);//構造一個斐波那契數組F 

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

  int  * temp;//將數組a擴展到F[k]-1的長度
  temp=new int [F[k]-1];
  memcpy(temp,a,n*sizeof(int));

  for(int i=n;i<F[k]-1;++i)
     temp[i]=a[n-1];
  
  while(low<=high)
  {
    int mid=low+F[k-1]-1;
    if(key<temp[mid])
    {
      high=mid-1;
      k-=1;
    }
    else if(key>temp[mid])
    {
     low=mid+1;
     k-=2;
    }
    else
    {
       if(mid<n)
           return mid; //若相等則說明mid即爲查找到的位置
       else
           return n-1; //若mid>=n則說明是擴展的數值,返回n-1
    }
  }  
  delete [] temp;
  return -1;
}

int main()
{
    int a[] = {0,16,24,35,47,59,62,73,88,99};
    int key=100;
    int index=FibonacciSearch(a,sizeof(a)/sizeof(int),key);
    cout<<key<<" is located at:"<<index;
    return 0;
}

5. 樹表查找

  5.1 最簡單的樹表查找算法——二叉樹查找算法。

  基本思想:二叉查找樹是先對待查找的數據進行生成樹,確保樹的左分支的值小於右分支的值,而後在就行和每一個節點的父節點比較大小,查找最適合的範圍。 這個算法的查找效率很高,可是若是使用這種查找方法要首先建立樹。 

  二叉查找樹(BinarySearch Tree,也叫二叉搜索樹,或稱二叉排序樹Binary Sort Tree)或者是一棵空樹,或者是具備下列性質的二叉樹:

  1)若任意節點的左子樹不空,則左子樹上全部結點的值均小於它的根結點的值;

  2)若任意節點的右子樹不空,則右子樹上全部結點的值均大於它的根結點的值;

  3)任意節點的左、右子樹也分別爲二叉查找樹。

  二叉查找樹性質對二叉查找樹進行中序遍歷,便可獲得有序的數列。

  不一樣形態的二叉查找樹以下圖所示:

   有關二叉查找樹的查找、插入、刪除等操做詳細講解,請移步淺談算法和數據結構: 七 二叉查找樹

  複雜度分析:它和二分查找同樣,插入和查找的時間複雜度均爲O(logn),可是在最壞的狀況下仍然會有O(n)的時間複雜度。緣由在於插入和刪除元素的時候,樹沒有保持平衡(好比,咱們查找上圖(b)中的「93」,咱們須要進行n次查找操做)。咱們追求的是在最壞的狀況下仍然有較好的時間複雜度,這就是平衡查找樹設計的初衷。

  下圖爲二叉樹查找和順序查找以及二分查找性能的對比圖:

 

  基於二叉查找樹進行優化,進而能夠獲得其餘的樹表查找算法,如平衡樹、紅黑樹等高效算法。

  5.2 平衡查找樹之2-3查找樹(2-3 Tree)

  2-3查找樹定義和二叉樹不同,2-3樹運行每一個節點保存1個或者兩個的值。對於普通的2節點(2-node),他保存1個key和左右兩個本身點。對應3節點(3-node),保存兩個Key,2-3查找樹的定義以下:

  1)要麼爲空,要麼:

  2)對於2節點,該節點保存一個key及對應value,以及兩個指向左右節點的節點,左節點也是一個2-3節點,全部的值都比key要小,右節點也是一個2-3節點,全部的值比key要大。

  3)對於3節點,該節點保存兩個key及對應value,以及三個指向左中右的節點。左節點也是一個2-3節點,全部的值均比兩個key中的最小的key還要小;中間節點也是一個2-3節點,中間節點的key值在兩個跟節點key值之間;右節點也是一個2-3節點,節點的全部key值比兩個key中的最大的key還要大。

Definition of 2-3 tree

  2-3查找樹的性質:

  1)若是中序遍歷2-3查找樹,就能夠獲得排好序的序列;

  2)在一個徹底平衡的2-3查找樹中,根節點到每個爲空節點的距離都相同。(這也是平衡樹中「平衡」一詞的概念,根節點到葉節點的最長距離對應於查找算法的最壞狀況,而平衡樹中根節點到葉節點的距離都同樣,最壞狀況也具備對數複雜度。)

  性質2)以下圖所示:

 

  複雜度分析:

  2-3樹的查找效率與樹的高度是息息相關的。

  • 在最壞的狀況下,也就是全部的節點都是2-node節點,查找效率爲lgN
  • 在最好的狀況下,全部的節點都是3-node節點,查找效率爲log3N約等於0.631lgN

  距離來講,對於1百萬個節點的2-3樹,樹的高度爲12-20之間,對於10億個節點的2-3樹,樹的高度爲18-30之間。

  對於插入來講,只須要常數次操做便可完成,由於他只須要修改與該節點關聯的節點便可,不須要檢查其餘節點,因此效率和查找相似。下面是2-3查找樹的效率:

analysis of 2-3 tree

 

  5.3 平衡查找樹之紅黑樹(Red-Black Tree)

  2-3查找樹能保證在插入元素以後能保持樹的平衡狀態,最壞狀況下即全部的子節點都是2-node,樹的高度爲lgn,從而保證了最壞狀況下的時間複雜度。可是2-3樹實現起來比較複雜,因而就有了一種簡單實現2-3樹的數據結構,即紅黑樹(Red-Black Tree)。

  基本思想:紅黑樹的思想就是對2-3查找樹進行編碼,尤爲是對2-3查找樹中的3-nodes節點添加額外的信息。紅黑樹中將節點之間的連接分爲兩種不一樣類型,紅色連接,他用來連接兩個2-nodes節點來表示一個3-nodes節點。黑色連接用來連接普通的2-3節點。特別的,使用紅色連接的兩個2-nodes來表示一個3-nodes節點,而且向左傾斜,即一個2-node是另外一個2-node的左子節點。這種作法的好處是查找的時候不用作任何修改,和普通的二叉查找樹相同。

Red black tree

  紅黑樹的定義:

  紅黑樹是一種具備紅色和黑色連接的平衡查找樹,同時知足:

  • 紅色節點向左傾斜
  • 一個節點不可能有兩個紅色連接
  • 整個樹徹底黑色平衡,即從根節點到因此葉子結點的路徑上,黑色連接的個數都相同。

  下圖能夠看到紅黑樹實際上是2-3樹的另一種表現形式:若是咱們將紅色的連線水平繪製,那麼他連接的兩個2-node節點就是2-3樹中的一個3-node節點了。

1-1 correspondence between 2-3 and LLRB

  紅黑樹的性質整個樹徹底黑色平衡,即從根節點到因此葉子結點的路徑上,黑色連接的個數都相同(2-3樹的第2)性質,從根節點到葉子節點的距離都相等)。

  複雜度分析:最壞的狀況就是,紅黑樹中除了最左側路徑所有是由3-node節點組成,即紅黑相間的路徑長度是全黑路徑長度的2倍。

  下圖是一個典型的紅黑樹,從中能夠看到最長的路徑(紅黑相間的路徑)是最短路徑的2倍:

a typic red black tree

  紅黑樹的平均高度大約爲logn。

  下圖是紅黑樹在各類狀況下的時間複雜度,能夠看出紅黑樹是2-3查找樹的一種實現,它能保證最壞狀況下仍然具備對數的時間複雜度。

  紅黑樹這種數據結構應用十分普遍,在多種編程語言中被用做符號表的實現,如:

  • Java中的java.util.TreeMap,java.util.TreeSet;
  • C++ STL中的:map,multimap,multiset;
  • .NET中的:SortedDictionary,SortedSet 等。

  5.4 B樹和B+樹(B Tree/B+ Tree)

  平衡查找樹中的2-3樹以及其實現紅黑樹。2-3樹種,一個節點最多有2個key,而紅黑樹則使用染色的方式來標識這兩個key。

  維基百科對B樹的定義爲「在計算機科學中,B樹(B-tree)是一種樹狀數據結構,它可以存儲數據、對其進行排序並容許以O(log n)的時間複雜度運行進行查找、順序讀取、插入和刪除的數據結構。B樹,歸納來講是一個節點能夠擁有多於2個子節點的二叉查找樹。與自平衡二叉查找樹不一樣,B樹爲系統最優化大塊數據的讀和寫操做。B-tree算法減小定位記錄時所經歷的中間過程,從而加快存取速度。廣泛運用在數據庫文件系統

  B樹定義:

  B樹能夠看做是對2-3查找樹的一種擴展,即他容許每一個節點有M-1個子節點。

  • 根節點至少有兩個子節點

  • 每一個節點有M-1個key,而且以升序排列

  • 位於M-1和M key的子節點的值位於M-1 和M key對應的Value之間

  • 其它節點至少有M/2個子節點

  下圖是一個M=4 階的B樹:

  能夠看到B樹是2-3樹的一種擴展,他容許一個節點有多於2個的元素。B樹的插入及平衡化操做和2-3樹很類似,這裏就不介紹了。下面是往B樹中依次插入

6 10 4 14 5 11 15 3 2 12 1 7 8 8 6 3 6 21 5 15 15 6 32 23 45 65 7 8 6 5 4

的演示動畫:

  B+樹定義:

  B+樹是對B樹的一種變形樹,它與B樹的差別在於:

  • 有k個子結點的結點必然有k個關鍵碼;
  • 非葉結點僅具備索引做用,跟記錄有關的信息均存放在葉結點中。
  • 樹的全部葉結點構成一個有序鏈表,能夠按照關鍵碼排序的次序遍歷所有記錄。

  以下圖,是一個B+樹:

B Plus tree

 

  下圖是B+樹的插入動畫:

 

  B和B+樹的區別在於,B+樹的非葉子結點只包含導航信息,不包含實際的值,全部的葉子結點和相連的節點使用鏈表相連,便於區間查找和遍歷。

  B+ 樹的優勢在於:

  • 因爲B+樹在內部節點上很差含數據信息,所以在內存頁中可以存放更多的key。 數據存放的更加緊密,具備更好的空間局部性。所以訪問葉子幾點上關聯的數據也具備更好的緩存命中率。
  • B+樹的葉子結點都是相鏈的,所以對整棵樹的便利只須要一次線性遍歷葉子結點便可。並且因爲數據順序排列而且相連,因此便於區間查找和搜索。而B樹則須要進行每一層的遞歸遍歷。相鄰的元素可能在內存中不相鄰,因此緩存命中性沒有B+樹好。

  可是B樹也有優勢,其優勢在於,因爲B樹的每個節點都包含key和value,所以常常訪問的元素可能離根節點更近,所以訪問也更迅速。

  下面是B 樹和B+樹的區別圖:

Different between B tree and B plus tree

  B/B+樹經常使用於文件系統和數據庫系統中,它經過對每一個節點存儲個數的擴展,使得對連續的數據可以進行較快的定位和訪問,可以有效減小查找時間,提升存儲的空間局部性從而減小IO操做。它普遍用於文件系統及數據庫中,如:

  • Windows:HPFS文件系統;
  • Mac:HFS,HFS+文件系統;
  • Linux:ResiserFS,XFS,Ext3FS,JFS文件系統;
  • 數據庫:ORACLE,MYSQL,SQLSERVER等中。

  有關B/B+樹在數據庫索引中的應用,請看張洋的MySQL索引背後的數據結構及算法原理這篇文章,這篇文章對MySQL中的如何使用B+樹進行索引有比較詳細的介紹,推薦閱讀。

  樹表查找總結:

  二叉查找樹平均查找性能不錯,爲O(logn),可是最壞狀況會退化爲O(n)。在二叉查找樹的基礎上進行優化,咱們可使用平衡查找樹。平衡查找樹中的2-3查找樹,這種數據結構在插入以後可以進行自平衡操做,從而保證了樹的高度在必定的範圍內進而可以保證最壞狀況下的時間複雜度。可是2-3查找樹實現起來比較困難,紅黑樹是2-3樹的一種簡單高效的實現,他巧妙地使用顏色標記來替代2-3樹中比較難處理的3-node節點問題。紅黑樹是一種比較高效的平衡查找樹,應用很是普遍,不少編程語言的內部實現都或多或少的採用了紅黑樹。

  除此以外,2-3查找樹的另外一個擴展——B/B+平衡樹,在文件系統和數據庫系統中有着普遍的應用。


6. 分塊查找

  分塊查找又稱索引順序查找,它是順序查找的一種改進方法。
  算法思想:將n個數據元素"按塊有序"劃分爲m塊(m ≤ n)。每一塊中的結點沒必要有序,但塊與塊之間必須"按塊有序";即第1塊中任一元素的關鍵字都必須小於第2塊中任一元素的關鍵字;而第2塊中任一元素又都必須小於第3塊中的任一元素,……
  算法流程:
  step1 先選取各塊中的最大關鍵字構成一個索引表;
  step2 查找分兩個部分:先對索引表進行二分查找或順序查找,以肯定待查記錄在哪一塊中;而後,在已肯定的塊中用順序法進行查找。


7. 哈希查找

  什麼是哈希表(Hash)?

  咱們使用一個下標範圍比較大的數組來存儲元素。能夠設計一個函數(哈希函數, 也叫作散列函數),使得每一個元素的關鍵字都與一個函數值(即數組下標)相對應,因而用這個數組單元來存儲這個元素;也能夠簡單的理解爲,按照關鍵字爲每個元素"分類",而後將這個元素存儲在相應"類"所對應的地方。 可是,不可以保證每一個元素的關鍵字與函數值是一一對應的,所以極有可能出現對於不一樣的元素,卻計算出了相同的函數值,這樣就產生了"衝突",換句話說,就是把不一樣的元素分在了相同的"類"之中。後面咱們將看到一種解決"衝突"的簡便作法。
  總的來講,"直接定址"與"解決衝突"是哈希表的兩大特色。

  什麼是哈希函數?

  哈希函數的規則是:經過某種轉換關係,使關鍵字適度的分散到指定大小的的順序結構中,越分散,則之後查找的時間複雜度越小,空間複雜度越高。

  算法思想:哈希的思路很簡單,若是全部的鍵都是整數,那麼就可使用一個簡單的無序數組來實現:將鍵做爲索引,值即爲其對應的值,這樣就能夠快速訪問任意鍵的值。這是對於簡單的鍵的狀況,咱們將其擴展到能夠處理更加複雜的類型的鍵。

  算法流程:

  1)用給定的哈希函數構造哈希表;
  2)根據選擇的衝突處理方法解決地址衝突;
    常見的解決衝突的方法:拉鍊法和線性探測法。 詳細的介紹能夠參見:淺談算法和數據結構: 十一 哈希表
  3)在哈希表的基礎上執行哈希查找。
  哈希表是一個在時間和空間上作出權衡的經典例子。若是沒有內存限制,那麼能夠直接將鍵做爲數組的索引。那麼全部的查找時間複雜度爲O(1);若是沒有時間限制,那麼咱們可使用無序數組並進行順序查找,這樣只須要不多的內存。哈希表使用了適度的時間和空間來在這兩個極端之間找到了平衡。只須要調整哈希函數算法便可在時間和空間上作出取捨。

  複雜度分析

  單純論查找複雜度:對於無衝突的Hash表而言,查找複雜度爲O(1)(注意,在查找以前咱們須要構建相應的Hash表)。

  使用Hash,咱們付出了什麼?
  咱們在實際編程中存儲一個大規模的數據,最早想到的存儲結構可能就是map,也就是咱們常說的KV pair,常用Python的博友可能更有這種體會。使用map的好處就是,咱們在後續處理數據處理時,能夠根據數據的key快速的查找到對應的value值。map的本質就是Hash表,那咱們在獲取了超高查找效率的基礎上,咱們付出了什麼?

  Hash是一種典型以空間換時間的算法,好比原來一個長度爲100的數組,對其查找,只須要遍歷且匹配相應記錄便可,從空間複雜度上來看,假如數組存儲的是byte類型數據,那麼該數組佔用100byte空間。如今咱們採用Hash算法,咱們前面說的Hash必須有一個規則,約束鍵與存儲位置的關係,那麼就須要一個固定長度的hash表,此時,仍然是100byte的數組,假設咱們須要的100byte用來記錄鍵與位置的關係,那麼總的空間爲200byte,並且用於記錄規則的表大小會根據規則,大小多是不定的。

  Hash算法和其餘查找算法的性能對比:

search method efficient conclusion

相關文章
相關標籤/搜索