字符串问题---字典树(前缀树)的实现

【题目】

  字典树又称为前缀树或者Trie树,是处理字符串常用的数据结构。假设组成所有单词的字符仅是‘a’~‘z’,请实现字典树的结构,并包含以下四个主要的功能。

  • void insert(String word):添加word,可重复添加
  • void delete(String word):删除word,如果word添加过多次,仅删除一次
  • boolean search(String word):查询word是否在字典树中
  • int prefixNumber(String pre):返回以字符串pre作为前缀的单词数量

【基本思路】

  字典树介绍。字典树是一种树形结构,优点是利用字符串的公共前缀来节约存储空间。如图,是插入abc, abcd, abd, b, bcd, efg, hik后的字典树。
         这里写图片描述
  字典树的基本性质如下:
  1.根节点没有字符路径。除根节点外,每一个节点都被一个字符路径找到。
  2.从根节点到某一节点,将路径上经过的字符连接起来,为扫过的对应字符串。
  3.每个节点向下所有的字符路径上的字符都不同。

下面介绍有关字典树节点的类型,首先定义节点类。

class TrieNode:
    def __init__(self):
        self.path = 0
        self.end = 0 
        self.map = [None for i in range(26)]

  TrieNode类中,path表示有多少个单词共用这个节点,end表示有多少个单词以这个单词结尾,map是一个哈希表结构,key代表该节点的一条字符路径,value表示字符路径指向的节点,根据题目的说明,map是一个长度为26的数组(相当于一棵有26个孩子的树),在字符种类较多的时候可以使用真实的哈希表结构实现map。下面介绍Trie树类如何实现。

  • void insert(String word):假设word的长度为N。从左到右遍历word中的每个字符,并依次从头节点开始根据每一个word[i],找到下一个节点。如果该节点不存在就新建一个,记为a,令a.path = 1.如果节点存在,记为b,令b + 1。通过最后一个字符找到最后一个节点时记为e,令e.path + 1,e.end + 1

  • boolean search(String word):从左到右遍历word中字符,并依次从头节点根据word[i]找到下一个节点。如果找的过程中节点不存在,直接返回False。如果能通过最后一个字符找到最后一个节点,并且该节点的end值不等于0,返回True。如果最后一个节点的end值为0,说明word只是一个前缀,返回False

  • void delete(String word):先调用search函数看word在不在树中,如果不在,直接返回。否则,进入如下的操作。从左到右依次遍历word中的字符,并依次从头节点根据word[i]找到下一个节点。在找的过程中,把扫过的每个节点的path值减 1 。如果发现下一个path的值减完为0,直接从当前节点的map中删除后续的所有路径,返回即可。如果扫到最后一个节点。记为e,令e.path,e.end都减1

  • int prefixNumber(String pre):和查找操作同理,根据pre不断找到节点,假设最后的节点记为e,返回e.path即可

下面是使用python3.5实现的代码。

class Trie:
    def __init__(self):
        self.root = TrieNode()

    def insert(self, word):
        if word == None:
            return
        node = self.root
        for i in word:
            index = ord(i) - ord('a')
            if node.map[index] == None:
                node.map[index] = TrieNode()
            node = node.map[index]
            node.path += 1
        node.end += 1
        print("Inset successful")

    def search(self, word):
        if word == None:
            return False
        node = self.root
        for i in word:
            index = ord(i) - ord('a')
            if node.map[index] == None:
                return False
            node = node.map[index]
        return True if node.end != 0 else False

    def delete(self, word):
        if self.search(word):
            node = self.root
            for i in word:
                index = ord(i) - ord('a')
                node.map[index].path -= 1
                if node.map[index].path == 0:
                    node.map[index] = None
                    return
                node = node.map[index]
            node.end -= 1

    def prefixNumber(self, pre):
        if pre == None:
            return
        node = self.root
        for i in pre:
            index = ord(i) - ord('a')
            if node.map[index] == None:
                return 0
            node = node.map[index]
        return node.path
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值