trie数的实现

      Trie树又称单词查找树,Trie树,是一种树形结构,是一种哈希树的变种。典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。它的优点是:利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较,查询效率比哈希表高。

      这里的需求是,给如一组词汇,北京人,北京,武汉,武汉话等等。能够统计“武汉”这个词的词频,输入"武"的时候,能够得到以“武”开头的所有词。实现的代码如下:

package com.dong.util;

import java.util.ArrayList;
import java.util.List;

public class Trie {
    // 根节点
    private final TrieNode root = new TrieNode(‘ ‘);

    // 向trie树中插入一个词
    public void insert(String word) {
        if (word == null || word.length() == 0) {
            return;
        }
        String left = word;
        TrieNode cur = root;
        while (left.length() > 0) {
            char toInert = left.charAt(0);
            TrieNode next = null;
            // 如果那个节点不存在的话,将当前节点插入
            if (containCharNode(cur.getChild(), toInert) == null) {
                next = new TrieNode(toInert);
                cur.getChild().add(next);
            } else {
                next = containCharNode(cur.getChild(), toInert);
            }
            cur = next;
            left = left.substring(1);
            if (left.length() == 0) {
                cur.setFreq(cur.getFreq() + 1);
            }
        }
    }

    // 通过前缀查找词,返回包括前缀的所有词。
    public List<String> search(String prefix) {
        List<String> retList = new ArrayList<String>();
        List<String> tempList = new ArrayList<String>();
        if (prefix == null || prefix.length() == 0) {
            return null;
        }
        String left = prefix;
        TrieNode cur = root;
        while (left.length() > 0) {
            char toFind = left.charAt(0);
            TrieNode next = null;
            // 如果那个节点不存在的话,将当前节点插入
            if (containCharNode(cur.getChild(), toFind) == null) {
                return null;
            } else {
                next = containCharNode(cur.getChild(), toFind);
                if (left.length() == 1) {
                    cur = next;
                    break;
                }
            }
            cur = next;
            left = left.substring(1);

        }

        dfs(cur, new ArrayList<Character>(), tempList);
        for (String s : tempList) {
            retList.add(prefix + s);
        }

        if (getFreq(prefix) > 0) {
            retList.add(prefix);

        }
        return retList;
    }

    // 深度搜索一个trieNode节点下的所有的词
    private void dfs(TrieNode root, List<Character> stack, List<String> retList) {
        if (root.getChild().size() == 0) {
            StringBuffer sb = new StringBuffer();
            for (char c : stack) {
                sb.append(c);
            }
            retList.add(sb.toString());

        } else {
            for (TrieNode r : root.getChild()) {
                stack.add(r.getVal());
                dfs(r, stack, retList);
                stack.remove(stack.size() - 1);
            }
        }

    }

    // 查看一个节点的的子节点是否包含一个字符
    public TrieNode containCharNode(List<TrieNode> child, char c) {
        TrieNode ret = null;
        for (TrieNode temp : child) {
            if (temp.getVal() == c) {
                ret = temp;
            }
        }
        return ret;

    }

    // 得到一个词的词频
    public int getFreq(String word) {
        if (word == null || word.length() == 0) {
            return 0;
        }
        String left = word;
        TrieNode cur = root;
        while (left.length() > 0) {
            char toFind = left.charAt(0);
            TrieNode next = null;
            // 如果不存在此节点,返回0
            if (containCharNode(cur.getChild(), toFind) == null) {
                return 0;
            } else {
                next = containCharNode(cur.getChild(), toFind);
                if (left.length() == 1) {
                    cur = next;
                    break;
                }
            }
            cur = next;
            left = left.substring(1);

        }
        return cur.getFreq();
    }

    public static String fill(String prefix, ArrayList<Character> stack) {
        ArrayList<String> retList = new ArrayList<String>();
        StringBuffer sb = new StringBuffer();
        sb.append(prefix);
        for (char c : stack) {
            sb.append(c);
        }
        return sb.toString();

    }

    public static void main(String[] args) {
        Trie t = new Trie();
        String[] wordList = { "我晕", "我晕啊", "我不信啊", "我信了", "也是", "这不对啊", "我晕" };
        for (String word : wordList) {
            t.insert(word);
        }
        System.out.println(t.search("我晕"));

    }
}

class TrieNode {
    // 节点下存放的字符
    private char val;
    // 一个节点下面的子节点
    private List<TrieNode> child;
    // 该词的词频
    private int freq;

    public TrieNode(char val) {
        child = new ArrayList();
        freq = 0;
        this.val = val;

    }

    public char getVal() {
        return val;
    }

    public void setVal(char val) {
        this.val = val;
    }

    public List<TrieNode> getChild() {
        return child;
    }

    public void setChild(List<TrieNode> child) {
        this.child = child;
    }

    public int getFreq() {
        return freq;
    }

    public void setFreq(int freq) {
        this.freq = freq;
    }
}
时间: 2024-10-15 19:33:30

trie数的实现的相关文章

poj 1204 Word Puzzles 静态trie数解决多模式串匹配问题

