未知長度鍊錶資料隨機抽取問題

2021-06-20 10:41:40 字數 1251 閱讀 4734

** 董的部落格

1. 問題由來

google曾經有一道非常經典的面試題:

給你乙個長度為n的鍊錶。n很大,但你不知道n有多大。你的任務是從這n個元素中隨機取出k個元素。你只能遍歷這個鍊錶一次。你的演算法必須保證取出的元素恰好有k個,且它們是完全隨機的(出現概率均等)?

這道題的解法非常多,網上討論也非常熱烈。本文要討論的是,這個問題是從何而來,有什麼實用價值?

自從有了hadoop之後,該問題便有了新的應用載體。隨著資料量的增多,很多資料探勘演算法被轉移到mapreduce上實現,而資料探勘中有個基本的問題是怎樣對資料進行抽樣。在hadoop中,每個job會被分解成多個task平行計算,而資料的總量事先是不知道的(知道job執行結束才能獲取數總數,而資料量非常大時,掃瞄一遍資料的代價非常高),使用者知道的只是要獲取的樣本量,那怎樣在類似於hadoop的分布式平台上進行資料抽樣?

回過頭來看google的這道面試題,是不是正好時hadoop平台上海量資料抽樣問題?

2. 在hadoop上編寫抽樣程式

2.1 解法一

(1) 設計思想

蓄水池抽樣:先儲存前k個元素, 從第k+1個元素開始, 以1/i (i=k+1, k+2,…,n) 的概率選中第i個元素,並隨機替換掉乙個已儲存的記錄,這樣遍歷一次得到k個元素,可以保證完全隨機選取。

(2) mapreduce實現

使用者執行job時,需指定每個map task的取樣量。比如,使用者該job的map task個數為s,則每個map task需要採集k/s個元素。

(3) 優缺點分析

由於該job沒有reduce task,因而效率很高。

2.2 解法二

(1) 設計思想

依次掃瞄每個元素,為每個元素賦予乙個隨機的整數值;然後使用top k演算法(譬如最大k個整數)得到需要的k個元素。

(2) mapreduce實現

(3) 優缺點分析

該演算法比第一種演算法低效,但由於整個過程自然流暢,實現起來非常簡單,不易出錯。

2.3 解法三

(1) 設計思想

考慮第乙個元素,其以k/n的概率被選中;如果該節點被選中,則從剩下的(n-1)個元素中選出(k-1)個元素;如果沒有被選中,則從剩下的(n-1)個元素中選出k個元素,…,依次這樣下去,直到獲取k個元素。

(2) mapreduce實現

(3) 優缺點分析

由於該演算法沒有reduce task,效率比較高,但需要在inputformat中統計資料量,程式設計複雜度較高。

查詢未知鍊錶長度的中間結點

眾所周知,鍊錶是不知道長度的,如果想知道長度只能通過遍歷一遍鍊錶才可得知,因此對於查詢未知鍊錶長度的中間結點可以有很多方法。最簡單的方法就是通過遍歷一邊鍊錶得到長度l,再通過遍歷l 2的鍊錶得到中間結點,此時時間複雜度就是o l l 2 而另一種更簡便方法則為通過建立兩個指標,第乙個指標為第二個指標...

基於鍊錶的上課隨機抽取回答問題系統

include include include include include 每個學生的結構體函式 struct student struct student list head 插入新節點函式 void student new struct student head 遊戲規則函式 int gam...

面試題 求未知長度的鍊錶的中間節點(快慢指標)

所謂的快慢指標的快慢是指指標向前移動的步長。比如在單鏈表中,快指標每次向前移動2個步長,慢指標則每次向前移動1個步長。快速找出未知長度的鍊錶的中間節點,暴力解法就是先遍歷真個鍊錶,算出鍊錶的長度,再從頭遍歷長度的一半,即可找出,不過這個比較費時。更巧妙的辦法是運用快慢指標,將快慢指標先指向頭結點,快...