代码之家  ›  专栏  ›  技术社区  ›  Dennis Haarbrink

优化Trie实现

  •  3
  • Dennis Haarbrink  · 技术社区  · 16 年前

    为了好玩,我实现了一个 Trie

    它功能齐全,但用数据填充Trie对我来说有点太过了。我将此列表用作数据源: http://www.isc.ro/lists/twl06.zip (在其他地方找到的)。装载大约需要11秒。我最初的实现花了大约15秒,所以我已经给它带来了很好的性能提升,但我仍然不满意:)

    我的问题是:还有什么能给我(实质性的)业绩提升?我不受这种设计的约束,彻底检修是可以接受的。

    class Trie
    {
        private $trie;
        public function __construct(TrieNode $trie = null)
        {
            if($trie !== null) $this->trie = $trie;
            else $this->trie = new TrieNode();
            $this->counter = 0;
        }
        public function add($value, $val = null)
        {
            $str = '';
            $trie_ref = $this->trie;
            foreach(str_split($value) as $char)
            {
                $str .= $char;
                $trie_ref = $trie_ref->addNode($str);
            }
            $trie_ref->value = $val;
            return true;
        }
        public function search($value, $only_words = false)
        {
            if($value === '') return $this->trie;
            $trie_ref = $this->trie;
            $str = '';
            foreach(str_split($value) as $char)
            {
                $str .= $char;
                if($trie_ref = $trie_ref->getNode($str))
                {
                    if($str === $value) return ($only_words ? $this->extractWords($trie_ref) : new self($trie_ref));
                    continue;
                }
                return false;
            }
            return false;
        }
        public function extractWords(TrieNode $trie)
        {
            $res = array();
            foreach($trie->getChildren() as $child)
            {
                if($child->value !== null) $res[] = $child->value;
                if($child->hasChildren()) $res = array_merge($res, $this->extractWords($child));
            }
            return $res;
        }
    }
    class TrieNode
    {
        public $value;
        protected $children = array();
        public function addNode($index)
        {
            if(isset($this->children[$index])) return $this->children[$index];
            return $this->children[$index] = new self();
        }
        public function getNode($index)
        {
            return (isset($this->children[$index]) ? $this->children[$index] : false);
        }
        public function getChildren()
        {
            return $this->children;
        }
        public function hasChildren()
        {
            return count($this->children)>0;
        }
    }
    
    2 回复  |  直到 13 年前
        1
  •  3
  •   Aryabhatta Aryabhatta    16 年前

    不懂php但是,

    方法如下:

       public function add($value, $val = null) 
        { 
            $str = ''; 
            $trie_ref = $this->trie; 
            foreach(str_split($value) as $char) 
            { 
                $str .= $char; 
                $trie_ref = $trie_ref->addNode($str); 
            } 
            $trie_ref->value = $val; 
            return true; 
        } 
        public function search($value, $only_words = false) 
        { 
            if($value === '') return $this->trie; 
            $trie_ref = $this->trie; 
            $str = ''; 
            foreach(str_split($value) as $char) 
            { 
                $str .= $char; 
                if($trie_ref = $trie_ref->getNode($str)) 
                { 
                    if($str === $value) return ($only_words ? $this->extractWords($trie_ref) : new self($trie_ref)); 
                    continue; 
                } 
                return false; 
            } 
            return false; 
        } 
    

    你为什么还需要 $str .= $char $value )而不是O(n)。

    在trie中,通常在遍历字符串的同时遍历trie,即根据当前字符而不是当前前缀查找下一个节点。

        2
  •  1
  •   Princeton Ebanks    11 年前

    我想这个实现是用于插入和查找的键值类型吗?这里有一个处理[英语]单词的。

    class Trie {
    
    
    static function insert_word(Node $root, $text) 
    {
        $v = $root;
        foreach(str_split($text) as $char) {
        $next = $v->children[$char];
            if ($next === null)
            {
                $v->children[$char] = $next = new Node();
            }
            $v = $next;
        }
    
        $v->leaf = true;
    }
    
    
    static function get_words_sorted(Node $node, $text) 
    {
    
        $res = array();  
        for($ch = 0; $ch < 128; $ch++) {
        $child = $node->children[chr($ch)];
    
            if ($child !== null)
            {
                $res = array_merge($res, Trie::get_words_sorted($child, $text . chr($ch)));
    
            }
        }
        if ($node->leaf === true) 
        {
            $res[] = $text;
        }
        return $res;
    
    }
    
    static function search(Node $root, $text) 
    {
        $v = $root;
        while($v !== null)
        {
            foreach(str_split($text) as $char) {
                $next = $v->children[$char];
                if ($next === null)
                {
                    return false;
                }
                else
                {
                    $v = $next;
                }
            }
    
            if($v->leaf === true)
            {
                return true;
            }
            else
            {
                return false;
            }
    
        }
        return false;
    
    }
    
    }
    
    
    class Node {
    
        public $children;
        public $leaf;
    
    
        function __construct()
        {
            $children = Array();
    
        }
    }
    

        $root = new Node();
        $words = Array("an", "ant", "all", "allot", "alloy", "aloe", "are", "ate", "be");
    
    
        for ($i = 0; $i < sizeof($words); $i++)
        {
    
            Trie::insert_word($root, $words[$i]);
        }
    
        $search_words = array("alloy", "ant", "bee", "aren't", "allot");
    
        foreach($search_words as $word)
        {
            if(Trie::search($root, $word) === true)
            {
                echo $word . " IS in my dictionary<br/>";
            }
            else
            {
                echo $word . " is NOT in my dictionary <br/>";
            }
        }
    
    推荐文章