通常來講,若是你但願數據可以被快速的找到,那麼最主要的兩種技術手段就是二分查找,或者使用Hash函數。算法
今天來介紹一個最簡單的數據結構,有序數組來組織的二分查找,固然,個人主要目標是介紹前人解決問題的思路,而非算法自己,因此不會嘗試用比較難理解的公式和僞碼來描述問題。數組
使用二分查找的前提條件是:數據結構
1.數據可以按照某種條件進行排序,好比S={0,1,2,3,4,5,6,7,100,101,102}就是排好序的數據,左面的數據必定小於右面的。分佈式
2.能夠經過某種方式,取出該數據集中任意子集的中間值。好比對於S={0,1,2,3,4,5,6,7,100,101,102},取中值意味着應該取出下標爲整數除法(0+11)/2=5的數字。若是咱們可以快速而直接的取出這個中間值,也就是可以快速的取出下標爲5的位置所對應的數據,那麼咱們就可以進行二分查找。ide
下面確定是一些算法的描述咯。。函數
舉個例子:性能
給定有序結果集S={1對應a,2對應b,3對應c,4對應e,6對應f},若是我須要找到4所對應的數據究竟是什麼,咱們應該如何利用二分查找法進行查找呢?指針
首先,由於S的總共個數是5,位置從0開始直到4,因此第一次應取的中值是(0+4)/2=2排序
對應在數組內,應取出的數字是元素[3對應c],由於3<4,因此推斷數據應該在該元素的右面。因而再從中取中值(2{原來的中值}+1{右面,因此加1}+4)/2=3.從數組裏取出位置3鎖對應的數據,就是4對應e.發現符合要求,因而返回查找成功。內存
看起來是挺簡單的一個算法,不過,我仍是建議你們都本身親自寫一寫,由於其實很容易出錯~XD。
看完了算法,也請由我來作一些分析,看看這些算法背後的思路吧。
在二分查找這套算法中,一個最重要的思路就是,折半查找。一下排除掉一半的數據,而後再排除一半,再排除一半,直到找到數據爲止,說是這樣可以快速的找到數據了,爲啥就能快呢?
這就讓我想起了一個古老的印度故事,國王要給大臣贏棋的獎賞,大臣但願可以「請在第一個格子裏放一顆麥粒,第二個格子裏放2顆,第三個格子裏放4個,第四個格子裏放8粒……依此類推,把64個格子都放滿。」總共能有多少,結論是一千八百四十四吉六千七百四十四兆零七百三十七億零九百五十五萬一千六百一十五,二分查找可以在64次運算後處理這樣多的記錄,結果仍是很驚人的,這也就是O(log2N)時間複雜度的由來,二分查找,2次能夠從4條記錄中找到對應記錄,3次8條,4次16條。。依次類推。
下面咱們來簡單的分析一下使用有序數組+二分查找的,他的一些技術特性如何,通常來講,若是你指望快速的瞭解一款存儲產品的性能如何,直接看他選擇的映射數據結構,就能大概的猜出這款產品的一些基本特性指標,由於,一個存儲的性能好壞,基本不取決於他如何處理分佈式場景,而所有取決於如何選擇他的映射存儲模式。
不過本週的數據結構由於十分簡單,因此一些技術特性也天然的就很簡單啦,讓咱們來看看。
1.是否支持範圍查找
基本上來講,這個問題主要取決於兩個方面,一個是數據是否有序,另一個是該存儲結構是否提供了快速讀取下一個記錄的方法。
對於數組來講,全部數據都是有序的,而且只須要簡單地作下標=下標+1的操做,就能夠以程序提供的最快方法。所以,範圍查找確定是能夠支持的。並且效率應該是很高的ov0.
2.集合是否可以隨着數據的增加而自動擴展
哎,這個屬性是個比較重要的特性,咱們來作一下探討。
首先,默認的數組是沒法支持自動擴展的。
而後,你們也應該知道,目前在現代語言中,通常都會提供一個支持自由擴展的數組,實現的方式主要是如下這麼幾類:
第一類是在在數組的尾部使用鏈接到另一個數組的指針。
第二類是直接建立一個新的數組而後把老數據所有複製過去。
因此,在有必定的空間消耗的狀況下,數組是可以作到自動擴展的~
然而,雖然可以作到自動的擴展了,可是,要知道,要可以保持映射能夠快速的查詢,那麼必須還要保證新寫入的數據的有序性,這就很麻煩了。。由於你沒法知道數據寫入的順序,那麼如何處理中間值插入就是個很麻煩的問題了。
好比,若是個人寫入順序是1,3,4,2,5這個順序,而且在開始的時候沒有辦法知道寫入的順序,那麼咱們惟一能作的事情就是,按照順序,寫1,而後在1的右臨位,寫3,而後再在右臨位寫4,這時候來個2,麻煩來了,我應該怎麼作呢?
在數組內,一種最容易想到的方式就是,找到1這個位置,而後將1右邊的數據所有往右移動一個位置,而後將2填寫進去。
哈,你也看到了,這種方式會隨着咱們數據量的變大,而代價變得很是巨大,好比若是有100萬行記錄,那麼就意味着最壞狀況下,須要每次寫入都移動100萬行記錄。。。這代價但是真大。
所以,這也就是咱們使用數組的時候的一個最大的問題了,單獨的使用數組,是不支持更新的,而使用簡單的策略好比自動擴增的數組,也沒法支持有序數據的自增的。
不過,數組做爲計算機內的基本數據結構,是其餘高級數據結構的基本組成部分,咱們後面還會看到他:)
3.讀寫性能如何
對於讀取,若是要快速查找數據,須要使用二分查找來找到一個數據,而二分查找的時間複雜度大概是O(log2N).
對於寫入,數組支持的代價很高,所以基本沒人會想要用大數組來作須要頻繁增長和刪除對應關係的映射的實現的吧?==
4.是否面向磁盤結構
大部分狀況下,純粹的數組並非一個面向磁盤的結構。
磁盤的特性是,一次讀取一批數據,或一次寫入一批數據時效率會高。
順序讀大批數據,或者順序寫大批數據的時候,效率會變高。
而若是要進行二分查找,若是可以一次從磁盤中取出整個數組再進行二分查找,則查找效率會變高,若不得不直接依託磁盤進行二分查找,則讀取效率會很低,每次折半,都須要從磁盤中的一個隨機位置取出一個block,並從中取出一條記錄,隨機讀取的次數=log2N的結果,而每一次的隨機讀,對磁盤來講都是災難。
不過,在將來,咱們會看到一些依託於數組的數據結構,部分的解決了這個問題:)
5.並行指標
只要是不支持修改的數據模型,通常來講並行讀取效率均可以作到很高,由於。。徹底不會變就不須要加鎖啊--,所以是能夠徹底並行的
但並行寫入效率嘛。。你能讓犀牛飛起來麼?
6.內存佔用
數組的內存佔用應該是個標杆,若是再能比數組更節省空間,那就須要作大量hack和壓縮了。
以上,咱們就針對數組,第一次對開篇提到的6個關鍵的判斷指標進行了簡單分析,但決定集合的關鍵,是場景自己,沒有銀彈,只有最合適的,大家感覺一下~