Preorder traversal through Morse code BST

后端 未结 1 1144
無奈伤痛
無奈伤痛 2020-12-22 09:22

In c++ I am working on two trees, 1 is alphabetical a-z with nums and characters 0-9 , . ?

The other tree is the equivalent of those characters in Morse code. I have

相关标签:
1条回答
  • 2020-12-22 09:48

    Did you notice that your insert() method does not handle the case of "key-collision" (due to the missing else branch for the last if). This can be used to detect if a key shall be inserted which is already in tree. As it is, such duplicated inserts are simply ignored (which is IMHO not the worst possible behavior).

    In my sample below, I decided for a different option: let insert() return a boolean value which reports about success of insertion.

    Unfortunately, you didn't provide an MCVE.

    Thus, I filled the gaps with own code where (for my personal joy) I involved templates. Hopefully, this won't bring in too much confusion.

    However, after playing around with your sample data, I came to the conclusion that your code does probably the right – may be not, what you expected. Eventually, you have a false expectation. Or, you correctly solved the false problem. I re-read your question multiple times but didn't get I clear idea about this...

    I used your last sample file as input (to build up the binary search tree) and let my application output preorder and inorder:

    • Preorder output corresponds to your last file.

    • Inorder output corresponds to your 3rd file.

    The inorder output provides a sorted output according to the defined order of the tree – in this case the lexicographical order of Morse sequences (where - precedes . due to their respective ASCII values).

    But this also does not print out the tree in alphabetical order for Morse code for preorder.

    Hmmm. If you expected an alphabetical order, do you mean an order which considers the alpha-numerical characters (to which the Morse codes map)?

    If so, this can hardly done by such a tree (as I cannot see how a possible order of Morse codes corresponds to a possible order of alpha-numerics). I.e. to achieve "Morse codes sorted by the associated alpha-numerics", the obvious (and IMHO only) way is to build a tree for the reverse mapping. You can easily built up another tree (e.g. from the first) where the assigned alpha-numeric values are used as key instead. (Actually, you already did first a binary search tree for alpha-numerics.)

    This leaves me somehow puzzled. May be, I missed something and didn't get your actual problem...

    However, below is the result of my fiddling:

    // forward template declaration:
    template <typename KEY, typename VALUE, typename COMP>
    class BSTreeT;
    
    /* provides a class template for a node in a binary search tree.
     *
     * KEY ... C++ type of the key values of nodes
     * VALUE ... C++ type of the other values of nodes
     */
    template <typename KEY, typename VALUE>
    class BSTreeNodeT {
    
      /* This friend shall ensure that the corresponding
       * BSTreeT template class may access private _pLeft and _pRight.
       */
      template <typename KEY_, typename VALUE_, typename COMP_>
      friend class BSTreeT;
    
      public:
        // the key value of node (used to define an order)
        const KEY key;
        // other values of node
        VALUE value;
      private:
        // pointers to left and right child nodes
        BSTreeNodeT *_pLeft, *_pRight;
    
      public:
        // constructor.
        BSTreeNodeT(const KEY &key, const VALUE &value):
          key(key), value(value), _pLeft(nullptr), _pRight(nullptr)
        { }
        // destructor.
        ~BSTreeNodeT() { delete _pLeft; delete _pRight; }
        // disabled:
        BSTreeNodeT(const BSTreeNodeT&) = delete;
        BSTreeNodeT& operator=(const BSTreeNodeT&) = delete;
    
      public:
        // returns pointer to left child node (or nullptr if there is none).
        const BSTreeNodeT* getLeft() const { return _pLeft; }
        // returns pointer to right child node (or nullptr if there is none).
        const BSTreeNodeT* getRight() const { return _pRight; }
    };
    
    /* provides a less functor which simply wraps operator < for a certain
     * type
     *
     * VALUE ... C++ type of value to less-compare
     *
     * Note:
     * This is actually, what std::less provides.
     * I involved this functor for illustration.
     */
    template <typename VALUE>
    struct lessFunc {
      bool operator()(const VALUE &value1, const VALUE &value2) const
      {
        return value1 < value2;
      }
    };
    
    /* provides a class template for a binary search tree.
     *
     * KEY ... C++ type of the key values of nodes
     * VALUE ... C++ type of the other values of nodes
     * COMP ... C++ type of the less comparator
     *          to define an order of tree nodes
     */
    template <typename KEY, typename VALUE, typename COMP = lessFunc<KEY> >
    class BSTreeT {
      public:
        const COMP &comp;
      private:
        BSTreeNodeT<KEY, VALUE> *_pRoot;
    
      public:
        /* constructor.
         *
         * comp ... a less comparator to define order of nodes
         */
        explicit BSTreeT(const COMP &comp = COMP()):
          comp(comp), _pRoot(nullptr)
        { }
        // destructor.
        ~BSTreeT() { delete _pRoot; }
        // disabled:
        BSTreeT(const BSTreeT&) = delete;
        BSTreeT& operator=(const BSTreeT&) = delete;
    
      public:
        /* inserts a node.
         *
         * key ... the key value of node
         * value ... the other value of node
         * return: true ... key/value inserted
         *         false ... Error! Possible reasons:
         *           - duplicated key
         *           - allocation of node failed.
         */
        bool insert(const KEY &key, const VALUE &value)
        {
          return insert(_pRoot, key, value);
        }
        /* provides a functor-like type which is applied to every node
         * in traverse().
         *
         * If an instance of this class is provided the traverse() does nothing
         * else than the pure traversal.
         */
        struct Apply {
          // pre-order access to node
          virtual void preNode(BSTreeNodeT<KEY, VALUE> &node) { }
          // in-order access to node
          virtual void inNode(BSTreeNodeT<KEY, VALUE> &node) { }
          // post-order access to node
          virtual void postNode(BSTreeNodeT<KEY, VALUE> &node) { }
        };
        /* traverses the tree and applies the provided object to every node.
         *
         * apply ... the action object applied to every node
         */
        void traverse(Apply &apply)
        {
          if (_pRoot) traverse(_pRoot, apply);
        }
    
      private:
        // inserts a node.
        bool insert(
          BSTreeNodeT<KEY, VALUE> *&pTree, const KEY &key, const VALUE &value)
        { /* Every if-branch ends with return.
           * Thus, no explict else is needed.
           */
          if (!pTree) { /* (!pTree) ... (pTree == nullptr) */
            return !!(pTree = new BSTreeNodeT<KEY, VALUE>(key, value));
          }
          if (comp(key, pTree->key)) return insert(pTree->_pLeft, key, value);
          if (comp(pTree->key, key)) return insert(pTree->_pRight, key, value);
          return false;
        }
        // traverses the tree.
        void traverse(BSTreeNodeT<KEY, VALUE> *pTree, Apply &apply)
        {
          apply.preNode(*pTree);
          if (pTree->_pLeft) traverse(pTree->_pLeft, apply);
          apply.inNode(*pTree);
          if (pTree->_pRight) traverse(pTree->_pRight, apply);
          apply.postNode(*pTree);
        }
    };
    
    // sample code:
    
    #include <ctype.h>
    #include <iostream>
    #include <string>
    
    using namespace std;
    
    // template instances (for convenience)
    typedef BSTreeNodeT<string, string> BSTNode;
    typedef BSTreeT<string, string> BST;
    
    /* a helper function to split a string into tow at the first occurence of
     * (a sequence of) whitespaces.
     *
     * line ... input
     * first ... returns first sub-string (might become empty)
     * second ... returns second sub-string (might become empty)
     */
    void split(const string &line, string &first, string &second)
    {
      size_t i0 = 0, n = line.length(), i;
      for (i = i0; i < n && !isspace(line[i]); ++i);
      first = line.substr(i0, i - i0);
      for (i0 = i; i0 < n && isspace(line[i0]); ++i0);
      for (i = i0; i < n && !isspace(line[i]); ++i);
      second = line.substr(i0, i - i0);
    }
    
    /* a derived tree-traversal action
     * for graphical (i.e. ASCII-art) output of tree
     */
    struct PrintGraph: public BST::Apply {
      string indent;
      PrintGraph(): indent("  ") { }
      virtual void preNode(BSTNode &node)
      {
        indent.pop_back(); char c = indent.back(); indent.pop_back();
        cout << indent << "+-"
          << (node.getLeft() || node.getRight() ? '+' : '-')
          << "- ["
          << node.key << ": " << node.value
          << ']' << endl;
        indent += c; indent += ' ';
        indent += node.getRight() ? "| " : "  ";
      }
      virtual void inNode(BSTNode &node)
      {
        indent.pop_back(); indent.pop_back();
        indent += "  ";
      }
      virtual void postNode(BSTNode &node)
      {
        indent.pop_back(); indent.pop_back();
      }
    };
    
    /* a derived tree-traversal action
     * for pre-order output of nodes
     */
    struct PrintPreOrder: public BST::Apply {
      virtual void preNode(BSTNode &node)
      {
        cout << node.key << ": " << node.value << endl;
      }
    };
    
    /* a derived tree-traversal action
     * for in-order output of nodes
     */
    struct PrintInOrder: public BST::Apply {
      virtual void inNode(BSTNode &node)
      {
        cout << node.key << ": " << node.value << endl;
      }
    };
    
    /* a derived tree-traversal action
     * to fill another tree with key and value of nodes swapped
     */
    struct FillRevTree: public BST::Apply {
      BST &tree; // destination tree to fill
      FillRevTree(BST &tree): tree(tree) { }
      virtual void preNode(BSTNode &node)
      {
        tree.insert(node.value, node.key);
      }
    };
    
    // main function
    int main()
    {
      BST tree;
      // read tree from input
      cout << "Read contents from input:" << endl;
      for (string line; getline(cin, line);) {
        string key, value; split(line, key, value);
        if (!tree.insert(key, value)) {
          cerr << "Error! Couldn't store the line:" << endl
            << "->" << line << endl;
        }
      }
      cout << "End of input." << endl
        << endl;
      // show tree
      cout << "The tree:" << endl;
      { PrintGraph print; tree.traverse(print); }
      cout << endl;
      // print tree by pre-order traversal
      cout << "Pre-Order Output:" << endl;
      { PrintPreOrder print; tree.traverse(print); }
      cout << endl;
      // print tree by in-order traversal
      cout << "In-Order Output:" << endl;
      { PrintInOrder print; tree.traverse(print); }
      cout << endl;
      // re-built tree with keys and values swapped
      BST treeRev;
      { FillRevTree fill(treeRev); tree.traverse(fill); }
      // show reverse tree
      cout << "The Rev. Tree:" << endl;
      { PrintGraph print; treeRev.traverse(print); }
      cout << endl;
      // print tree by in-order traversal
      cout << "In-Order Output of Rev. Tree:" << endl;
      { PrintInOrder print; treeRev.traverse(print); }
      cout << endl;
      // done
      cout << "That's it." << endl;
      return 0;
    }
    

    Compile and run:

    $ g++ -std=c++11 -o binary-search-tree binary-search-tree.cc
    
    $ ./binary-search-tree <morse.txt 
    Read contents from input:
    End of input.
    
    The tree:
    +-+- [-..: D]
      +-+- [--.-: Q]
      | +-+- [-----: 0]
      | | +-+- [--: M]
      | | | +--- [-: T]
      | | | +--- [---: O]
      | | +-+- [---..: 8]
      | |   +--- [----.: 9]
      | |   +--- [--.: G]
      | +-+- [-.: N]
      |   +-+- [--..--: ,]
      |   | +--- [--..: Z]
      |   | +--- [--...: 7]
      |   +-+- [-.--: Y]
      |     +--- [-.-: K]
      |     +--- [-.-.: C]
      +-+- [..: I]
        +-+- [.----: 1]
        | +-+- [.: E]
        | | +-+- [-...: B]
        | | | +--- [-..-: X]
        | | | +--- [-....: 6]
        | | +-+- [.--: W]
        | |   +--- [.-: A]
        | |   +--- [.---: J]
        | +-+- [.-.-.-: .]
        |   +-+- [.--.: P]
        |   | +--- [.-.: R]
        |   +--- [.-..: L]
        +-+- [...--: 3]
          +-+- [..--..: ?]
          | +-+- [..---: 2]
          | | +--- [..-: U]
          | +-+- [...: S]
          |   +--- [..-.: F]
          |   +--- [...-: V]
          +-+- [....-: 4]
            +--- [....: H]
            +--- [.....: 5]
    
    Pre-Order Output:
    -..: D
    --.-: Q
    -----: 0
    --: M
    -: T
    ---: O
    ---..: 8
    ----.: 9
    --.: G
    -.: N
    --..--: ,
    --..: Z
    --...: 7
    -.--: Y
    -.-: K
    -.-.: C
    ..: I
    .----: 1
    .: E
    -...: B
    -..-: X
    -....: 6
    .--: W
    .-: A
    .---: J
    .-.-.-: .
    .--.: P
    .-.: R
    .-..: L
    ...--: 3
    ..--..: ?
    ..---: 2
    ..-: U
    ...: S
    ..-.: F
    ...-: V
    ....-: 4
    ....: H
    .....: 5
    
    In-Order Output:
    -: T
    --: M
    ---: O
    -----: 0
    ----.: 9
    ---..: 8
    --.: G
    --.-: Q
    --..: Z
    --..--: ,
    --...: 7
    -.: N
    -.-: K
    -.--: Y
    -.-.: C
    -..: D
    -..-: X
    -...: B
    -....: 6
    .: E
    .-: A
    .--: W
    .---: J
    .----: 1
    .--.: P
    .-.: R
    .-.-.-: .
    .-..: L
    ..: I
    ..-: U
    ..---: 2
    ..--..: ?
    ..-.: F
    ...: S
    ...-: V
    ...--: 3
    ....: H
    ....-: 4
    .....: 5
    
    The Rev. Tree:
    +-+- [D: -..]
      +-+- [0: -----]
      | +-+- [,: --..--]
      | | +--- [.: .-.-.-]
      | +-+- [8: ---..]
      |   +-+- [7: --...]
      |   | +-+- [1: .----]
      |   |   +-+- [6: -....]
      |   |     +-+- [3: ...--]
      |   |       +--- [2: ..---]
      |   |       +-+- [4: ....-]
      |   |         +--- [5: .....]
      |   +-+- [9: ----.]
      |     +-+- [C: -.-.]
      |       +-+- [B: -...]
      |         +-+- [A: .-]
      |           +--- [?: ..--..]
      +-+- [Q: --.-]
        +-+- [M: --]
        | +-+- [G: --.]
        | | +-+- [E: .]
        | | | +--- [F: ..-.]
        | | +-+- [K: -.-]
        | |   +-+- [I: ..]
        | |   | +--- [H: ....]
        | |   | +--- [J: .---]
        | |   +--- [L: .-..]
        | +-+- [O: ---]
        |   +--- [N: -.]
        |   +--- [P: .--.]
        +-+- [T: -]
          +-+- [R: .-.]
          | +--- [S: ...]
          +-+- [Z: --..]
            +-+- [Y: -.--]
              +-+- [X: -..-]
                +-+- [W: .--]
                  +-+- [U: ..-]
                    +--- [V: ...-]
    
    In-Order Output of Rev. Tree:
    ,: --..--
    .: .-.-.-
    0: -----
    1: .----
    2: ..---
    3: ...--
    4: ....-
    5: .....
    6: -....
    7: --...
    8: ---..
    9: ----.
    ?: ..--..
    A: .-
    B: -...
    C: -.-.
    D: -..
    E: .
    F: ..-.
    G: --.
    H: ....
    I: ..
    J: .---
    K: -.-
    L: .-..
    M: --
    N: -.
    O: ---
    P: .--.
    Q: --.-
    R: .-.
    S: ...
    T: -
    U: ..-
    V: ...-
    W: .--
    X: -..-
    Y: -.--
    Z: --..
    
    That's it.
    
    $
    

    Note:

    I just recognized that the "reversed" tree is not well-balanced anymore. Thus, the optimal worst-case time-complexity of O(ld(n)) cannot be achieved.

    0 讨论(0)
提交回复
热议问题