python实现三叉树_使用python代码实现三叉搜索树高效率”自动输入提示”功能
最近項目中需要通過全拼音和簡寫拼音實現輸入自動提示結果功能,查了一些資料發現三叉搜索樹無論是在時間還是空間上都比較優秀。
三叉搜索樹是trie樹的演化版,除去了指針,這樣在空間上節省不少,每個節點基本分為三個方向:左、中、右,當字符小于當前節點則存放左邊,大于則存放右邊,等于則存放中間。
具體實現原理可參考:http://igoro.com/archive/efficient-auto-complete-with-a-ternary-search-tree/
假如我們存入”AB”,”ABBA”.”ABCD”.”BCD”,這幾個單詞,那么三叉樹就會出現如下的儲存方式:
虛線表示匹配的箭頭,黃色的表示單詞結尾
下面是python實現代碼:# -*- coding: utf-8 -*-
#Ternary Search Tree
# 小于的left, 大于的right, 等于的mid
#定義狀態屬性
_SENTINEL = ()
class TST(object):
#定義三叉樹位置結構
__slots__ = ('splitchar','l','m','r','v')
#初始化結構
def __init__(self, ch=None):
self.splitchar = ch
self.l = self.m = self.r = None
#返回狀態
def __getstate__(self):
l = [self.splitchar,self.l,self.m,self.r]
if hasattr(self,'v'):
l.append(self.v)
return tuple(l)
#設置狀態,目的支持pickle的持久化對象
def __setstate__(self,l):
self.splitchar = l[0]
self.l = l[1]
self.m = l[2]
self.r = l[3]
if len(l) > 4 :
self.v = l[4]
#定義類方法,遞歸方式插入字母,這樣不用實例
@classmethod
def insert(klass,p,k,v):
#獲取字母
ch = k[0]
#若三叉樹結構為空,則初始化
if p is None:
p = TST(ch)
elif p.splitchar is None:
p.splitchar = ch
#若當前字符小于節點字符,則做插入
if ch < p.splitchar:
p.l = klass.insert(p.l,k,v)
#若當前字符等于節點字符,則
elif ch == p.splitchar:
#獲取剩余字符
k = k[1:]
if k:
p.m = klass.insert(p.m,k,v)
else:
#標記字母位置
p.v = v
#否則右插入
else:
p.r = klass.insert(p.r,k,v)
return p
#添加數據
def add(self,k,v):
return self.insert(self,k,v)
#搜索字符串
def search(self,s,fallback=None):
p = self
while p:
ch = s[0]
if ch < p.splitchar:
p = p.l
elif ch == p.splitchar:
s = s[1:]
if not s:
if hasattr(p,'v') :
return p.v
break
p = p.m
else:
p = p.r
return fallback
#搜索前綴的字符
def prefix_search(self,s):
p = self
while p:
ch = s[0]
if ch < p.splitchar:
p = p.l
elif ch == p.splitchar:
s = s[1:]
if not s:
return list(p)
p = p.m
else:
p = p.r
return []
#批量增加數據
def bulk_add(self,l,start=0,stop=None,sorted=False):
'''
為了取得最佳性能,字符串應該以隨機或者自平衡順序插入到三叉樹中
尤其不能按照字母順序,這樣就和鏈表沒啥區別了
'''
#若是沒有排序的數據則進行排序
if not sorted:
l.sort()
#若沒有結束位置,則以全部長度作為結束
if stop is None:
stop = len(l)
#比較開始到結束距離
diff = stop - start
#若為一個則直接添加
if diff == 1 :
self.add(l[start][0],l[start][1])
#若為兩個同樣直接添加
elif diff == 2 :
self.add(l[start][0],l[start][1])
self.add(l[start+1][0],l[start+1][1])
return
#兩個以上則開始計算中間值
else:
mid_p = start + (diff / 2)
#增加中間值
self.add(l[mid_p][0],l[mid_p][1])
#采用分治法遞歸增加,讓我回憶起快速排序
self.bulk_add(l,mid_p+1,stop,True)
self.bulk_add(l,start,mid_p,True)
def __contains__(self,k):
if self.search(k,_SENTINEL) is _SENTINEL:
return False
return True
def __iter__(self):
stack = []
p = self
if not p:
return
while True:
if p.r:
stack.append(p.r)
if p.m:
stack.append(p.m)
if p.l:
stack.append(p.l)
if hasattr(p,'v') :
yield p.v
if not stack:
break
p = stack.pop()
總結
以上是生活随笔為你收集整理的python实现三叉树_使用python代码实现三叉搜索树高效率”自动输入提示”功能的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 工具类软件操作手册_全套广联达软件学习资
- 下一篇: pandas python csv_py