2012-01-18 7 views
3

すべての一意のサブストリングを印刷する必要があります。だから私はtrieを構築するが、どのように私はすべてのサブ文字列を印刷することができないのか把握することができません。 たとえば、入力がaabaacの場合は、"a", "aa", "aab", "aac", "ab", "ac", "b", "c"と表示されます。データ構造とすべてのサブストリングを印刷する

基本的には、文字列のセットから一意の部分文字列を取得する方法を見つける必要があります。私は考えているtrieは良い方法ですtrieを取るだろうO(n)

私のコードはトライを構築することです。

#include <string> 
#include <iostream> 
#include <vector> 

struct trie_node { 
    trie_node *(next[26]); 

    trie_node() { 
     for (int i = 0; i < 26; ++i) { 
      next[i] = (trie_node*)0; 
     } 
    } 
}; 

trie_node *root; 
char cur_substring[2000]; 
void build_trie(std::string& input) { 
    trie_node *ptrie = root; 
    for (std::string::iterator it = input.begin(); it != input.end(); ++it) { 
     int i = *it - 'a'; 
     if (ptrie->next[i] == (trie_node*)0) 
      ptrie->next[i] = new trie_node; 
     ptrie = ptrie->next[i]; 
    } 
} 

void print_sub_strings(trie_node *p_trie, int pos) { 
    for (int i = 0; i < 26; i++) { 
     if (p_trie->next[i] != (trie_node*)0) { 
      cur_substring[pos] = i + 'a'; 
      print_sub_strings(p_trie->next[i], pos + 1); 
     } 
    } 
} 

UPDATE 1

私は私のコードを再書いなった入力に基づいて

が、また、動作しているようですしません。あなたが適切にあなたの元の文字列のすべての可能なサブ文字列を与えるトライをトラバース、すべての文字列を考慮してトライ構造を構築した場合

#include <string> 
#include <iostream> 
#include <vector> 

const int ALPHABET_SIZE = 26; 
char text[2000]; 
int LEN; 

struct trie_node_t { 
    trie_node_t*child_list[ALPHABET_SIZE]; 
    trie_node_t() { 
     for(int index = 0; index < ALPHABET_SIZE; index++) 
      child_list[index] = (trie_node_t*)0; 
    } 
}; 

class Trie { 
public: 
    Trie():m_root(new trie_node_t) { 
    } 

    ~Trie() { 
     _delete(m_root); 
    } 

    void _insert(int pos) { 
     int lcv, index; 
     trie_node_t* t = m_root; 
     for(lcv = pos; lcv < LEN; lcv++) { 
      index = text[lcv] - 'a'; 
      if (t->child_list[index] == (trie_node_t*)0) { 
       t->child_list[index] = new trie_node_t; 
      } 
      t = t->child_list[index]; 
     } 
    } 
    void insert() { 
     for (int i = 0; i < LEN; i++) { 
      _insert(i); 
     } 
    } 

    void iterate() { 
     _iterate(m_root, ""); 
    } 

    void _iterate(trie_node_t *t, std::string prefix) {   
     for (int i = 0; i < ALPHABET_SIZE; i++) { 
      if (t->child_list[i] != (trie_node_t*)0) { 
       prefix += 'a' + i; 
       std::cout << prefix << std::endl; 
       _iterate(t->child_list[i], prefix); 
      } 
     } 
    } 
private: 
    int node_count; 
    trie_node_t* m_root; 

    void _delete (trie_node_t* t) { 
     int index; 
     if (t != (trie_node_t*)0) { 
      for(index = 0; index < ALPHABET_SIZE; index++) 
       _delete(t->child_list[index]); 
      delete t; 
     } 
    }  
}; 

int main (int argc, char** argv) { 
    Trie *pTrie = new Trie(); 

    strcpy(text,"aab"); 
    LEN = strlen(text); 
    pTrie->insert(); 

    strcpy(text,"aac"); 
    LEN = strlen(text); 
    pTrie->insert(); 

    pTrie->iterate(); 
} 

出力は、

a 
aa 
aab 
aabc 
aab 
aabc 
ab 
abc 
Press any key to continue . . . 
+0

