讀古今文學網 > 算法神探:一部谷歌首席工程師寫的CS小說 > 22 公文字典樹 >

22 公文字典樹

在對調職記錄進行兩次完整的搜索後,Frank仍然沒有發現任何可疑的人。更確切地說,他沒有找到任何有明顯跡象參與了密謀的人。此時,每個人仍都是他的懷疑對象。

「嘿,Notation的名字在這裡。」Socks在第二次搜索的時候注意到。

Frank歎了口氣,說:「當然會在那裡,她剛剛從警察學院畢業。這是一本警察學院的警官分派記錄。」

「她在學校表現得很好,是不是?」Socks在掃瞄她的調職記錄時問。

「請注意,Socks,」Frank說,「記住,我們是尋找任何可疑的東西,而不是那些無關緊要的。」

「三個畢業生轉移到了城堡,」Socks說,「或許我們應該對其中的某人進行更加深入的調查。Gretchen認為……」

「不,」Frank搖了搖頭打斷了Socks的話。他已經看過了這些調職記錄,這三個人沒有任何可疑之處。

「這裡什麼都沒有。」Frank說。Socks本想反駁,Frank再次打斷他:「你應該回到我的辦公室。我向警長匯報完畢後就去那裡找你,我們再一起看看還有沒有什麼別的線索。」

此時,Frank看到Socks的臉上顯露出如釋重負的表情,但是他不確定這是否只是自己的臆想。他知道有些新人為了躲過周會不僅會裝作身患闌尾炎,甚至還甘願去做手術,而Socks現在可以躲過與警長的會面了。

在去辦公室找警長之前,Frank先去了趟檔案室。當時警長只給了他案件的官方報告,並沒有讓他去犯罪現場進行調查,說不定在這裡能幸運地找到一些線索。

檔案管理員是一個名叫John Cache的人,在勉強同意Frank進入房間後便寸步不離地盯著他。這可能是因為盜竊之後警察局加強了防盜警戒,也可能僅僅是John Cache作為一個新手的急躁表現——每個新手都幻想著有一天能打擊犯罪扭轉局面呢。

Frank掃視整個書櫃,假裝在搜尋有關丟失寵物龍的信息。不出所料,這麼大的警察局裡,公文多如牛毛。現在每個政府組織的公文數量都在成倍地增長,更別說首都警察局了,其中的警官人數比任何其他兩所警察局中的警官人數之和還要多。雖然這裡有很多卷宗被偷走了,但房間裡還是堆滿了數不清的卷宗。

幸運的是,檔案管理員已經將信息有效地組織起來。每個文檔都必須遵守國王所頒布的《文書和十人以上機構工作文檔的存儲規則》,強制按照目錄進行分類和存檔。書櫃中很大一部分都用於存儲諸如逮捕報告、費用報告、調職記錄、警衛輪崗和噪聲投訴等文件了。

檔案室看起來像是一個巨大的trie樹。trie樹,也稱為前綴樹,是一種可對字符串集合進行高效搜索的數據結構。它在概念上類似於二叉搜索樹,也是首先從根節點開始,並一路向下擴展。但是,trie樹是用來搜索字符串而不是數值的。在每一個節點,trie樹都會根據字符串中的下一個字母來對原始數據進行拆分。因此,trie樹中的每個節點都有很多子節點,包含了字母表中A~Z的每個字母。在這種結構中,只需沿trie樹中的一條路徑就可以高效地搜索出任意字符串,因為只需要根據目標字符串中的下一個字母就可以方便地選擇出下一個節點。

Frank曾經在一個巫師大會上看到過這個神奇的trie樹。一棵像霓虹燈樣子的樹倒掛在空中,顯示著它所攜帶的一千多種不同藥水的名字。為簡單起見,這裡的trie樹只顯示非空的子樹。

客戶可以使用trie樹快速瞭解哪些商品有現貨哪些商品缺貨。例如,他們可以通過B、A、T、N、I和P這條分支來知道小販今天攜帶了batnip;也可以迅速地知道今天baby powder缺貨,因為此時BA的子樹中沒有B這個分支。

