Trie树的基本原理与实现以及改进

Trie树的基本原理

本文介绍了关于Trie树的基本原理与实现,维基百科中的说明如下:trie,又称前缀树或字典树,是一种有序树,用于保存关联数组,其中的键通常是字符串。与二叉查找树不同,键不是直接保存在节点中,而是由节点在树中的位置决定。一个节点的所有子孙都有相同的前缀,也就是这个节点对应的字符串,而根节点对应空字符串。一般情况下,不是所有的节点都有对应的值,只有叶子节点和部分内部节点所对应的键才有相关的值。

(1)使用节点数组,因为是英文字符,可以用Node[26]来保存孩子节点(如果是数字我们可以用Node[10]),这种方式最快,但是并不是所有节点都会有很多孩子,所以这种方式浪费的空间太多 (2)用一个链表根据需要动态添加节点。这样我们就可以省下不小的空间,但是缺点是搜索的时候需要遍历这个链表,增加了时间复杂度。

给出一组单词,inn, int, at, age, adv, ant, 我们可以得到下面的Trie:

所以,当前的字符串的长度越长,树的高度越高,存储一个字符串,要将前几个字符都要存储,这也是Trie树这种数据结构的一个弊端,太过于消耗资源。

Trie节点原型

这是一个多叉树,实际上与二叉树非常的类似,只不过把孩子节点作为一个数组的形式表示。

class TrieNode {
    TrieNode[] next = new TrieNode[26];
    String word;
}

Trie树的建立

在Trie树中,根节点是不存数据的。i是找到当前的字母是26个字母中的哪一个,p是从头结点一直移动到叶子节点,然后将word插入。

public TrieNode buildTrie(String[] words) {
    TrieNode root = new TrieNode();
    for (String w : words) {
        TrieNode p = root;
        for (char c : w.toCharArray()) {
            int i = c - 'a';
            if (p.next[i] == null)
                p.next[i] = new TrieNode();
            p = p.next[i];
        }
        p.word = w;
        System.out.println(w);
    }
    return root;
}

Trie树的遍历

这个是Trie树的层序遍历,同样是采用一个队列,方法与二叉树的层序遍历区别不大。

public void printTrie(TrieNode root){
    Queue<TrieNode> queue = new LinkedList<>();
    queue.add(root);
    while (!queue.isEmpty()){
        TrieNode temp = queue.remove();
        if (temp.word!=null)
            System.out.println(temp.word);
        for (TrieNode trieNode:temp.next){
            if (trieNode!=null){
                queue.add(trieNode);
            }
        }
    }
}

添加两个数据项:

  1. 以该节点为结尾的个数,可以达到查询是否存在某个字符串的功能
  2. 插入节点时,记录节点划过的次数,可以达到查询有多少个以某个字符串作为前缀的功能
public class Code_01_TrieTree {

	public static class TrieNode {
		public int path;
		public int end;
		public TrieNode[] nexts;

		public TrieNode() {
			path = 0;
			end = 0;
			nexts = new TrieNode[26];
		}
	}

	public static class Trie {
		private TrieNode root;

		public Trie() {
			root = new TrieNode();
		}

		public void insert(String word) {
			if (word == null) {
				return;
			}
			char[] chs = word.toCharArray();
			TrieNode node = root;
			int index = 0;
			for (int i = 0; i < chs.length; i++) {
				index = chs[i] - 'a';
				if (node.nexts[index] == null) {
					node.nexts[index] = new TrieNode();
				}
				node = node.nexts[index];
				node.path++;
			}
			node.end++;
		}

		public void delete(String word) {
			if (search(word) != 0) {
				char[] chs = word.toCharArray();
				TrieNode node = root;
				int index = 0;
				for (int i = 0; i < chs.length; i++) {
					index = chs[i] - 'a';
					if (--node.nexts[index].path == 0) {
						node.nexts[index] = null;
						return;
					}
					node = node.nexts[index];
				}
				node.end--;
			}
		}

		public int search(String word) {
			if (word == null) {
				return 0;
			}
			char[] chs = word.toCharArray();
			TrieNode node = root;
			int index = 0;
			for (int i = 0; i < chs.length; i++) {
				index = chs[i] - 'a';
				if (node.nexts[index] == null) {
					return 0;
				}
				node = node.nexts[index];
			}
			return node.end;
		}

		public int prefixNumber(String pre) {
			if (pre == null) {
				return 0;
			}
			char[] chs = pre.toCharArray();
			TrieNode node = root;
			int index = 0;
			for (int i = 0; i < chs.length; i++) {
				index = chs[i] - 'a';
				if (node.nexts[index] == null) {
					return 0;
				}
				node = node.nexts[index];
			}
			return node.path;
		}
	}

	 
	}

}

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

编辑于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券