2008-12-08 25 views
9

Tôi phải thực hiện một Trie tự chế và tôi bị mắc kẹt trên phần Iterator. Tôi dường như không thể tìm ra phương pháp tăng cho trie.Bị kẹt trên một Iterator Thực hiện của một Trie

Tôi hy vọng ai đó có thể giúp tôi làm rõ mọi thứ.

Dưới đây là các mã cho Iterator:

template <typename T> class Trie<T>::IteratorPrefixe{ 
friend class Trie<T>; 
public: 
    IteratorPrefixe() : tree(NULL), currentNode(NULL), currentKey("") {}; 
    pair<string, T*> operator*() {return make_pair(currentKey, currentNode -> element);} ; 
    IteratorPrefixe operator++()throw(runtime_error); 
    void operator=(IteratorPrefixe iter) {tree = iter.tree; currentNode = iter.currentNode; currentKey = iter.currentKey;}; 
    bool operator==(IteratorPrefixe iter) {return tree == iter.tree && currentNode == iter.currentNode;}; 
    bool operator!=(IteratorPrefixe iter) {return tree != iter.tree || currentNode != iter.currentNode;}; 
private: 
    Trie<T> * tree; 
    Trie<T> * currentNode; 
    string currentKey; 
}; 

Và đây là Trie tôi:

template <typename T> class Trie { 
friend class IteratorPrefixe; 
public: 
    // Create a Trie<T> from the alphabet of nbletters, where nbletters must be 
    // between 1 and NBLETTERSMAX inclusively 
    Trie(unsigned nbletters) throw(runtime_error); 

    // Add a key element of which is given in the first argument and content second argument 
    // The content must be defined (different from NULL pointer) 
    // The key is to be composed of valid letters (the letters between A + inclusive and exclusive nbletters 
    //  Eg if nblettres is 3, a, b and c are the only characters permitted; 
    //   If nblettres is 15, only the letters between a and o inclusive are allowed. 
    // Returns true if the insertion was achieved, returns false otherwise. 
    bool addElement(string, T*) throw(runtime_error); 
    // Deletes a key element of which is given as an argument and returns the contents of the node removed 
    // The key is to be composed of letters valid (see above) 
    // Can also delete at the same time the reference of the ancestors, if these ancestors are no longer used. 
    // Returns NULL if the item has no delete 
    T* removeElement(string cle) throw(runtime_error); 
    // Find a key element of which is given as an argument and returns the associated content 
    // The key is to be composed of letters valid (see above) 
    // Returns NULL if the key does not exist 
    T* searchElement(string cle) throw(); 
    // Iterator class to browse the Trie <T> in preorder mode 
    class IteratorPrefixe; 
    // Returns an iterator pointing to the first element 
    IteratorPrefixe pbegin() throw(runtime_error); 
    // Returns an iterator pointing beyond the last item 
    IteratorPrefixe pend() throw(); 

private: 
    unsigned nbLetters; 
    T* element; 
    vector<Trie<T> *> childs; 
    Trie<T> * parent; 

    // This function removes a node and its ancestors if became unnecessary. It is essentially the same work 
    // as deleteElement that is how to designate remove a node that is changing. Moreover, unlike 
    // deleteElement, it does not return any information on the node removed. 
    void remove(Trie<T> * node) throw(); 

    // This function is seeking a node based on a given key. It is essentially the same work 
    // searchElement but that returns a reference to the node found (or null if the node does not exist) 
    // The key is to be composed of letters valid (see above) 
    Trie<T>* search(string key) throw(runtime_error); 
}; 

Trả lời

6

Tôi rất vui khi thấy Tries vẫn dạy, họ là một cấu trúc dữ liệu quan trọng đó là thường bị bỏ quên.

Có thể có một vấn đề về thiết kế trong mã của bạn vì bạn có thể có một lớp Trie và một lớp Node. Cách bạn viết nó có vẻ như mỗi nút trong Trie của bạn là trie của riêng nó, mà có thể làm việc, nhưng sẽ làm cho một số điều phức tạp.

Nó không thực sự rõ ràng từ câu hỏi của bạn những gì nó là bạn đang gặp vấn đề với: tìm thứ tự, hoặc tìm mã thực tế?

