1. 程式人生 > >演算法--統計文字中出現次數最多的單詞(字典樹)

演算法--統計文字中出現次數最多的單詞(字典樹)

統計一個文字中,出現次數最多的單詞:單詞全部小寫,單詞與單詞之間以空格間隔

1.利用字典  key為單詞  value為單詞出現的次數

def mostString():
    dict = {}
    fr = open('preprocessing.txt')
    k = 0
    n = 0
    for line in fr.readlines():
        for s in line.strip().split(' '):
            if s not in dict.keys():
                dict[s] = 0
            else:
                dict[s] = dict[s] + 1
            if dict[s]>=n:
                k = s
                n = dict[s]
    #print(dict)
    print(k)

程式碼如上,利用一個字典來儲存所有字典,value來儲存每個單詞的次數,當字典中沒有該單詞時,執行新增操作;若已經有該單詞則執行更新操作,最後返回次數最多的單詞即可。空間複雜度N  時間複雜度平均為N

2.字典樹解法

字典樹,又稱為單詞查詢樹,Tire數,是一種樹形結構,它是一種雜湊樹的變種。

基本性質如下:

  • 根節點不包含字元,除根節點外的每一個子節點都包含一個字元
  • 從根節點到某一節點。路徑上經過的字元連線起來,就是該節點對應的字串
  • 每個節點的所有子節點包含的字元都不相同

典型應用是用於統計,排序和儲存大量的字串(不僅限於字串),經常被搜尋引擎系統用於文字詞頻統計。

利用字串的公共字首來減少查詢時間,最大限度的減少無謂的字串比較,查詢效率比雜湊樹高。

       如果文字中的單詞數量很多,並且大部分單詞字首都相同,那麼利用第一種字典方式來儲存所有單詞,則會浪費許多空間,此時可以利用字典樹來儲存單詞,充分利用最大公共字首。

構造字典樹節點:

class TrieNode:
    def __init__(self, var=None, parent=None, num=0):
        self.num = num
        self.isEnd = False
        self.son = {}
        self.var = var
        self.parent = parent

num  該字元在某種字首中出現的次數

isEnd  true標識某個單詞以該字元結尾

var  該節點儲存的字元

son 該節點所有葉子節點

parent  指向父節點的指標

1.建構函式:

root = None
    
    def __init__(self):
        self.root = TrieNode()

2.在字典樹中插入一個單詞:

def insert(self, str):
        if len(str)<=0:
            return
        node = self.root    
        for c in str:
            if c not in node.son.keys():
                node.son[c] = TrieNode(c, node, 1)                
            else:
                node.son[c].num += 1
            node = node.son[c]
        node.isEnd = True

遍歷單詞的每個字元,找到從根節點開始的一條路徑來儲存所有字元,若字元不存在則新建一個節點,若已經存在則更新計數,最後將單詞最後一個字元指示變數isEnd置為true

2.在字典樹中查詢一個單詞是否存在

def has(self, str):
        if len(str)==0:
            return False
        node = self.root    
        for c in str:
            if c not in node.son.keys():
                return False
            else:
                node = node.son[c]
        return node.isEnd

從字典樹的根節點開始,依次匹配單詞的每個字元,若最終存在某條路徑包含該單詞所有字元,則觀察最後一個字元的指示變數

3.計算以某個字元為字首的所有單詞總數

def countPrefix(self, prefix):
        if len(prefix)==0:
            return -1
        node = self.root
        for c in prefix:
            if c not in node.son.keys():
                return 0
            else:
                node = node.son[c]
        return node.num

找到該字串的最後一個字元位置,返回計數值即可。

4.遍歷字典樹

def preOrder(self, node):
        if node != None:
            print (list(node.son.keys()))
            for child in node.son.keys():
                self.preOrder(node.son[child])

5.計算出現次數最多的單詞

def mostString(self):
        max = [0]
        r = [TrieNode()]
        self.helper(self.root, max, r)
        x = r[0]
        print(x)
        s = []
        while x!=None:
            s.append(x.var)
            x = x.parent
        s.reverse()
        return s

    def helper(self, node, max, r):
        if node != None:
            print (node.num, node.isEnd)
            if node.isEnd and node.num >= max[0]:
                r[0] = node
                max[0] = node.num
            print('r value ', max, r[0].var)
            for child in node.son.keys():
                self.helper(node.son[child], max, r)

如上所示,遍歷每一個節點,找到那些指示變數isEnd==true並且計數值最大的節點,從該節點沿parent指標回溯到根節點,然後倒序輸出即可。

def mostString2():
    dict = {}
    t = Trie()
    fr = open('preprocessing.txt')    
    for line in fr.readlines():
        for s in line.strip().split(' '):
            print(s) 
            t.insert(s)
    #print(t.preOrder(t.root))
    #print(t)
    #t.preOrder(t.root)
    #print(k)
    print(t.has('chen'))   
    print(t.has('chendsfdsfsd'))
    print(t.countPrefix('chen'))  
    print(t.mostString())

問題:

1.python中是否支援物件陣列,本來想利用物件陣列來儲存某節點的孩子節點集合的

2.python中引數傳遞問題,為求最大值,函式傳遞時使用max=[0] r=[TrieNode()],很彆扭

max=0屬於不可變物件可以理解,但是r=TrieNode() r應該是可變物件吧,但是這裡好像也是不可改變的

測試一下:

def canchange(r):
    r = TrieNode(2) 
    print('func inner ',r.var)    
                
def mostString2():
    dict = {}
    t = Trie()
    fr = open('preprocessing.txt')    
    for line in fr.readlines():
        for s in line.strip().split(' '):
            print(s) 
            t.insert(s)
    #print(t.preOrder(t.root))
    #print(t)
    #t.preOrder(t.root)
    #print(k)
    print(t.has('chen'))   
    print(t.has('chendsfdsfsd'))
    print(t.countPrefix('chen'))  
    print(t.mostString())
    r = TrieNode(1)
    print('before',r.var)
    canchange(r)
    print('after',r.var)

可知物件指標是不可變物件,函式傳遞屬於值傳遞,好奇怪!

參考地址:

https://www.cnblogs.com/xujian2014/p/5614724.html