2012-12-03 13 views
5

Ich versuche eine Trie Implementierung in C++ zu erstellen. Ich kann nicht herausfinden, wie alle Wörter gedruckt werden, die in Trie gespeichert werden.Wie alle Wörter in einem Trie gedruckt werden?

Dies ist, wie ich die TrieNode implementiert habe.

struct TrieNode{ 
    bool isWord; 
    int data; //Number of times Word Occured 
    TrieNode *Child[ALPHABET_SIZE]; //defined as 26 
}; 

Ich weiß, dass ich ein pointer zu dem übergeordneten Knoten speichern könnte, Tiefensuche für alle Knoten in dem isWord==True und rekursiv jedes Wort aus diesen Knoten drucken.

Aber ich frage mich, gibt es eine Möglichkeit, jedes Wort in der Trie mit meiner Implementierung eines TrieNode auszudrucken.

Danke für jede Hilfe.

+0

Was ist 'data'? Ich verstehe 'isWord' und das' Child'-Array (warum nicht 'children'?) Gibt den Kindern ... aber wofür stehen' data'? –

+0

Entschuldigung, zur Klarstellung. Es soll die Anzahl der Male enthalten, die das Wort in einem Textdokument vorkam. – theIrishUser

Antwort

10

Hier ist eine einigermaßen effiziente Version von Konrad Rudolph, ohne davon auszugehen, dass Daten ein Zeichen sind. Ich entfernte auch den O (n^2) Gesamtspeicher, der in Konrads Version zugewiesen wurde, auf Kosten von std::string&. Die Idee besteht darin, das Präfix weiterzuleiten und es bei jeder Rekursion zu modifizieren, indem man die Zeichen auf das Ende drückt und es anschließend wieder öffnet, was schließlich effizienter ist, als es irre zu kopieren.

void traverse(std::string& prefix, TrieNode const& node) { 
    if (node.isWord) 
    print(prefix); 

    for (char index = 0; index < ALPHABET_SIZE; ++index) { 
    char next = 'a'+index; 
    TrieNode const* pChild = node.Child[index]; 
    if (pChild) { 
     prefix.push_back(next); 
     traverse(prefix, *pChild); 
     prefix.pop_back(); 
    } 
    } 
} 
+0

Hinweis: Sie könnten einen 'std :: string & prefix' ohne Verlust der Funktionalität verwenden, und der Code für' print' wäre einfacher. –

+0

Ja, aber dann müsste ich die richtige Syntax nachschlagen, um 'pop_back' für' std :: string' zu fälschen, und ich war in Eile. Anscheinend wurde es seit C++ 11 jedoch hinzugefügt? Ergebnis! – Yakk

+0

Logic war sehr hilfreich für mich. Danke – theIrishUser

6

Sie benötigen Ihren Elternknoten nicht, Ihr Code passt sich durch Rekursion leicht dem Traversal an. Pseudocode:

void traverse(string prefix, TrieNode const& n) { 
    prefix += static_cast<char>(n.data); 

    if (n.isWord) 
     print(prefix); 

    for (auto const next : n.Child) 
     if (next) 
      traverse(prefix, *next); 
} 

Dies ist mehr oder weniger gültig C++. Definieren Sie einfach print entsprechend.

EDIT Als Reaktion auf Yakk Kommentar und Ihre Klarstellung, hier ist eine Version, die das aktuelle Zeichen nicht davon ausgehen, dass data enthält (schlechten Beleg auf meiner Seite!):

void traverse(string const& prefix, TrieNode const& n) { 
    if (n.isWord) 
     print(prefix); 

    for (std::size_t i = 0; i < ALPHABET_SIZE; ++i) 
     if (n.child[i]) 
      traverse(prefix + ('a' + i), *n.child[i]); 
} 

Ich werde verlassen die effizientere Umsetzung zu Yakks Antwort.

+0

Warum nehmen Sie an, dass "Daten" ein Zeichen wären? –

+0

@MatthieuM. Weil OP sagte, dass die Struktur einen Trie darstellt. Was sollte es sonst sein? Sie müssen die Zeichendaten eines Knotens irgendwo speichern. (Aber ja, 'data' sollte vom Typ' char' sein, nicht 'int'). –

+1

@KonradRudolph, siehe meine Antwort - der Index des Child-Zeigers sagt Ihnen, was das nächste Zeichen ist, also brauchen Sie es nicht speichern Sie es tatsächlich in dem Knoten. – Yakk

-1

Ich glaube nicht, dass hier ein Wort benötigt wird. Die Existenz des Zeigers für Kinder reicht aus, um den Trie für verfügbare Wörter im Trie durchqueren zu können. Um ein Wort zu finden, beginnen Sie mit der Wurzel und suchen Sie während eines rekursiven Schritts nach dem aktuellen Zeichen innerhalb des Wortes.

struct trie { 
    trie *children[ALPHABET_SIZE]; 
}; 


void traversal(trie *&t, string &str) { 
    bool is_seen = false; 
    for(int i = 0; i < ALPHABET_SIZE; i++) { 
     if(t->children[i]) { 
      if(!is_seen) { 
       is_seen = true; 
      } 
      str.push_back(t[i]); 
      traversal(t->children[i], str); 
      str.pop_back(); 
     } 
    } 
    if(!is_seen) { 
     cout << str << "\n"; 
    } 

} 
+0

Nicht jeder Knoten ist ein Wort. Sie müssen es markieren oder ein Word_string-Objekt verwenden, um das Wort zu speichern; Leeres Wort bedeutet, dass dieses Wort nicht im Wörterbuch enthalten ist. –

0
void traversePrint(TrieNode* sr,char* out,int index) 
{ 
    if(sr!=NULL) 
    { 
     for(int i=0;i<SIZE;i++) 
     { 
      if(sr->child[i]!=NULL) 
      { 
       out[index] = 'a'+i; 
       traversePrint(sr->child[i],out,index+1); 
      } 
     } 
     if(sr->isEnd) 
     { 
      out[index]='\0'; 
      cout << out << endl; 
     } 
    } 
} 

// Aufruf

char out[MAX_WORD_SIZE]; 
traversePrint(root,out,0); 
Verwandte Themen