python利用Trie(前缀树)实现搜索引擎中关键字输入提示(学习Hash Trie和Double-array Trie)

主要包括两部分内容:
(1)利用python中的dict实现Trie;
(2)按照darts-java的方法做python的实现Double-array Trie

比较:
(1)的实现相对简单,但在词典较大时,时间复杂度较高
(2)Double-array Trie是Trie高效实现,时间复杂度达到O(n),但是实现相对较难

最近遇到一个问题,希望对地名检索时,根据用户的输入,实时推荐用户可能检索的候选地名,并根据实时热度进行排序。这可以以归纳为一个Trie(前缀树)问题。

aaarticlea/jpeg;base64,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" alt="" width="269" height="286" />

Trie在自然语言处理中非常常用,可以实现文本的快速分词、词频统计、字符串查询和模糊匹配、字符串排序、关键输入提示、关键字纠错等场景中。

这些问题都可以在单词树/前缀树/Trie来解决,关于Trie的介绍看【小白详解 Trie 树】这篇文章就够了

一、Hash实现Trie(python中的dict)

github上有Trie实现关键字,实现Trie树的新增、删除、查找,并根据热度CACHED_THREHOLD在node节点对后缀进行缓存,以便提高对高频词的检索效率。本人在其代码上做了注解。
   并对其进行了测试,测试的数据包括了两列,包括关键词和频次。
【code】