题意: 给一个二维字符数组和w个模式串,求这w个模式串在二维字符数组的位置. 分析: 静态trie树. 代码: //poj 1204 //sep9 #include <iostream> using namespace std; const int maxN=1024; const int maxM=270*maxN; char str[maxN][maxN]; char s[maxN]; int vis[27],query_id[maxM],ans[maxN][3]; int num,x,y

POJ 3630 Phone List Trie题解

Trie的应用题目. 本题有两个难点了: 1 动态建立Trie会超时,须要静态建立数组,然后构造树 2 推断的时候注意两种情况: 1) Tire树有133,然后插入13333556的时候.2)插入顺序倒转过来的时候 改动一下标准Trie数的插入函数就能够了: #include <stdio.h> #include <string.h> const int MAX_NODE = 100001; const int MAX_WORD = 11; const int ARR_SIZE =

Trie树沉思录(1)

发现自己已经很久没有写解题报告了,很大一部分是因为懒,做完题之后不想再怎样了~不过最近发现写解题报告确实是有好处的,一方面可以复习,一方面可以梳理.还有就是可以给自己的岁月留下一点什么东西~今天是五一劳动节,就应该要劳动!我要重新着手写我的博客了~ 最近几个星期都在研究字符串,有点难,不过到现在为止Trie数学得还算是有那么点意思,写篇博文来记录一下! (关于Trie数是什么东西我就不想写了,我只写我个人的一些思考) Trie树通过共享前缀来达到了节约内存的目标,十分的强大!关于他的实现大概有两

BZOJ 3261 最大异或和 可持久化Trie树

题目大意:给定一个序列,提供下列操作: 1.在数组结尾插入一个数 2.给定l,r,x,求一个l<=p<=r,使x^a[p]^a[p+1]^...^a[n]最大 首先我们可以维护前缀和 然后就是使x^sum[n]^sum[p-1]最大 x^sum[n]为定值,于是用Trie树贪心即可 考虑到l-1<=p-1<=r-1,我们不能对于每个询问都建一棵Trie树,但是我们可以对于Trie数维护前缀和,建立可持久化Trie树 每个区间[l,r]的Trie树为tree[r]-tree[l-1]

Trie树/字典树题目(2017今日头条笔试题:异或)

1 /* 2 本程序说明: 3 4 [编程题] 异或 5 时间限制:1秒 6 空间限制:32768K 7 给定整数m以及n各数字A1,A2,..An,将数列A中所有元素两两异或,共能得到n(n-1)/2个结果,请求出这些结果中大于m的有多少个. 8 输入描述: 9 第一行包含两个整数n,m. 10 11 第二行给出n个整数A1,A2,...,An. 12 13 数据范围 14 15 对于30%的数据,1 <= n, m <= 1000 16 17 对于100%的数据,1 <= n, m,

【暖*墟】#数据结构# 可持久化Trie 与 XOR问题

0/1 Trie [例题]最长异或路径 给定一棵n个点的带权树,求树中最长的异或路径. Solution 01字典树:用于解决xor问题. 用dis[i]表示‘从i点到根节点的路径异或和’. ---> 那么问题转化为:求两点dis的异或最大值. 一般查询两数的最大异或值时,都是从最高位到最低位,由此建立Trie树. 利用贪心的思想:对 dis[ ] 建一棵trie树,对于每个数,每次选相反的位置. 即:如果x这一位是1,在tire树上往0跑,反之往1跑. #include<iostream&g

Trie树的java实现

leetcode 地址: https://leetcode.com/problems/implement-trie-prefix-tree/description/ 难度:中等 描述:略 解题思路: Trie树 也就是字典查找树,是一种能够实现在一个字符串集中实现快速查找和匹配的多叉树结构,关于Trie树的深入分析我就不展开了,因为我自己也理解的不深刻^_^,这里只给出Trie树的定义,以及常用的应用场景,然后给出一个简单的java实现,当然代码简洁性和性能上有很大的优化空间. 首先,Trie树

Codeforces Round #371 (Div. 1)

A: 题目大意: 在一个multiset中要求支持3种操作: 1.增加一个数 2.删去一个数 3.给出一个01序列,问multiset中有多少这样的数,把它的十进制表示中的奇数改成1,偶数改成0后和给出的01序列相等(比较时如果长度不等各自用0补齐) 题解: 1.我的做法是用Trie数来存储,先将所有数用0补齐成长度为18位,然后就是Trie的操作了. 2.官方题解中更好的做法是,直接将每个数的十进制表示中的奇数改成1,偶数改成0,比如12345,然后把它看成二进制数10101,还原成十进制是2

AC自动机- 自我总结

AC自动机算法总结  No.1 What's Aho-Corasick automaton? 一种多模式串匹配算法,该算法在1975年产生于贝尔实验室,是著名的多模匹配算法之一. 简单的说,KMP用来匹配一个模式串:但如果现在有多个模式串需要在同一篇文章中出现,现在就需要Aho-Corasick automaton算法了. 不要天真的以为AC自动机为auto-Accept,虽然他能让你AC一些题. No.2 My Understanding About Aho-Corasick automato