一般來說,如果你希望資料能夠被快速的找到,那麼最主要的兩種技術手段就是二分查詢,或者使用hash函式。
今天來介紹乙個最簡單的資料結構,有序陣列來組織的二分查詢,當然,我的主要目標是介紹前人解決問題的思路,而非演算法本身,所以不會嘗試用比較難理解的公式和偽碼來描述問題。
使用二分查詢的前提條件是:
1.資料能夠按照某種條件進行排序,比如s=就是排好序的資料,左面的資料一定小於右面的。
2.可以通過某種方式,取出該資料集中任意子集的中間值。比如對於s=,取中值意味著應該取出下標為整數除法(0+11)/2=5的數字。如果我們能夠快速而直接的取出這個中間值,也就是能夠快速的取出下標為5的位置所對應的資料,那麼我們就能夠進行二分查詢。
下面肯定是一些演算法的描述咯。。
舉個例子:
給定有序結果集s=,如果我需要找到4所對應的資料到底是什麼,我們應該如何利用二分查詢法進行查詢呢?
首先,因為s的總共個數是5,位置從0開始直到4,所以第一次應取的中值是(0+4)/2=2
對應在陣列內,應取出的數字是元素[3對應c],因為3<4,所以推斷資料應該在該元素的右面。於是再從中取中值(2+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個關鍵的判斷指標進行了簡單分析,但決定集合的關鍵,是場景本身,沒有銀彈,只有最合適的,你們感受一下~
有序陣列中插入資料
問題描述 專案3 有序陣列中插入資料 定義好乙個有10個元素的陣列,先輸入9個呈公升序的數作為前9個元素,再輸入乙個數,要求按原來排序的規律將它插入陣列中。例如,9個呈公升序的數為1 7 8 17 23 24 59 62 101,需要插入的數字為50,輸出的序列則為1 7 8 17 23 24 50...
有序陣列歸併
寫下這段文字純粹因為太生疏了。下午花了很多時間寫有序陣列的歸併陷入死胡同,結果是證明了兩個陣列歸併沒有輔助陣列時不幸的。通常的陣列歸併,對於大小為m和n的陣列,需要m n的輔助陣列,寫起來並不複雜。有次面試的時候要求寫乙個只有n輔助大小的做法。將b陣列拷到a陣列中,然後在a,b中選小的逐個放入a中。...
Java有序陣列
1 有序陣列簡介,以及優缺點 2 構建有序陣列 在陣列增刪改查功能裡,我們是如何讓陣列有序的呢?肯定是新增方法 1 我們在新增的時候可以進行乙個判斷 2 判斷我們這個新新增的資料到底是新增在哪個地方在哪個位置 接下來插入資料 public void insert int values 然後跳出這個迴...