#!/usr/bin/env python
# encoding: utf-8
"""
@date: 20131001
@version: 0.2
@author: wklken@yeah.net
@desc: 搜索下拉提示,基于后台提供数据,建立数据结构(前缀树),用户输入query前缀时,可以提示对应query前缀补全 @update:
20131001 基本结构,新增,搜索等基本功能
20131005 增加缓存功能,当缓存打开,用户搜索某个前缀超过一定次数时,进行缓存,减少搜索时间
20140309 修改代码,降低内存占用 @TODO:
test case
加入拼音的话,导致内存占用翻倍增长,要考虑下如何优化节点,共用内存 """
#这是实现cache的一种方式,也可以使用redis/memcached在外部做缓存
#https://github.com/wklken/suggestion/blob/master/easymap/suggest.py
#一旦打开,search时会对每个节点做cache,当增加删除节点时,其路径上的cache会被清除,搜索时间降低了一个数量级
#代价:内存消耗, 不需要时可以关闭,或者通过CACHED_THREHOLD调整缓存数量 #开启
#CACHED = True
#关闭
CACHED = False #注意,CACHED_SIZE >= search中的limit,保证search从缓存能获取到足够多的结果
CACHED_SIZE = 10
#被搜索超过多少次后才加入缓存
CACHED_THREHOLD = 10 ############### start ###################### class Node(dict):
def __init__(self, key, is_leaf=False, weight=0, kwargs=None):
"""
@param key: 节点字符
@param is_leaf: 是否叶子节点
@param weight: 节点权重, 某个词最后一个字节点代表其权重,其余中间节点权重为0,无意义
@param kwargs: 可传入其他任意参数,用于某些特殊用途
"""
self.key = key
self.is_leaf = is_leaf
self.weight = weight #缓存,存的是node指针
self.cache = []
#节点前缀搜索次数,可以用于搜索query数据分析
self.search_count = 0 #其他节点无关仅和内容相关的参数
if kwargs:
for key, value in kwargs.iteritems():
setattr(self, key, value) def __str__(self):
return '<Node key:%s is_leaf:%s weight:%s Subnodes: %s>' % (self.key, self.is_leaf, self.weight, self.items()) def add_subnode(self, node):
"""
添加子节点 :param node: 子节点对象
"""
self.update({node.key: node}) def get_subnode(self, key):
"""
获取子节点 :param key: 子节点key
:return: Node对象
"""
return self.get(key) def has_subnode(self):
"""
判断是否存在子节点 :return: bool
"""
return len(self) > 0 def get_top_node(self, prefix):
"""
获取一个前缀的最后一个节点(补全所有后缀的顶部节点) :param prefix: 字符转前缀
:return: Node对象
"""
top = self for k in prefix:
top = top.get_subnode(k)
if top is None:
return None
return top def depth_walk(node):
"""
递归,深度优先遍历一个节点,返回每个节点所代表的key以及所有关键字节点(叶节点) @param node: Node对象
"""
result = []
if node.is_leaf:
#result.append(('', node))
if len(node) >0:#修改,避免该前缀刚好是关键字时搜索不到
result.append((node.key[:-1], node))
node.is_leaf=False
depth_walk(node)
else:
return [('', node)] if node.has_subnode():
for k in node.iterkeys():
s = depth_walk(node.get(k))
#print k , s[0][0]
result.extend([(k + subkey, snode) for subkey, snode in s])
return result
#else:
#print node.key
#return [('', node)] def search(node, prefix, limit=None, is_case_sensitive=False):
"""
搜索一个前缀下的所有单词列表 递归 @param node: 根节点
@param prefix: 前缀
@param limit: 返回提示的数量
@param is_case_sensitive: 是否大小写敏感
@return: [(key, node)], 包含提示关键字和对应叶子节点的元组列表
"""
if not is_case_sensitive:
prefix = prefix.lower() node = node.get_top_node(prefix)
#print 'len(node):' ,len(node)
#如果找不到前缀节点,代表匹配失败,返回空
if node is None:
return [] #搜索次数递增
node.search_count += 1 if CACHED and node.cache:
return node.cache[:limit] if limit is not None else node.cache
#print depth_walk(node)
result = [(prefix + subkey, pnode) for subkey, pnode in depth_walk(node)] result.sort(key=lambda x: x[1].weight, reverse=True) if CACHED and node.search_count >= CACHED_THREHOLD:
node.cache = result[:CACHED_SIZE]
#print len(result)
return result[:limit] if limit is not None else result #TODO: 做成可以传递任意参数的,不需要每次都改 2013-10-13 done
def add(node, keyword, weight=0, **kwargs):
"""
加入一个单词到树 @param node: 根节点
@param keyword: 关键词,前缀
@param weight: 权重
@param kwargs: 其他任意存储属性
"""
one_node = node index = 0
last_index = len(keyword) - 1
for c in keyword:
if c not in one_node:
if index != last_index:
one_node.add_subnode(Node(c, weight=weight))
else:
one_node.add_subnode(Node(c, is_leaf=True, weight=weight, kwargs=kwargs))
one_node = one_node.get_subnode(c)
else:
one_node = one_node.get_subnode(c) if CACHED:
one_node.cache = [] if index == last_index:
one_node.is_leaf = True
one_node.weight = weight
for key, value in kwargs:
setattr(one_node, key, value)
index += 1 def delete(node, keyword, judge_leaf=False):
"""
从树中删除一个单词 @param node: 根节点
@param keyword: 关键词,前缀
@param judge_leaf: 是否判定叶节点,递归用,外部调用使用默认值
""" # 空关键词,传入参数有问题,或者递归调用到了根节点,直接返回
if not keyword:
return top_node = node.get_top_node(keyword)
if top_node is None:
return #清理缓存
if CACHED:
top_node.cache = [] #递归往上,遇到节点是某个关键词节点时,要退出
if judge_leaf:
if top_node.is_leaf:
return
#非递归,调用delete
else:
if not top_node.is_leaf:
return if top_node.has_subnode():
#存在子节点,去除其标志 done
top_node.is_leaf = False
return
else:
#不存在子节点,逐层检查删除节点
this_node = top_node prefix = keyword[:-1]
top_node = node.get_top_node(prefix)
del top_node[this_node.key]
delete(node, prefix, judge_leaf=True) ##############################
# 增补功能 读数据文件建立树 #
############################## def build(file_path, is_case_sensitive=False):
"""
从文件构建数据结构, 文件必须utf-8编码,可变更 @param file_path: 数据文件路径,数据文件默认两列,格式“关键词\t权重"
@param is_case_sensitive: 是否大小写敏感
"""
node = Node("")
f = open(file_path)
for line in f:
line = line.strip()
if not isinstance(line,unicode):
line = line.decode('utf-8')
parts = line.split('\t')
name = parts[0]
if not is_case_sensitive:
name = name.lower()
add(node, name, int(parts[1]))
f.close()
return node import time
if __name__ == '__main__':
#print '============ test1 ==============='
#n = Node("")
#default weight=0, 后面的参数可以任意加,搜索返回结果再从node中将放入对应的值取出,这里放入一个othervalue值
#add(n, u'he', othervalue="v-he")
#add(n, u'her', weight=0, othervalue="v-her")
#add(n, u'hero', weight=10, othervalue="v-hero")
#add(n, u'hera', weight=3, othervalue="v-hera") #delete(n, u'hero') #print "search h: "
#for key, node in search(n, u'h'):
#print key, node, node.othervalue, id(node)
#print key, node.weight #print "serch her: "
#for key, node in search(n, u'her'):
#print key, node, node.othervalue, id(node)
#print key, node.weight
start= time.clock()
print '============ test2 ==============='
tree = build("./shanxinpoi.txt", is_case_sensitive=False)
print len(tree),'time:',time.clock()-start
startline=time.clock()
print u'search 秦岭'
for key, node in search(tree, u'秦岭', limit=10):
print key, node.weight
print time.clock()-startline