Từ tên của trình lặp, có vẻ như nó sẽ phải hoạt động theo thứ tự tiền tố. Vì trie của bạn lưu trữ các từ và các nút con của nó được sắp xếp theo các chữ cái, sau đó bạn về cơ bản dự kiến ​​sẽ đi qua tất cả các từ theo thứ tự chữ cái. Mỗi lần tăng sẽ đưa bạn đến từ tiếp theo.

Sự bất biến về trình lặp của bạn là tại bất kỳ thời điểm nào (miễn là nó hợp lệ), nó phải trỏ vào một nút có ký tự "terminator" cho một từ hợp lệ. Tìm kiếm từ đó chỉ đơn thuần liên quan đến việc quét lên trên qua chuỗi gốc cho đến khi bạn tìm thấy toàn bộ chuỗi của mình. Chuyển sang từ tiếp theo có nghĩa là thực hiện tìm kiếm DFS: đi lên một lần, quét tìm liên kết trong "anh em" sau này, xem bạn có tìm thấy một từ không, nếu không đệ quy lên, v.v.

+0

Câu trả lời hay. Là một sang một bên, đôi khi nó là tốt hơn để lưu trữ các mục công cụ theo thứ tự ngược lại, giống như tên miền. – Josh

2

Bạn có thể muốn xem triển khai Trie tại địa chỉ:

Cụ thể, bạn có thể tìm thấy những discussion tôi đã có trên comp.lang.C++ kiểm duyệt về việc thực hiện lặp cho của Trie một cách phù hợp STL, mà là một vấn đề kể từ đó. tất cả các container stl không may bị buộc phải sử dụng std :: pair <> và trình lặp đó phải chứa giá trị thay vì chỉ là một tham chiếu đến nút đơn trong trie.

+0

Không có gì để tìm thấy trên trang của bạn? – Enno

+0

Xin lỗi - máy chủ đã được di chuyển, url sẽ hoạt động ngay bây giờ. Nguồn này có trong mercurial tại http://opensource.jdkoftinoff.com/hg-oss/jdktrie và cũng có trong svn tại http://opensource.jdkoftinoff.com/jdks/svn/trunk/jdktrie/trunk – jdkoftinoff

+1

Các liên kết đó đã chết một lần nữa:/ – thirtythreeforty

0

Đối với một điều, mã được hiển thị không thực sự mô tả một trie. Thay vào đó, nó dường như là một cây có chứa một cặp phần tử trong mỗi nút (T*unsigned). Bạn có thể theo kỷ luật sử dụng một cây bộ dữ liệu như một trie, nhưng nó chỉ theo quy ước, chứ không phải thực thi. Đây là một phần lý do tại sao bạn gặp khó khăn trong việc thực hiện operator++.

Những gì bạn cần làm là có mỗi Trie chứa ADT phân tách bên trái trái, chứ không phải chỉ là các phần tử thô. Đó là một lớp trừu tượng thường được tìm thấy trong các ngôn ngữ chức năng (ví dụ: Scala's Either). Thật không may, hệ thống kiểu của C++ không đủ mạnh để làm điều gì đó thanh lịch.Tuy nhiên, không có gì là ngăn cản bạn làm điều này:

template <class L, class R> 
class Either 
{ 
public: 

    Either(L *l) : left(l), right(0) 
    {} 

    Either(R *r) : left(0), right(r) 
    {} 

    L *get_left() const 
    { 
     return left; 
    } 

    R *get_right() const 
    { 
     return right; 
    } 

    bool is_left() const 
    { 
     return left != 0; 
    } 

    bool is_right() const 
    { 
     return right != 0; 
    } 

private: 
    L *left; 
    R *right; 
}; 

Sau đó Trie của bạn dữ liệu các thành viên sẽ được xác định như sau:

private: 
    Either<unsigned, T*> disjoint; 

    vector<Trie<T> *> children; // english pluralization 
    Trie<T> * parent; 

Tôi đang chơi nhanh và lỏng lẻo với con trỏ của bạn, nhưng bạn có được ý chính của những gì tôi đang nói. Bit quan trọng là không có nút nhất định nào có thể chứa cả hai an unsignedT*.

Hãy thử điều này và xem điều đó có hữu ích không. Tôi nghĩ rằng bạn sẽ thấy rằng có thể dễ dàng xác định xem bạn đang ở trên một chiếc lá hay một chi nhánh sẽ giúp bạn rất nhiều trong nỗ lực của bạn để lặp lại.

Các vấn đề liên quan