字典树与前缀匹配

14 篇文章 1 订阅
5 篇文章 0 订阅

简介

前缀匹配大家都不陌生,运用也很广泛,常见的应用是输入框的自动提示,像Linux这样的操作系统命令行的自动补全,也是前缀匹配的一个应用。

字典树

字典树有如下性质

1,根节点不包含字符,除根节点意外每个节点只包含一个字符。

2,从根节点到某一个节点,路径上经过的字符连接起来,为该节点对应的字符串。

3,每个节点的所有子节点包含的字符串不相同。

代码实现

字典树节点的定义

    private static class Node {

        Node(char c) {
            this.ch = c;
        }
        
        boolean wordEnd = false;    /*是否是某个单词的最后一个字母*/
        char ch;    /*这个节点所代表的字母*/
        Map<Character, Node> children = new HashMap<>();  /*字典树是哈系树的一种,子节点可以用HashMap来存储*/
    }

字典树的构建

    private final Node root = new Node('\0');  /*需要一个根节点*/

    public void insert(String word) {
        if (word.isEmpty()) {
            return;
        }
        char[] arr = word.toCharArray();
        Node cur = root;
        for (char c : arr) {
            if (!cur.children.containsKey(c)) {
                cur.children.put(c, new Node(c));
            }
            cur = cur.children.get(c);
        }
        cur.wordEnd = true;
    }

字典树的查找

    public Set<String> search(String prefix) {
        char[] arr = prefix.toCharArray();
        Node cur = root;
        Set<String> resultSet = new HashSet<>();
        for (char c : arr) {
            cur = cur.children.get(c);
            if (cur == null)
                break;
        }
        if (cur != null) {
            getAllWords(cur, prefix, resultSet);
        }
        return resultSet;
    }

    private void getAllWords(Node node, String prefix, Set<String> resultSet) {
        if (node.wordEnd) {
            resultSet.add(prefix);
        }
        for (Map.Entry<Character, Node> e : node.children.entrySet()) {
            getAllWords(e.getValue(), prefix + e.getKey(), resultSet);
        }
    }

完整代码

public class TireTree {

    private final Node root = new Node('\0');

    public void insert(String word) {
        if (word.isEmpty()) {
            return;
        }
        char[] arr = word.toCharArray();
        Node cur = root;
        for (char c : arr) {
            if (!cur.children.containsKey(c)) {
                cur.children.put(c, new Node(c));
            }
            cur = cur.children.get(c);
        }
        cur.wordEnd = true;
    }

    public Set<String> search(String prefix) {
        char[] arr = prefix.toCharArray();
        Node cur = root;
        Set<String> resultSet = new HashSet<>();
        for (char c : arr) {
            cur = cur.children.get(c);
            if (cur == null)
                break;
        }
        if (cur != null) {
            getAllWords(cur, prefix, resultSet);
        }
        return resultSet;
    }

    private void getAllWords(Node node, String prefix, Set<String> resultSet) {
        if (node.wordEnd) {
            resultSet.add(prefix);
        }
        for (Map.Entry<Character, Node> e : node.children.entrySet()) {
            getAllWords(e.getValue(), prefix + e.getKey(), resultSet);
        }
    }

    private static class Node {

        Node(char c) {
            this.ch = c;
        }
        
        boolean wordEnd = false;    /*是否是某个单词的最后一个字母*/
        char ch;    /*这个节点所代表的字母*/
        Map<Character, Node> children = new HashMap<>();
    }
}

客户端调用

public class Client {

    private static String[] words = new String[]{
            "assassin",
            "arc",
            "archer",
            "abandon",
            "angel",
            ...
            /* 中间省略一些 */
            ...
            "yummy",
            "zero",
            "zone",
            "zoom"
    };

    public static void main(String[] args) {
        TireTree tireTree = new TireTree();
        for (String word : words) {
            tireTree.insert(word);
        }

        long start, end;
        Scanner sc = new Scanner(System.in);

        while (sc.hasNext()) {
            String word = sc.next();
            start = System.currentTimeMillis();

            System.out.printf("Result set = %s\n", tireTree.search(word));

            end = System.currentTimeMillis();
            System.out.println("Search cost: "+(end - start) + "ms");
        }

    }
}

运行结果

>> app
Result set = [apple, apply]
Search cost: 8ms
>> un
Result set = [unity, unit, until, unix]
Search cost: 0ms
>> ca
Result set = [canada, car, candy, cat]
Search cost: 0ms
>> protect
Result set = [protected, protection, protect]
Search cost: 0ms

这里我还做了一个JS在线Demo的演示,实现的是在输入框输入前缀自动提示

http://demo.wongyotwei.cn/tiretree/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值