二、Trie的Double-array Trie实现

Trie的Double-array Trie的实现参考【小白详解 Trie 树】和【双数组Trie树(DoubleArrayTrie)Java实现】

在看代码之前提醒几点:
(1)Comero有根据komiya-atsushi/darts-java,进行了Double-array Trie的python实现,komiya-atsushi的实现巧妙使用了文字的的编码,以文字的编码(一个汉字三个字符,每个字符0-256)作为【小白详解 Trie 树】中的字符编码。

(2)代码中不需要构造真正的Trie树,直接用字符串,构造对应node,因为words是排过序的,这样避免Trie树在构建过程中频繁从根节点开始重构

(3)实现中使用了了base[s]+c=t & check[t]=base[s],而非【小白详解 Trie 树】中的base[s]+c=t & check[t]=s

(4)komiya-atsushi实现Trie的构建、从词典文件创建,以及对构建Trie的本地化(保存base和check,下次打开不用再重新构建)

(5)本文就改了Comero中的bug,并对代码进行了注解。并参照dingyaguang117/DoubleArrayTrie(java)中的代码实现了输入提示FindAllWords方法。

(6)本文实现的FindAllWords输入提示方法没有用到词频信息,但是实现也不难

【code】

# -*- coding:utf-8 -*-

# base
# https://linux.thai.net/~thep/datrie/datrie.html
# http://jorbe.sinaapp.com/2014/05/11/datrie/
# http://www.hankcs.com/program/java/%E5%8F%8C%E6%95%B0%E7%BB%84trie%E6%A0%91doublearraytriejava%E5%AE%9E%E7%8E%B0.html
# (komiya-atsushi/darts-java | 先建立Trie树,再构造DAT,为siblings先找到合适的空间)
# https://blog.csdn.net/kissmile/article/details/47417277
# http://nark.cc/p/?p=1480
#https://github.com/midnight2104/midnight2104.github.io/blob/58b5664b3e16968dd24ac5b1b3f99dc21133b8c4/_posts/2018-8-8-%E5%8F%8C%E6%95%B0%E7%BB%84Trie%E6%A0%91(DoubleArrayTrie).md # 不需要构造真正的Trie树,直接用字符串,构造对应node,因为words是排过序的
# todo : error info
# todo : performance test
# todo : resize
# warning: code=0表示叶子节点可能会有隐患(正常词汇的情况下是ok的)
# 修正: 由于想要回溯字符串的效果,叶子节点和base不能重合(这样叶子节点可以继续记录其他值比如频率),叶子节点code: 0->-1
# 但是如此的话,叶子节点可能会与正常节点冲突? 找begin的使用应该是考虑到的?
#from __future__ import print_function
class DATrie(object): class Node(object): def __init__(self, code, depth, left, right):
self.code = code
self.depth = depth
self.left = left
self.right = right def __init__(self):
self.MAX_SIZE = 2097152 # 65536 * 32
self.base = [0] * self.MAX_SIZE
self.check = [-1] * self.MAX_SIZE # -1 表示空
self.used = [False] * self.MAX_SIZE
self.nextCheckPos = 0 # 详细 见后面->当数组某段使用率达到某个值时记录下可用点,以便下次不再使用
self.size = 0 # 记录总共用到的空间 # 需要改变size的时候调用,这里只能用于build之前。cuz没有打算复制数据.
def resize(self, size):
self.MAX_SIZE = size
self.base = [0] * self.MAX_SIZE
self.check = [-1] * self.MAX_SIZE
self.used = [False] * self.MAX_SIZE # 先决条件是self.words ordered 且没有重复
# siblings至少会有一个
def fetch(self, parent): ###获取parent的孩子,存放在siblings中,并记录下其左右截至
depth = parent.depth siblings = [] # size == parent.right-parent.left
i = parent.left
while i < parent.right: #遍历所有子节点,right-left+1个单词
s = self.words[i][depth:] #词的后半部分
if s == '':
siblings.append(
self.Node(code=-1, depth=depth+1, left=i, right=i+1)) # 叶子节点
else:
c = ord(s[0]) #字符串中每个汉字占用3个字符(code,实际也就当成符码),将每个字符转为数字 ,树实际是用这些数字构建的
#print type(s[0]),c
if siblings == [] or siblings[-1].code != c:
siblings.append(
self.Node(code=c, depth=depth+1, left=i, right=i+1)) # 新建节点
else: # siblings[-1].code == c
siblings[-1].right += 1 #已经是排过序的可以直接计数+1
i += 1
# siblings
return siblings # 在insert之前,认为可以先排序词汇,对base的分配检查应该是有利的
# 先构建树,再构建DAT,再销毁树
def build(self, words):
words = sorted(list(set(words))) # 去重排序
#for word in words:print word.decode('utf-8')
self.words = words
# todo: 销毁_root
_root = self.Node(code=0, depth=0, left=0, right=len(self.words)) #增加第一个节点
self.base[0] = 1
siblings = self.fetch(_root)
#for ii in words: print ii.decode('utf-8')
#print 'siblings len',len(siblings)
#for i in siblings: print i.code
self.insert(siblings, 0) #插入根节点的第一层孩子
# while False: # 利用队列来实现非递归构造
# pass
del self.words
print("DATrie builded.") def insert(self, siblings, parent_base_idx):
""" parent_base_idx为父节点base index, siblings为其子节点们 """
# 暂时按komiya-atsushi/darts-java的方案
# 总的来讲是从0开始分配beigin]
#self.used[parent_base_idx] = True begin = 0
pos = max(siblings[0].code + 1, self.nextCheckPos) - 1 #从第一个孩子的字符码位置开始找,因为排过序,前面的都已经使用
nonzero_num = 0 # 非零统计
first = 0 begin_ok_flag = False # 找合适的begin
while not begin_ok_flag:
pos += 1
if pos >= self.MAX_SIZE:
raise Exception("no room, may be resize it.")
if self.check[pos] != -1 or self.used[pos]: # check——check数组,used——占用标记,表明pos位置已经占用
nonzero_num += 1 # 已被使用
continue
elif first == 0:
self.nextCheckPos = pos # 第一个可以使用的位置,记录?仅执行一遍
first = 1 begin = pos - siblings[0].code # 第一个孩子节点对应的begin if begin + siblings[-1].code >= self.MAX_SIZE:
raise Exception("no room, may be resize it.") if self.used[begin]: #该位置已经占用
continue if len(siblings) == 1: #只有一个节点
begin_ok_flag = True
break for sibling in siblings[1:]:
if self.check[begin + sibling.code] == -1 and self.used[begin + sibling.code] is False: #对于sibling,begin位置可用
begin_ok_flag = True
else:
begin_ok_flag = False #用一个不可用,则begin不可用
break # 得到合适的begin # -- Simple heuristics --
# if the percentage of non-empty contents in check between the
# index 'next_check_pos' and 'check' is greater than some constant value
# (e.g. 0.9), new 'next_check_pos' index is written by 'check'. #从位置 next_check_pos 开始到 pos 间,如果已占用的空间在95%以上,下次插入节点时,直接从 pos 位置处开始查找成功获得这一层节点的begin之后得到,影响下一次执行insert时的查找效率
if (nonzero_num / (pos - self.nextCheckPos + 1)) >= 0.95:
self.nextCheckPos = pos self.used[begin] = True # base[begin] 记录 parent chr -- 这样就可以从节点回溯得到字符串
# 想要可以回溯的话,就不能在字符串末尾节点记录值了,或者给叶子节点找个0以外的值? 0->-1
#self.base[begin] = parent_base_idx #【*】
#print 'begin:',begin,self.base[begin] if self.size < begin + siblings[-1].code + 1:
self.size = begin + siblings[-1].code + 1 for sibling in siblings: #更新所有子节点的check base[s]+c=t & check[t]=s
self.check[begin + sibling.code] = begin for sibling in siblings: # 由于是递归的情况,需要先处理完check
# darts-java 还考虑到叶子节点有值的情况,暂时不考虑(需要记录的话,记录在叶子节点上)
if sibling.code == -1:
self.base[begin + sibling.code] = -1 * sibling.left - 1
else:
new_sibings = self.fetch(sibling)
h = self.insert(new_sibings, begin + sibling.code) #插入孙子节点,begin + sibling.code为子节点的位置
self.base[begin + sibling.code] = h #更新base所有子节点位置的转移基数为[其孩子最合适的begin] return begin def search(self, word):
""" 查找单词是否存在 """
p = 0 # root
if word == '':
return False
for c in word:
c = ord(c)
next = abs(self.base[p]) + c
# print(c, next, self.base[next], self.check[next])
if next > self.MAX_SIZE: # 一定不存在
return False
# print(self.base[self.base[p]])
if self.check[next] != abs(self.base[p]):
return False
p = next # print('*'*10+'\n', 0, p, self.base[self.base[p]], self.check[self.base[p]])
# 由于code=0,实际上是base[leaf_node->base+leaf_node.code],这个负的值本身没什么用
# 修正:left code = -1
if self.base[self.base[p] - 1] < 0 and self.base[p] == self.check[self.base[p] - 1] :
#print p
return True
else: # 不是词尾
return False def common_prefix_search(self, content):
""" 公共前缀匹配 """
# 用了 darts-java 写法,再仔细看一下
result = []
b = self.base[0] # 从root开始
p = 0
n = 0
tmp_str = ""
for c in content:
c = ord(c)
p = b
n = self.base[p - 1] # for iden leaf if b == self.check[p - 1] and n < 0:
result.append(tmp_str) tmp_str += chr(c)
#print(tmp_str )
p = b + c # cur node if b == self.check[p]:
b = self.base[p] # next base
else: # no next node
return result # 判断最后一个node
p = b
n = self.base[p - 1] if b == self.check[p - 1] and n < 0:
result.append(tmp_str) return result def Find_Last_Base_index(self, word):
b = self.base[0] # 从root开始
p = 0
#n = 0
#print len(word)
tmp_str = ""
for c in word:
c = ord(c)
p = b
p = b + c # cur node, p is new base position, b is the old if b == self.check[p]:
tmp_str += chr(c)
b = self.base[p] # next base
else: # no next node
return -1
#print '====', p, self.base[p], tmp_str.decode('utf-8')
return p def GetAllChildWord(self,index):
result = []
#result.append("")
# print self.base[self.base[index]-1],'++++'
if self.base[self.base[index]-1] <= 0 and self.base[index] == self.check[self.base[index] - 1]:
result.append("")
#return result
for i in range(0,256):
#print(chr(i))
if self.check[self.base[index]+i]==self.base[index]:
#print self.base[index],(chr(i)),i
for s in self.GetAllChildWord(self.base[index]+i):
#print s
result.append( chr(i)+s)
return result def FindAllWords(self, word):
result = []
last_index=self.Find_Last_Base_index(word)
if last_index==-1:
return result
for end in self.GetAllChildWord(last_index):
result.append(word+end)
return result def get_string(self, chr_id):
""" 从某个节点返回整个字符串, todo:改为私有 """
if self.check[chr_id] == -1:
raise Exception("不存在该字符。")
child = chr_id
s = []
while 0 != child:
base = self.check[child]
print(base, child)
label = chr(child - base)
s.append(label)
print(label)
child = self.base[base]
return "".join(s[::-1]) def get_use_rate(self):
""" 空间使用率 """
return self.size / self.MAX_SIZE if __name__ == '__main__':
words = ["一举","一举一动",'',
"一举成名",
"一举成名天下知","洛阳市西工区中州中路","人民东路2号","中州东",
"洛阳市","洛阳","洛神1","洛神赋","万科","万达3","万科翡翠","万达广场",
"洛川","洛川苹果","商洛","商洛市","商朝","商业","商业模","商业模式",
"万能",
"万能胶"] #for word in words:print [word] #一个汉字的占用3个字符,
words=[]
for line in open('1000.txt').readlines():
# #print line.strip().decode('utf-8')
words.append(line.strip()) datrie = DATrie()
datrie.build(words)
#for line in open('1000.txt').readlines():
# print(datrie.search(line.strip()),end=' ')
#print('-'*10)
#print(datrie.search("景华路"))
#print('-'*10)
#print(datrie.search("景华路号")) # print('-'*10)
#for item in datrie.common_prefix_search("商业模式"): print(item.decode('utf-8'))
#for item in datrie.common_prefix_search("商业模式"):print item.decode('utf-8')
# print(datrie.common_prefix_search("一举成名天下知"))
#print(datrie.base[:1000])
# print('-'*10)
# print(datrie.get_string(21520))
#index=datrie.Find_Last_Base_index("商业")
#print(index),'-=-=-='
#print datrie.search("商业"),datrie.search("商业"),datrie.search("商业模式")
#print index, datrie.check[datrie.base[index]+230],datrie.base[index]
for ii in datrie.FindAllWords('中州中路'):print ii.decode('utf-8')
#print(datrie.Find_Last_Base_index("一举")[2].decode('utf-8'))
#print()

