zoukankan      html  css  js  c++  java
  • Trie(prefix tree)

    Trie

    Trie 是一种特殊的数据结构,与二叉树类似,只是 Trie 不限子孩子数量。

    Trie 又名字典树,单词查找树,前缀树。我们可以使用 Trie 来构造工作中使用到的 红点系统

    下面以 LeetCode 的第208题 Implement Trie (Prefix Tree) 来讨论实现 Trie 这种特殊的数据结构。

    题目描述

    Implement a trie with insert, search, and startsWith methods.

    Trie trie = new Trie();
    
    trie.insert("apple");
    trie.search("apple");   // returns true
    trie.search("app");     // returns false
    trie.startsWith("app"); // returns true
    trie.insert("app");
    trie.search("app");     // returns true
    

    Note: You may assume that all inputs are consist of lowercase letters a-z.All inputs are guaranteed to be non-empty strings.

    实现 Trie

    假设我们要往 Trie 中加入 ['apple', 'app', 'about', 'bed']。

    在创建 Trie 时,我们以对象 Object 为存储类型,对一个单词字母都是对象的一个属性,然后在每个单词末尾时,我们加多一个单词结尾标识 isEnd

    把对应的单词插入 Trie 后,我们将得到下图所示的 Trie 结构:

    Trie结构

    1. 插入单词

    插入单词时,每一个字母对应一个结点对象,如果没有对应的结点则创建;如果有就在此结点下继续查找。在单词的结尾时,我们需加入单词结束标识 isEnd,以便查找。

    let obj = this.root;
    for (let i = 0; i < word.length; i++) {
      let c = word[i];
      // 没有这个字母结点,创建
      if (!obj[c]) {
        obj[c] = {};
      }
      obj = obj[c];
    }
    // 标识单词结尾
    obj.isEnd = true;
    

    2. 查找单词或前缀

    在查找单词或前缀的时候,需要一步一步的往下查找,如果中途没有任一个结点,则直接返回即可。如果是查找单词,找到了对应的最后一个字母结点后,我们仍需判断结点是否有 isEnd 属性;如果是前缀,则判断是否是一个对象即可。

    // 查找函数
    Trie.prototype.commonSearch = function (word) {
      let obj = this.root;
      for (let char of word.split('')) {
        if (!obj[char]) {
          // 对应对应字母的结点,返回null
          return null;
        } else {
          obj = obj[char];
        }
      }
      // 找到最后一个单词结点,返回结点对象
      return obj;
    };
    

    完整代码附下

    
    /**
     * Initialize your data structure here.
     */
    const Trie = function () {
      this.root = {};
    };
    
    /**
     * Inserts a word into the trie.
     * @param {string} word
     * @return {void}
     */
    Trie.prototype.insert = function (word) {
      let obj = this.root;
      for (let i = 0; i < word.length; i++) {
        let c = word[i];
        if (!obj[c]) {
          obj[c] = {};
        }
        obj = obj[c];
      }
      obj.isEnd = true;
    };
    
    /**
     * Returns if the word is in the trie.
     * @param {string} word
     * @return {boolean}
     */
    Trie.prototype.search = function (word) {
      let obj = this.commonSearch(word);
      return obj && obj.isEnd ? true : false;
    };
    
    /**
     * Returns if there is any word in the trie that starts with the given prefix.
     * @param {string} prefix
     * @return {boolean}
     */
    Trie.prototype.startsWith = function (prefix) {
      let obj = this.commonSearch(prefix);
      return !!obj;
    };
    
    /**
     * @param {string} prefix
     * @return {any}
     */
    Trie.prototype.commonSearch = function (word) {
      let obj = this.root;
      for (let char of word.split('')) {
        if (!obj[char]) {
          return null;
        } else {
          obj = obj[char];
        }
      }
      return obj;
    };
    
  • 相关阅读:
    SignalR2结合ujtopo实现拓扑图动态变化
    SignalR2简易数据看板演示
    使用SignalR 2进行服务器广播
    使用SignalR实时Web应用程序
    ZooKeeper安装
    MongoDB安装
    线程安全与非线程安全
    监听器,事件对象,事件源
    Graphics与Canvas
    JDialog
  • 原文地址:https://www.cnblogs.com/AuKing/p/13993904.html
Copyright © 2011-2022 走看看