前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Trie树的基本原理与实现以及改进

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

原创
作者头像
大学里的混子
修改2019-02-21 17:08:37
1.3K0
修改2019-02-21 17:08:37
举报
文章被收录于专栏:LeetCodeLeetCode

Trie树的基本原理

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

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

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

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

Trie节点原型

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

代码语言:javascript
复制
class TrieNode {
    TrieNode[] next = new TrieNode[26];
    String word;
}

Trie树的建立

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

代码语言:javascript
复制
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树的层序遍历,同样是采用一个队列,方法与二叉树的层序遍历区别不大。

代码语言:javascript
复制
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. 插入节点时,记录节点划过的次数,可以达到查询有多少个以某个字符串作为前缀的功能
代码语言:javascript
复制

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;
		}
	}

	 
	}

}

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

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

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Trie树的基本原理
  • Trie节点原型
  • Trie树的建立
  • Trie树的遍历
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档