檔案室採用了trie樹的概念,並將其應用於書櫃的管理上。26個巨大的書櫃靠牆排列著,每個書櫃上都記錄了一個字母,它們是trie樹的第一層節點。首先是A書櫃,然後是B書櫃,以此類推。

接下來,每個書櫃包含若干個擱架,每個擱架對應了目錄的第二個字母,這些層構成了trie樹的第二層。

由於大部分兩個字母的組合與現有的目錄並不對應,因此每個書櫃並不需要26個獨立的擱架。每個擱架水平放置一些貼了標籤的書擋,這些書擋就構成了trie樹的第三層。

Frank一邊走,一邊看著V號擱架。他在警隊的時候,就曾經成功遊說為Vinettee集團專門開闢一個叫作Vinettees的目錄。他花了很多晚上去研究書櫃V擱架I書擋N上的文件。

此時,Frank停在書櫃D擱架R書擋A處。他取出了一本有關寵物龍的檔案假裝在看它,同時搜尋著房間的其他地方。

警長說的沒錯。書櫃中前綴為AS、CE、EX、NO、PR和RO的擱架裡的文件全部被搬空了,而其他的卻完好無損。他暗暗地記住了這些前綴,被偷走的這些前綴的文件中一定暗藏著什麼信息。Frank有了另外一條線索。

他把手中的書放回到Dragon書櫃的Registrations號擱架處,大聲宣佈:「好消息!檔案記載首都只有幾隻食鴿龍,不過卻有很多的鴿子。等我找到它時,至少那只可憐的龍不會被餓死。」

當Frank從檔案室大步走出來的時候,John Cache憐憫地看了他一眼,什麼也沒有說。

警用算法導論:trie樹

節選自Drecker教授講義

trie樹是基於樹的數據結構,用戶可以很方便地通過某個字符串的前綴來搜索到目標字符串。與二叉搜索樹一樣,trie樹也是首先從根節點開始,然後一步步向下選取分支節點。在trie樹中,每一個節點下的分支數(即有多少個子節點),取決於所有字符串中當前節點字母的下一個元素有多少種不同的可能。所以,trie樹的每個節點可能不止兩個子節點。

和二叉搜索樹一樣,我們只需將數據中出現過的節點依次插入到trie樹中。例如,現在有單詞ZAP、ZEN、ZONE和ZOOM。因為此時並沒有ZONK這個單詞,所以我們並不需要在ZON下面再設一個節點為K的子樹。

注意,我們不需要在每個節點中存儲一個字符串的所有可能的前綴,而是可以根據需要通過從樹根到該節點的路徑來重建出這個前綴。但是,有時也需要在每個節點中存儲一些額外的信息,比如標記該節點是否為一個字符串或者單詞的最後一個字母,以便我們區分當前插入的是一個單詞還是一個單詞的前綴。例如,我們無法確定樹中的ZOO是否為一個獨立的單詞,因為還有一個單詞是ZOOM。

trie樹的搜索過程類似於二叉搜索樹的搜索過程。算法從trie樹的頂部開始向下進行。在每個節點,決定接下來應該選取哪個分支就需要看目標字符串的下一個字母是什麼。例如,需要搜索ZEN這個字符串,搜索路徑為:從Z開始,接著選擇E這個分支,最後選擇N這個分支。

如果找不到這樣的節點,就可以確定我們所需要的單詞(字符串)不在樹中。所以,如果我們在這棵樹上搜索ZANY,我們會發現ZA之後便無路可走。

令人驚訝的是,警務中常常用trie樹來編製犯罪嫌疑犯名單。舉報者常常拒絕提供一個完整的名字,只會提供名字的前幾個字母。此時,我們就可以使用trie樹來對名字的前綴進行搜索,便可以得到與該前綴相匹配的所有人的名字。依據字母的數量和特殊性,這些信息足以大幅減少搜索範圍。