大數據下-巧用位數組排序和判重及布隆過濾器的簡單應用

技巧一:對無重複的數據集排序

對於給定的數據集,(2,4,1,12,9,7,6)如何對它排序?

        第一種方式、使用最基本的冒泡,快排、基數排序等,最小時間複雜度 0(nlogn)。

        第二種方式、使用位數組排序算法。

對於數據集排序,相信大多數都會在第一時間便能想起來,而對於方法二,就需要一定的思考了。

對於我們給定的數據集,最大數值爲 12,那麼我們可以開闢一個長度爲 12 的字節數組,如下圖,都初始化爲0,


然後讀取數據,例如,讀取到 2 的時候,就將下標爲 1 的位置爲 1,即 a[2-1] = 1,此時數組狀態如下圖:


當讀到 4 的時候,數組的狀態如下圖:

當讀取完之後,數組的狀態如下圖:


此時,我們再遍歷一遍該字符數組,依次記錄值爲 1 的所有元素的下表,即 0,1,3,5,6,8,11,也就是1,2,4,6,7,9,12。 

比較方法一和方法二:

方法一,最好情況下的時間空間複雜度爲 O(nlogn),O(nlogn)。

方法二,時間複雜度和空間複雜度完全依賴於數據集中最大的數字,爲 O(n),如果數據集合適,它是十分高效的算法。它的侷限也很明顯:數據集需是無重複集,數據分佈比較密集,數據區間上下限差不能太大,最大數不宜過大。


技巧二:對有重複的數據進行判重

對於給定數據集(2,4,1,12,2,9,7,6,1,4)如何找出重複出現的數字?

方法一、使用排序算法排序,然後遍歷找出重複出現的元素。

方法二、首先開闢出長度爲 12 的位數組,並初始化爲0。然後遍歷元素集,對於每次出現的數據,如2,則令 a[2-1] = 1 ,如此這般,一直遍歷到12,此時位數組的狀態如下圖:


對於下一個元素 2,當訪問 a[1]時發現a[1]=1,說明2之前出現過,則2即爲重複出現的數。


實際應用案例

應用1:某文件中包含一些 8 位的電話號碼,統計電話號碼出現的個數?

8位電話號碼,最大的整數,爲 99999999,需建立的位數組大概佔用 100000000/8 = 1250000B = 12500K = 12.5MB,可以看出需要大約 12.5MB的空間。


應用2:某文件中包含一些 8 位的電話號碼,統計只出現一次的號碼?

這裏需要擴展一下,可以用兩個 bit 表示一個號碼,00 代表沒有出現過,01代表出現過一次,10表示出現過兩次,11表示三次。此時,大約需要 25MB 的空間。


應用3:有兩個文件,文件1中有1 億個10位的qq號碼,文件2中有5千萬個10位的QQ號碼,判斷兩個文件中重複出現的QQ號?

同應用1, 10位的QQ號最大數爲 9999999999 , 需建立的數組大約佔用 1250MB 即 1.25G ,全部初始化爲0,。讀取第一個文件,將出現過的位標記爲1。標記完之後,再讀取第二個文件,對於讀取到每一個號碼,如果該號碼對應的位爲1,則說明該號碼爲重複QQ號。


應用4:有兩個文件,文件1中含有1億個15位的QQ號碼,文件2中含有5千萬個15位的QQ號碼,判斷兩個文件中重複出現的QQ號?

在這裏QQ號碼的位數升級爲15位了,如果還採用應用3的方法,此時需要的空間大概有125000GB = 125TB,顯然這是不現實的,那麼我們就要尋求別的解決方案。


Bloom Filter(布隆過濾器)

對於Bit-Map分析一下,每次都會開闢一塊表示最大數值大小的bit數組,比如情景1中的12,將對應的數據經過映射到bit數組的下標,這其實是一種最簡單的hash算法,對1去模。在上述應用4中,當qq號碼改爲15位的時候,Bit-Map就不太好用了,如何改進呢?解決辦法:減少bit數組的長度,增加hash函數的個數

對於每一個qq號碼,我用K個hash函數,經過k次映射,得到k個不同位置,假設k=3,那麼對於一個qq號碼,映射到位數組中3個不同的位置。



當讀取第二個包含5千萬個qq號碼的文件的時候,使用同樣的3個hash函數進行映射,當3個位置全部是1的時候才表示出現過,否則表示沒有出現過。

這種判重算法對於大數據量的情況下是十分高效的,因爲所有的操作都是在內存中完成的,避免了磁盤讀寫對速度的影響。

但是這種算法並不能保證 100%的準確性,只能保證可控制的誤差範圍。這種可控誤差的精確數學公式會在 BloomFilter 有關的文章中專門介紹。



發佈了86 篇原創文章 · 獲贊 65 · 訪問量 43萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章