All Downloads are FREE. Search and download functionalities are using the official Maven repository.

META-INF.dirigible.dev-tools.common.Trie.js Maven / Gradle / Ivy

There is a newer version: 10.6.27
Show newest version
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

/**
 * @unrestricted
 */
export class Trie {
  constructor() {
    /** @type {number} */
    this._size;
    /** @type {number} */
    this._root = 0;
    /** @type {!Array>} */
    this._edges;
    /** @type {!Array} */
    this._isWord;
    /** @type {!Array} */
    this._wordsInSubtree;
    /** @type {!Array} */
    this._freeNodes;

    this.clear();
  }

  /**
   * @param {string} word
   */
  add(word) {
    let node = this._root;
    ++this._wordsInSubtree[this._root];
    for (let i = 0; i < word.length; ++i) {
      const edge = word[i];
      let next = this._edges[node][edge];
      if (!next) {
        if (this._freeNodes.length) {
          // No need to reset any fields since they were properly cleaned up in remove().
          next = /** @type {number} */ (this._freeNodes.pop());
        } else {
          next = this._size++;
          this._isWord.push(false);
          this._wordsInSubtree.push(0);
          this._edges.push(/** @type {?} */ ({__proto__: null}));
        }
        this._edges[node][edge] = next;
      }
      ++this._wordsInSubtree[next];
      node = next;
    }
    this._isWord[node] = true;
  }

  /**
   * @param {string} word
   * @return {boolean}
   */
  remove(word) {
    if (!this.has(word)) {
      return false;
    }
    let node = this._root;
    --this._wordsInSubtree[this._root];
    for (let i = 0; i < word.length; ++i) {
      const edge = word[i];
      const next = this._edges[node][edge];
      if (!--this._wordsInSubtree[next]) {
        delete this._edges[node][edge];
        this._freeNodes.push(next);
      }
      node = next;
    }
    this._isWord[node] = false;
    return true;
  }

  /**
   * @param {string} word
   * @return {boolean}
   */
  has(word) {
    let node = this._root;
    for (let i = 0; i < word.length; ++i) {
      node = this._edges[node][word[i]];
      if (!node) {
        return false;
      }
    }
    return this._isWord[node];
  }

  /**
   * @param {string=} prefix
   * @return {!Array}
   */
  words(prefix) {
    prefix = prefix || '';
    let node = this._root;
    for (let i = 0; i < prefix.length; ++i) {
      node = this._edges[node][prefix[i]];
      if (!node) {
        return [];
      }
    }
    /** @type {!Array} */
    const results = [];
    this._dfs(node, prefix, results);
    return results;
  }

  /**
   * @param {number} node
   * @param {string} prefix
   * @param {!Array} results
   */
  _dfs(node, prefix, results) {
    if (this._isWord[node]) {
      results.push(prefix);
    }
    const edges = this._edges[node];
    for (const edge in edges) {
      this._dfs(edges[edge], prefix + edge, results);
    }
  }

  /**
   * @param {string} word
   * @param {boolean} fullWordOnly
   * @return {string}
   */
  longestPrefix(word, fullWordOnly) {
    let node = this._root;
    let wordIndex = 0;
    for (let i = 0; i < word.length; ++i) {
      node = this._edges[node][word[i]];
      if (!node) {
        break;
      }
      if (!fullWordOnly || this._isWord[node]) {
        wordIndex = i + 1;
      }
    }
    return word.substring(0, wordIndex);
  }

  clear() {
    this._size = 1;
    this._root = 0;
    /** @type {!Array>} */
    this._edges = [/** @type {?} */ ({__proto__: null})];
    /** @type {!Array} */
    this._isWord = [false];
    /** @type {!Array} */
    this._wordsInSubtree = [0];
    /** @type {!Array} */
    this._freeNodes = [];
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy