暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

数据结构之字典树或前缀树(Trie)

敲代码的人 2019-09-02
430

如果有100个因为单词,如果使用二分搜索树保存就是100个节点,每个节点保存的就是一个单词,查询每个单词花费的时间复杂度大概是O(log100).


使用Trie这种数据结构,每个结果保存的是要给字母,查询是和多少个单子无关,只和单子长度有关.



如果在英语中不考虑大小写的话,每个节点都会有26个指向下个节点的指针

class Node{
char c;
  Node next[26];
 }
复制


但是考虑到使用语言,情境的不同,我们表示从一个节点到下一个节点是一个映射的过程,而且去下一个节点之前,我们已经知道了这个字母是什么,所以节点可以这样设计

在英语单词中pan和panda这是两个单词,光靠叶子节点不能区分,所以添加一个标志,代表是不是一个单词的结

class Node{
boolean isWord;
Map<Character,Node> next;
}
复制

节点设计说明:

  private class Node {
// 我们设计时,不一定存放的一定是26个因为字母
// 所以每一个节点指向的是n个节点
// 所以每个节点存放的是一个映射Map,
// map中的存放的是一个字符,及对应的下一个node
// 可以这样理解,这个节点中存放的是可以去下一个节点的路标
// 正好映射中存放的一一对应的关系,Character就是连接下一个不同节点的路径
Map<Character, Node> next;


// 这里没有设计 char c;
// 因为这个节点需要存放的字符,就是上一个节点找过的路标,就是Character
// char c


// 我们trie存放的是一个单词,所以需要设计一个表示单词结尾的符号
boolean isWord;


// 构造函数
public Node(boolean isWord) {
this.isWord = isWord;
next = new TreeMap<>();
}


// 无参
public Node() {}
  }
复制


基础框架设计:

public class Trie{
    //内部类
   
//设计成员变量
private Node root;
private int size;

//构造函数
public Trie(){
root = new Node();
size = 0;
}

//获取trie中存储的单词数量
public int getSize(){
return size;
}
}
复制


向trie中添加字符串

思路分析:

  1. 我们节点存放的是一个一个字符,但是添加的是一个一个单词,也就是字符串

  2. 我们需要把一个一个字符串拆成一个一个字符,组织成一个一个节点,添加进去

  3. 添加时,取出字符串第一个节点,以二叉树的根节点为第一个节点的下一个节点插入

  4. 判断当前节点中有没有可以根据需要插入的字符,可以到达的节点

  5. 如果有,跳过,当前节点往下移

  6. 没有,把字符做成节点挂接(就是上一个节点,添加一个根据字符能到新添加节点的路径),当前节点下移

  7. 循环,直至字符串最后一个字符,并把最后一个节点,最后单词标志(isWord = true)


//想trie中添加一个新的单词word
public void add(String word){
//定义当前trie的节点为根几点
Node cur = root;

//遍历每一个字符串的每一个字符
for(int i = 0; i < word.length();i++){
//取出每一个字符比较
char c = word.charAt(i);
//当前节点是否有能根据c,到达的下一个节点
      if(cur.next.get(c) == null){//没有找到下一个节点
cur.next.put(c, new Node());
}
//当前节点网下移
cur = cur.next.get(c);

//判断最后节点位置isword是否为true
if(!cur.isWord){
cur.isWord = true;
size++;
}
}
}
复制


查询trie中是否存在单词word

思路分析:

  1. 和添加大致一样,拆成字符遍历

  2. 如果下一个节点没有找到,直接返回false;

  3. 来到以后一个节点不能直接返回true,(因为如果直接有一个单词是abcd,但是查找的是ab)

  4. 这样情况也能到达单词最后一个字符,但是trie中并没有ab

  5. 最后判断,isWord


  //查询单词word是否存在trie中
public boolean contains(String word){
Node cur = root;
for(int i = 0; i <word.length();i++ ){
char c = word.charAt(i);
if(cur.next.get(c) == null){
return false;
}
cur = cur.next.get(c);
}
return cur.isWord;
}
复制


查找trie中是否有单词以prefix为前缀

思路分析:

  1. 和查找一个单词一样

  2. 但是查找到最后直接返回true

// 查询单词word是否存在trie中
public boolean isPrefix(String word) {
Node cur = root;
for (int i = 0; i < word.length(); i++) {
char c = word.charAt(i);
if (cur.next.get(c) == null) {
return false;
}
cur = cur.next.get(c);
}
return true;
}
复制

喜欢,转发

明天见


文章转载自敲代码的人,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论