一部の文字列にはO(n^2)個の部分文字列が含まれているため、O(n)時間内にすべての部分文字列を出力することはできません。たとえば、abcdefg ... zとなります。 – templatetypedef

+0

@templatetypedef、私は同意しますが、トライの繰り返しはすべて私にすべての部分文字列を与えるでしょう。私がトライ絵を描くと、ツリーを正しくトラバースすればすべての部分文字列を得ることができます。 – Avinash

+0

コードの最初の追加コメント:_または__で始まる識別子は使用しないでください。 _と__で始まるすべての識別子は予約されています。また、あなたのコードはあなたが定期的にCをやっているように見え、現在C++をやっています。 C++のイディオムを学ぼうとすると、多くの場合、本当に役立ちます。 – LiKao

答えて

0

文字列のすべての部分文字列(最初の文字で始まらない文字列も含む)を取得する場合は、文字列の接尾辞をトライに格納する必要があります。

I.e.何をしたら、完全な文字列を格納し、最初の文字なしで文字列を格納し、次に2番目の文字などを使用しないで保存します。この方法では、繰り返しの部分文字列の削除を正しく処理し、 。ただし、これはO(n)ではないことに注意してください。他の人が正しく指摘しているように、この種の問題は不可能です。

しかし、この種のデータ構造の通常の使用例は、部分文字列の高速取得です。サフィックスを開始した位置(各位置が複数ある場合もあります)を各出発時に格納すると、任意の長い部分文字列内のすべての部分文字列をすべて簡単に見つけることができます。ここでは、フルテキスト検索などの検索作業に力を入れています。

EDIT

あなたの更新の後、あなたはループ内でローカルプレフィックス変数に追加されているので、あなたは、ループの中で次の子を調査するとき、それは間違った値を持つことになります。あなたの例にあるべきでない追加の値は、これによって引き起こされます。それぞれの反復で新しい接頭辞変数を作成し、その接頭辞を渡す必要があります。追加のデバッグ出力hereで修正されたコードを見つけることができます。

0

まあです。重複は、Triesの構造のために自動的に処理されます。

+0

これはまさに私が重複を扱うことを考えていたことです。しかし今、私はトライを作りました。どのようにそれを反復して、すべての部分文字列を得ることができますか? – Avinash

+0

@Avinash:私が見るところでは、すべてのノードをたどるように再帰的な部分が正しくあります。ここで、1回の再帰呼び出しを入力するとすぐに、cur_substringの内容を出力します。これは仕事をするはずです。 –

+0

a aa aab aacこれは私が得るものですが、私はabとacも必要です。 – Avinash

1

Trieは異なる文字列を格納しますが、最初の文字から始まっていないサブ文字列は気にしません。 Trieに格納されている各文字列は、ルートから非ルートノードへと始まります。非ルートノードから別の非ルートノードにサブ文字列を取得しようとすることはできますが、サブ文字列が一意であることを保証することはできません。

たとえば、文字列「abab」が格納されます。あなたはユニークな文字列を取得することができますABABA、非ルートノードへのルートからABAB。あなたは、非ルート・ノードから始まる文字列を拾うしようとすると、取得します

  • B AB
  • BA B
  • BAB
  • AB b
  • ab ab
  • ABA B
ABBが既に存在している

。これを避けるために、最後の文字にすべてのサブストリングの終わりを格納しようとすることができます。例えば、新しい文字列は " abcdab" 来ている、あなたは " abcdab"、 "bcdab"、 "CDAB"、 "DAB" を格納する必要があり、 "AB" と " b "である。とにかく、これはO(n^2)ではなくO(n^2)になります。

+0

複雑さについて:とにかくサブストリングの数をO(n^2)よりもO(n^2)に近づけると、それは問題ではないと思います:)サブストリングの列挙を 'abab' 「あなたはユニークな文字列a、ab、aba、ababを[...]から得ることができます。 –

+0

私は、ルートから非ルートノードまで、a、ab、aba、ababしか得られないことを意味します。 Trieの標準的な使い方では、バとバブを得ることはできません。 – Ddavid

+0

説明のためにああありがとう、申し訳ありません、私の脳はゆっくりと目を覚ましています。 –

関連する問題