关于ternary search tree的复杂度问题

来源:1-1 平衡树和AVL

weixin_慕圣6334738

2021-10-17 03:01:00

bobo老师你好,我遇到了一个关于ternary复杂度的问题但是不太能想出来答案


就是现在我有一个叫TernarySearchTreeAutocomplete的class,这个class里面有两个方法,第一个叫addAll是负责把一个Collection(这个collection里面装了很多strings)的里面所有的string添加到ternary tree里,


第二个方法 addMatches, 是用户给一个 prefix,然后找到,树中所有满足这个prefix的string并且返回一个装有所有matches的list:



然后问题是:


第一个问题:

give a big-theta bound for the worst-case runtime of the addAll and allMatches methods for each implementation,with respect to N, the total number of terms currently in the data structure.

题目假定所有传入addAll方法的string的数量和 prefix 都是constant

第二个问题:

class中allmatch 和collect 背后的思路是怎样 的,  collect那个方法我有点没看懂


class具体代码如下:

package autocomplete;

java.util.Collection;
java.util.List;
java.util.LinkedList;
TernarySearchTreeAutocomplete Autocomplete {
    Node ;

    TernarySearchTreeAutocomplete() {
        = ;
    }

    addAll(Collection<? CharSequence> terms) {
        (CharSequence s : terms) {
            (!contains(s)) {
                = add(, s, );
            }
        }
    }

    Node add(Node node, CharSequence key, depth) {
        curr = key.charAt(depth);
        (node == ) {
            node = Node(curr, );
        }
        (curr < node.) {
            node.= add(node., key, depth);
        } (curr > node.) {
            node.= add(node., key, depth);
        } (depth < key.length() - ) {
            node.= add(node., key, depth + );
        } {
            node.= ;
        }
        node;
    }

    contains(CharSequence key) {
        (key == ) {
            NullPointerException();
        } (key.length() == ) {
            IllegalArgumentException();
        }
        Node node = get(, key, );
        node != && node.;
    }

    Node get(Node node, CharSequence key, depth) {
        (node == ) {
            ;
        }
        curr = key.charAt(depth);
        (curr < node.) {
            get(node., key, depth);
        } (curr > node.) {
            get(node., key, depth);
        } (depth < key.length() - ) {
            get(node., key, depth + );
        } {
            node;
        }
    }

    List<CharSequence> allMatches(CharSequence prefix) {
        (prefix == ) {
            NullPointerException();
        } (prefix.length() == ) {
            IllegalArgumentException();
        }
        List<CharSequence> list = LinkedList<>();
        Node node = get(, prefix, );
        (node == ) {
            list;
        }
        (node.) {
            list.add(prefix);
        }
        collect(node., StringBuilder(prefix), list);
        list;
    }

    collect(Node node, StringBuilder prefix, List<CharSequence> list) {
        (node == ) {
            ;
        }
        collect(node., prefix, list);
        (node.) {
            list.add(prefix.toString() + node.);
        }
        prefix.append(node.);
        collect(node., prefix, list);
        prefix.deleteCharAt(prefix.length() - );
        collect(node., prefix, list);
    }
    Node {
        ;
        ;
        Node ;
        Node ;
        Node ;

        Node(data, isTerm) {
            .= data;
            .= isTerm;
            .= ;
            .= ;
            .= ;
        }
    }
}


写回答

1回答

liuyubobobo

2021-10-17

你的代码部分估计是因为慕课网的 bug,所以格式有问题,我看不懂。你看看能不能怎么调整一下。如果不能的话你回复我一下,我反应给慕课网。


==========


这是一个非常标准的 TST 的实现,我强烈建议你阅读一下《算法4》第五章 Strings 第 2 节 Tries 的第二部分,讲的就是 TST。


https://img.mukewang.com/climg/616b39a9090b52a110001000.jpg


直接抛结论的话:


1)TST 的最差时间复杂度,各个操作是 O(n) 的(类似 BST 的退化)。所以 addAll 和 matchAll 最坏情况都是 O(n^2) 的


2)如果你没有理解 collect 方法,大概率是你没有理解 TST 到底是怎么做存储的。


在 TST 中,只有 mid 代表的字符是匹配的。left 和 right 都是比和当前字符不一致,去走的分支。这是和 Trie 不一样的(Trie 每一个分支都是匹配的。)


所以,在 matchAll 中,首先找到 prefix 对应的 Node,之后,在 collect 中,只有走 mid 分支的时候,prefix 才会添加上当前的字符(走 right 前删去),这样最后,prefix 中就是一个完整的存储的字符,而不再是一个 prefix(所以在 collect 中,prefix 这个变量名不够好。)


我强烈建议你在阅读完《算法4》相应章节,或者网上任意 TST 原理的讲解的内容之后,使用一个小的数据量,试验一下,用单步跟踪的方式看一下,对于你选择的 string 集合,TST 到底是什么样子,相应的 matchAll 到底是如何一步一步找到对应的 prefix 的所有元素的。



继续加油!:)


0
hiuyubobobo
回复
heixin_慕圣6334738
hp>我补充在了原回答中。

h021-10-17
共3条回复

算法与数据结构

波波老师5年集大成之作,算法与数据结构系统学习,考试、面试、竞赛通用

2636 学习 · 1090 问题

查看课程