测试数据是洛阳地址1000.txt

最后欢迎参与讨论。

参考:

小白详解Trie树:https://segmentfault.com/a/1190000008877595

Hash实现Trie(python中的dict)(源码):https://github.com/wklken/suggestion/blob/master/easymap/suggest.py

双数组Trie树(DoubleArrayTrie)Java实现(主要理解):http://www.hankcs.com/program/java/%E5%8F%8C%E6%95%B0%E7%BB%84trie%E6%A0%91doublearraytriejava%E5%AE%9E%E7%8E%B0.html

Comero对DoubleArrayTrie的python实现(源码):https://github.com/helmz/toy_algorithms_in_python/blob/master/double_array_trie.py

DoubleArrayTrie树的Tail压缩,java实现(源码):https://github.com/dingyaguang117/DoubleArrayTrie/blob/master/src/DoubleArrayTrie.java#L348

搜索时的动态提示:https://mp.weixin.qq.com/s/fT2LJ-skNEdh89DnH9FRxw

python利用Trie(前缀树)实现搜索引擎中关键字输入提示(学习Hash Trie和Double-array Trie)的更多相关文章

  1. 实现 Trie (前缀树)

    实现一个 Trie (前缀树),包含 insert, search, 和 startsWith 这三个操作. 示例: Trie trie = new Trie(); trie.insert(" ...

  2. 力扣208——实现 Trie (前缀树)

    这道题主要是构造前缀树节点的数据结构,帮助解答问题. 原题 实现一个 Trie (前缀树),包含 insert, search, 和 startsWith 这三个操作. 示例: Trie trie = ...

  3. [Swift]LeetCode208. 实现 Trie (前缀树) | Implement Trie (Prefix Tree)

    Implement a trie with insert, search, and startsWith methods. Example: Trie trie = new Trie(); trie. ...

  4. leetcode 208. 实现 Trie (前缀树)

    实现一个 Trie (前缀树),包含 insert, search, 和 startsWith 这三个操作. 示例: Trie trie = new Trie(); trie.insert(" ...

  5. 第15个算法-实现 Trie (前缀树)(LeetCode)

    解法代码来源 :https://blog.csdn.net/whdAlive/article/details/81084793 算法来源:力扣(LeetCode)链接:https://leetcode ...

  6. Java实现 LeetCode 208 实现 Trie (前缀树)

    208. 实现 Trie (前缀树) 实现一个 Trie (前缀树),包含 insert, search, 和 startsWith 这三个操作. 示例: Trie trie = new Trie() ...

  7. 【LeetCode】208. Implement Trie (Prefix Tree) 实现 Trie (前缀树)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 公众号:负雪明烛 本文关键词:Leetcode, 力扣,Trie, 前缀树,字典树,20 ...

  8. 数据结构—— Trie (前缀树)

    实现一个 Trie (前缀树),包含 插入, 查询, 和 查询前缀这三个操作. Trie trie = new Trie(); trie.insert("apple"); trie ...

  9. 力扣 - 208. 实现Trie(前缀树)

    目录 题目 思路 代码 复杂度分析 题目 208. 实现 Trie (前缀树) 思路 在我们生活中很多地方都用到了前缀树:自动补全,模糊匹配,九宫格打字预测等等... 虽然说用哈希表也可以实现:是否出 ...

随机推荐

  1. Linux链接脚本学习--lds

    一.概论 ld: GNU的链接器. 用来把一定量的目标文件跟档案文件链接在一起,并重新定位它们的数据,链接符号引用. 一般编译一个程序时,最后一步就是运行ld进行链接 每一个链接都被一个链接脚本所控制 ...

  2. Spring Bean 的生命周期,如何被管理的?

    定义 Bean是一个被实例化,组装,并通过Spring IOC容器(BeanFactory和ApplicationContext容器)所管理的对象. 作用域 Spring支持五个作用域,分别是sing ...

  3. 从 Secure Element 到 Android KeyStore

    忽如一夜春风来,智能手机来到每个人的手上,我们用它支付.理财.娱乐.工作.记录生活.存储私密信息.乘坐公共交通.开启家门.控制汽车....智能手机是如此的重要,不知天天把它拿在手上的你,是否关心过它是 ...

  4. 利用history.pushState()实现页面无刷新更新

    本来是在研究vue-router如何记录滚动位置,点返回的时候还是回到原来的位置,看到有人说的history.state存了一个值,才把history研究一下,发现 history.pushState ...

  5. mysql的binlog进行数据恢复

    什么是binlog? binlog,也称为二进制日志,记录对数据发生或潜在发生更改的SQL语句,并以二进制的形式保存在磁盘中,可以用来查看数据库的变更历史(具体的时间点所有的SQL操作).数据库增量备 ...

  6. 转载:https原理:证书传递、验证和数据加密、解密过程解析

    写的太好了,就是我一直想找的内容,看了这个对https立马明白多了 http://www.cnblogs.com/zhuqil/archive/2012/07/23/2604572.html 我们都知 ...

  7. mysql 开发进阶篇系列 36 工具篇mysqlshow(数据库对象查看工具)

    一.概述 mysqlshow客户端查找工具,能很快地查找存在哪些数据库,数据库中的表,表中的列或索引,和mysql客户端工具很类似,不过有些特性是mysql客户端工具所不具备的. mysqlshow的 ...

  8. Hadoop项目实战-用户行为分析之分析与设计

    1.概述 本课程的视频教程地址:<用户行为分析之分析与设计> 下面开始本教程的学习,本教程以用户行为分析案例为基础,带着大家对项目的各个指标做详细的分析,对项目的整体设计做合理的规划,让大 ...

  9. php处理文件的思考(去除空行、每行多余字符)

    1.去除空行 <?php $str = file_get_contents('a.txt'); $str = explode(PHP_EOL, $str); //分割为数组,每行为一个数组元素 ...

  10. Java设计模式学习记录-中介者模式

    前言 中介者模式听名字就能想到也是一种为了解决耦合度的设计模式,其实中介者模式在结构上与观察者.命令模式十分相像:而应用目的又与结构模式“门面模式”有些相似.但区别于命令模式的是大多数中介者角色对于客 ...