logo

データ構造を試す |挿入して検索

データ構造を試す 動的な文字列セットを格納するために使用されるツリー状のデータ構造です。効率的な目的でよく使用されます 検索 そして ストレージ 大規模なデータセット内のキーの数。などの操作をサポートする構造です。 挿入 検索 、 そして 削除 キーの数が多いため、コンピュータ サイエンスや情報検索などの分野で貴重なツールになります。この記事では、 挿入と検索 Try Data Structure での操作。

データ構造を試す

データ構造を試す



目次

  • Trie ノードの表現
  • Trie ノードの表現:

    データ構造を試す エッジで接続されたノードで構成されます。各ノードは文字または文字列の一部を表します。トライの開始点であるルート ノードは空の文字列を表します。ノードから発せられる各エッジは、特定の文字を表します。ルートからノードへのパスは、トライに格納されている文字列のプレフィックスを表します。

    英語のアルファベットのノードを表す簡単な構造は次のとおりです。



    bash 読み取りファイル
    C++
    struct TrieNode {  // pointer array for child nodes of each node  TrieNode* childNode[26];  // Used for indicating ending of string  bool wordEnd;  TrieNode()  {  // constructor  // initialize the wordEnd variable with false  // initialize every index of childNode array with  // NULL  wordEnd = false;  for (int i = 0; i < 26; i++) {  childNode[i] = NULL;  }  } };>
    ジャワ
    public class TrieNode {    // Array for child nodes of each node  TrieNode[] childNode;    // Used for indicating the end of a string  boolean wordEnd;  // Constructor  public TrieNode() {  // Initialize the wordEnd variable with false  wordEnd = false;  // Initialize every index of the childNode array with null  childNode = new TrieNode[26];  for (int i = 0; i < 26; i++) {  childNode[i] = null;  }  } }>

    Trie データ構造に単語を挿入するプロセスを見てみましょう。 Trie とそのノード構造の基本についてはすでに説明しました。

    Java 演算子

    単語の挿入を視覚的に表現したものは次のとおりです。 そして そして の上 Try データ構造に変換します。




    Try データ構造での挿入操作


    Trie データ構造に と を挿入します。

    逆参照ポインタ c
    • ルート ノードから開始します。 ルート ノードには関連付けられた文字がありません。 ワードエンド 値は 0 、この時点で完全な単語が終わっていないことを示します。
    • 最初の文字 a: ‘を使用してインデックスを計算します 「a」 – 「a」 = 0 。かどうかを確認してください。 子ノード[0] ヌル 。そうなったので、キャラクターで新しい TrieNode を作成します ある ワードエンド に設定 0 、およびポインターの空の配列。この新しいノードに移動します。
    • 2 番目の文字 n: 次を使用してインデックスを計算します 「n」 – 「a」 = 13 。どうかを確認してください 子ノード[13] ヌル 。ですので、そのキャラクターで新しい TrieNode を作成します n ワードエンド に設定 0 、およびポインターの空の配列。この新しいノードに移動します。
    • 3 番目の文字 d: ‘を使用してインデックスを計算します d’ – 「a」 = 3 。どうかを確認してください 子ノード[3] ] は ヌル 。ですので、そのキャラクターで新しい TrieNode を作成します d ワードエンド に設定 1 (単語を示して そして ここで終わります)。

    Trie データ構造に ant を挿入する:

    • ルート ノードから開始します。 ルート ノードにはデータは含まれませんが、挿入されたすべての文字列の最初の文字をすべて追跡します。
    • 最初の文字 a: ‘を使用してインデックスを計算します 「a」 – 「a」 = 0 。かどうかを確認してください。 子ノード[0] ヌル 。私たちはすでに ある 前回の挿入で作成されたノード。したがって、既存のものに移動します ある ノード。
    • 最初の文字 n: ‘を使用してインデックスを計算します n' – 'a' = 13 。どうかを確認してください 子ノード [13]は ヌル 。そうではないので、既存のものに移動してください n ノード。
    • 2 番目の文字 t: 次を使用してインデックスを計算します 「t」 – 「a」 = 19 。どうかを確認してください 子ノード [19]は ヌル 。ですので、そのキャラクターで新しい TrieNode を作成します t ワードエンド に設定 1 (アリという単語がここで終わることを示します)。

    以下は、Trie データ構造への文字列の挿入の実装です。

    C++
    #include  using namespace std; struct TrieNode {  // pointer array for child nodes of each node  TrieNode* childNode[26];  // Used for indicating ending of string  bool wordEnd;  TrieNode()  {  // constructor  // initialize the wordEnd variable with false  // initialize every index of childNode array with  // NULL  wordEnd = false;  for (int i = 0; i < 26; i++) {  childNode[i] = NULL;  }  } }; void insert_key(TrieNode* root, string& key) {  // Initialize the currentNode pointer  // with the root node  TrieNode* currentNode = root;  // Iterate across the length of the string  for (auto c : key) {  // Check if the node exist for the current  // character in the Trie.  if (currentNode->childNode[c - 'a'] == NULL) { // 現在のキャラクターのノードが存在しない場合、 // 新しいノードを作成します TrieNode* newNode = new TrieNode();  // 新しく作成されたノードの参照を // 保持します。  currentNode->childNode[c - 'a'] = newNode;  } // ここで、現在のノード ポインタを // 新しく作成されたノードに移動します。  currentNode = currentNode->childNode[c - 'a'];  } // 最後の currentNode の wordEndCount をインクリメントします。 // ポインターは、 // currentNode で終わる文字列があることを意味します。  currentNode->wordEnd = 1; }>>

    時間計算量: O(単語数 * 単語の最大長)
    補助スペース: O(単語数 * 単語の最大長)

    Trie データ構造内のキーの検索は、挿入操作と似ています。ただし、それのみ 文字を比較して下に移動します 。文字列の終わりまたはトライ内のキーの欠如により、検索が終了する可能性があります。

    Trie データ構造内で検索するための段階的なアプローチ:

    Linuxファイルシステム
    • ルートノードから開始します。これは、トライ内のすべての検索の開始点です。
    • 検索している単語の文字に基づいてトライを横断します。各文字について、トライの対応する分岐をたどります。ブランチが存在しない場合、その単語はトライに存在しません。
    • 単語の末尾に到達し、wordEnd フラグが 1 に設定されている場合、その単語は見つかったことになります。
    • 単語の末尾に到達し、wordEnd フラグが 0 の場合、その単語は、既存の単語とプレフィックスを共有していても、トライ内に存在しません。

    検索ワードを視覚的に表現したものは次のとおりです お父さん Try データ構造内:

    単語が正常に挿入されたと仮定しましょう そして の上 、 そして お父さん Trie に入力すると、Trie データ構造内で特定の単語を検索する必要があります。言葉を検索してみましょう お父さん :


    Try データ構造での検索操作


    • ルートノードから始めます。
    • 文字「d」に対応する分岐をたどります。
    • 文字 a’ に対応する分岐をたどります。
    • 文字「d」に対応する分岐をたどります。
    • 言葉の終わりに達すると、 ワードエンド 旗は 1 。この意味は お父さん トライに存在します。

    以下は、Trie データ構造での検索文字列の実装です。

    C++
    #include  using namespace std; struct TrieNode {  // pointer array for child nodes of each node  TrieNode* childNode[26];  // Used for indicating ending of string  bool wordEnd;  TrieNode()  {  // constructor  // initialize the wordEnd variable with false  // initialize every index of childNode array with  // NULL  wordEnd = false;  for (int i = 0; i < 26; i++) {  childNode[i] = NULL;  }  } }; bool search_key(TrieNode* root, string& key) {  // Initialize the currentNode pointer  // with the root node  TrieNode* currentNode = root;  // Iterate across the length of the string  for (auto c : key) {  // Check if the node exist for the current  // character in the Trie.  if (currentNode->childNode[c - 'a'] == NULL) { // 指定された単語が Trie に存在しません return false;  } // currentNode ポインタを、 // 現在のキャラクタの既存のノードに移動します。  currentNode = currentNode->childNode[c - 'a'];  return (currentNode->wordEnd == true); }>>

    時間計算量: O(単語数 * 単語の最大長)
    補助スペース: O(単語数 * 単語の最大長)

    文字列整数

    の助けを借りてルートノードを作成します トライノード() コンストラクタ。

  • トライに挿入する必要がある文字列のコレクションを文字列のベクトルに格納します。 到着しました
  • Trie にすべての文字列を挿入する の助けを借りて 挿入キー() 関数、
  • を利用して文字列を検索する 検索キー() 関数。

上記のアプローチの実装を以下に示します。

C++
#include  using namespace std; struct TrieNode {  // pointer array for child nodes of each node  TrieNode* childNode[26];  // Used for indicating ending of string  bool wordEnd;  TrieNode()  {  // constructor  // initialize the wordEnd variable with false  // initialize every index of childNode array with  // NULL  wordEnd = false;  for (int i = 0; i < 26; i++) {  childNode[i] = NULL;  }  } }; void insert_key(TrieNode* root, string& key) {  // Initialize the currentNode pointer  // with the root node  TrieNode* currentNode = root;  // Iterate across the length of the string  for (auto c : key) {  // Check if the node exist for the current  // character in the Trie.  if (currentNode->childNode[c - 'a'] == NULL) { // 現在のキャラクターのノードが存在しない場合、 // 新しいノードを作成します TrieNode* newNode = new TrieNode();  // 新しく作成されたノードの参照を // 保持します。  currentNode->childNode[c - 'a'] = newNode;  } // ここで、現在のノード ポインタを // 新しく作成されたノードに移動します。  currentNode = currentNode->childNode[c - 'a'];  } // 最後の currentNode の wordEndCount をインクリメントします。 // ポインターは、 // currentNode で終わる文字列があることを意味します。  currentNode->wordEnd = 1; } bool search_key(TrieNode* root, string& key) { // currentNode ポインタを // ルート ノード TrieNode* currentNode = root; で初期化します。  // 文字列の長さ全体で繰り返します for (auto c : key) { // トライ内の現在の文字に対するノードが // 存在するかどうかを確認します。  if (currentNode->childNode[c - 'a'] == NULL) { // 指定された単語が Trie に存在しません return false;  } // currentNode ポインタを、 // 現在のキャラクタの既存のノードに移動します。  currentNode = currentNode->childNode[c - 'a'];  return (currentNode->wordEnd == true); } // ドライバー コード int main() { // Trie のルート ノードを作成します TrieNode* root = new TrieNode();  // 挿入したい文字列を // Trie ベクトルに格納しますinputStrings = { 'and', 'ant', 'do', 'geek', 'dad', 'ball' };  // トライ内の挿入操作の数 int n = inputStrings.size();  for (int i = 0; i< n; i++) {  insert_key(root, inputStrings[i]);  }  // Stores the strings that we want to search in the Trie  vectorsearchQueryStrings = { 'do', 'geek', 'bat' };  // Trie 内の検索操作の数 int searchQueries = searchQueryStrings.size();  for (int i = 0; i< searchQueries; i++) {  cout << 'Query String: ' << searchQueryStrings[i]  << '
';  if (search_key(root, searchQueryStrings[i])) {  // the queryString is present in the Trie  cout << 'The query string is present in the '  'Trie
';  }  else {  // the queryString is not present in the Trie  cout << 'The query string is not present in '  'the Trie
';  }  }  return 0; }>
ジャワ
class TrieNode {  TrieNode[] childNode;  boolean wordEnd;  TrieNode()  {  childNode = new TrieNode[26];  wordEnd = false;  } } class Trie {  TrieNode root;  Trie() { root = new TrieNode(); }  // Function to insert a key into the Trie  void insert(String key)  {  TrieNode currentNode = root;  for (int i = 0; i < key.length(); i++) {  int index = key.charAt(i) - 'a';  if (currentNode.childNode[index] == null) {  currentNode.childNode[index]  = new TrieNode();  }  currentNode = currentNode.childNode[index];  }  currentNode.wordEnd = true;  }  // Function to search for a key in the Trie  boolean search(String key)  {  TrieNode currentNode = root;  for (int i = 0; i < key.length(); i++) {  int index = key.charAt(i) - 'a';  if (currentNode.childNode[index] == null) {  return false;  }  currentNode = currentNode.childNode[index];  }  return currentNode.wordEnd;  } } public class Main {  public static void main(String[] args)  {  Trie trie = new Trie();  String[] inputStrings  = { 'and', 'ant', 'do', 'geek', 'dad', 'ball' };  // Insert each string into the Trie  for (String str : inputStrings) {  trie.insert(str);  }  String[] searchQueryStrings  = { 'do', 'geek', 'bat' };  // Search for each string and print whether it is  // found in the Trie  for (String query : searchQueryStrings) {  System.out.println('Query String: ' + query);  if (trie.search(query)) {  System.out.println(  'The query string is present in the Trie');  }  else {  System.out.println(  'The query string is not present in the Trie');  }  }  } }>
パイソン
class TrieNode: def __init__(self): self.childNode = [None] * 26 self.wordEnd = False class Trie: def __init__(self): self.root = TrieNode() # Function to insert a key into the Trie def insert(self, key): currentNode = self.root for char in key: index = ord(char) - ord('a') if not currentNode.childNode[index]: currentNode.childNode[index] = TrieNode() currentNode = currentNode.childNode[index] currentNode.wordEnd = True # Function to search for a key in the Trie def search(self, key): currentNode = self.root for char in key: index = ord(char) - ord('a') if not currentNode.childNode[index]: return False currentNode = currentNode.childNode[index] return currentNode.wordEnd if __name__ == '__main__': trie = Trie() inputStrings = ['and', 'ant', 'do', 'geek', 'dad', 'ball'] # Insert each string into the Trie for word in inputStrings: trie.insert(word) searchQueryStrings = ['do', 'geek', 'bat'] # Search for each string and print whether it is found in the Trie for query in searchQueryStrings: print('Query String:', query) if trie.search(query): print('The query string is present in the Trie') else: print('The query string is not present in the Trie')>
JavaScript
class TrieNode {  constructor() {  // Initialize the childNode array with 26 nulls  this.childNode = Array(26).fill(null);  // Initialize wordEnd to the false indicating that no word ends here yet  this.wordEnd = false;  } } class Trie {  constructor() {  // Initialize the root node of the Trie  this.root = new TrieNode();  }  // Function to insert a key into the Trie  insert(key) {  // Start from the root node  let currentNode = this.root;  for (let i = 0; i < key.length; i++) {  const index = key.charCodeAt(i) - 'a'.charCodeAt(0);  if (currentNode.childNode[index] === null) {  currentNode.childNode[index] = new TrieNode();  }  // Move to the next node in the Trie  currentNode = currentNode.childNode[index];  }  // Mark the end of the word  currentNode.wordEnd = true;  }  // Function to search for a key in the Trie  search(key) {  // Start from the root node  let currentNode = this.root;  // Iterate through each character in the key  for (let i = 0; i < key.length; i++) {  const index = key.charCodeAt(i) - 'a'.charCodeAt(0);  if (currentNode.childNode[index] === null) {  return false;  }  // Move to the next node in the Trie  currentNode = currentNode.childNode[index];  }  // Return true if the end of the word is marked otherwise false  return currentNode.wordEnd;  } } // Driver code const trie = new Trie(); const inputStrings = ['and', 'ant', 'do', 'geek', 'dad', 'ball']; // Insert each string into the Trie inputStrings.forEach((str) =>trie.insert(str)); const searchQueryStrings = ['do', 'geek', 'bat']; // 各文字列を検索し、Trie で見つかったかどうかを出力します。 searchQueryStrings.forEach((query) => { console.log(`Query String: ${query}`); if (trie.search(query)) { console.log('クエリ文字列はトライに存在します'); } else { console.log('クエリ文字列はトライに存在しません') } });>>

出力
Query String: do The query string is present in the Trie Query String: geek The query string is present in the Trie Query String: bat The query string is not present in the Trie>

削除してみてください
  • トライの内容を表示する
  • Trieを使用したオートコンプリート機能
  • すべてのサフィックスのトライを使用したパターン検索
  • 練習問題:

    • 最小単語区切り
    • バイナリ行列の一意の行
    • 個別の部分文字列の数
    • ワードボグル
    • Trie を使用した文字列 (または単語) の配列の並べ替え