预订遍历莫尔斯电码BST

时间:2017-07-11 23:42:41

标签: c++ binary-search-tree morse-code

在c ++中我正在处理两棵树,1是字母a-z,带有nums和字符0-9 ,. ?

另一棵树相当于摩尔斯电码中的那些字符。我必须在文本文件中有不同的树,这些树应该已经按正确的顺序插入。在我的普通字母表中,我找到了我的平衡文本文件,用于前序遍历,如

P 
H
D
B
A
C
F
E
G
L
J
I
K
N
M
O
2
X
T
R
Q
S
V
U
W
0
Y
Z
1
9
5
4
3
7
6
8
,
.
?

此文本文件打印出预订序遍历

,
.
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

我遇到的问题是摩尔斯电码文本文件。据我所知,摩尔斯电码的字符与普通字母表的字符不同。从最大到最大,这是摩尔斯电码

-    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

对树应用相同的公式(因此它与上面的字母顺序相同,我的文本文件看起来像

-..  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

但是,对于预订的摩尔斯电码,这也不会按字母顺序打印出树。

这就是我插入树的方式

void BST::insert(BSTNode *&pTree, string morse)
{
    if (pTree == NULL)
    {
        BSTNode *pMem = new BSTNode(morse);
        pTree = pMem;
    }
    else if (morse < (pTree)->getMorse())
    {
        insert((pTree)->getLeft(), morse);
    }
    else if (morse > (pTree)->getMorse())
    {
        insert((pTree)->getRight(), morse);
    }
}

这就是我打印结果的方式

void BST::print(BSTNode *&pTree, string id)
{
    if (pTree != nullptr)
    {
        //cout << pTree->getMorse() << endl; // processed
        print(pTree->getLeft(), id);
        cout << pTree->getMorse() << endl; // processed
        print(pTree->getRight(), id);
    }

}

(相同的代码用于字母表,除了它使用chars和getLetter(),但除此之外它是相同的)

如果我只是错误地接近这个,我可以在正确的方向上使用任何帮助。

1 个答案:

答案 0 :(得分:0)

您是否注意到您的insert()方法无法处理&#34;密钥冲突&#34; (由于最后else缺少if分支。这可用于检测是否应插入已在树中的密钥。实际上,这样的重复插入被简单地忽略了(这是恕我直言,不是最糟糕的行为)。

在下面的示例中,我决定使用其他选项:让insert()返回一个布尔值,报告插入成功。

很遗憾,您没有提供MCVE

因此,我用自己的代码填补了空白(我个人的喜悦)我参与了模板。希望这不会带来太多混乱。

但是,在使用您的示例数据后,我得出的结论是您的代码可能是正确的 - 可能不是,您所期望的。最终,你有一个错误的期望。或者,您正确地解决了错误的问题。我多次重读你的问题,但我没有清楚地了解这个......

我使用您的上一个示例文件作为输入(构建二进制搜索树)并让我的应用程序输出预订并按顺序排列:

  • 预购输出对应于您的上一个文件。

  • Inorder输出对应于您的第3个文件。

inorder输出根据树的定义顺序提供排序输出 - 在这种情况下是莫尔斯序列的词典顺序(-由于它们各自的ASCII值而在.之前)。 / p>

  

但是,对于预先订购的摩尔斯电码,这也不会按字母顺序打印出树。

嗯。如果您期望按字母顺序排列,那么您的意思是指一个考虑字母数字字符(摩尔斯电码代码映射到哪个)的订单吗?

如果是这样,这种树很难完成(因为我无法看到莫尔斯码的可能顺序如何对应于α数字的可能顺序)。即为了实现按照相关的字母数字&#34;排序的莫尔斯代码,显而易见的(仅限IMHO)方法是为反向映射构建一个树。您可以轻松地构建另一个树(例如,从第一个树),其中指定的字母数字值用作键。 (实际上,你已经为alpha-numerics做了第一个二叉搜索树。)

这让我感到困惑。可能是,我错过了什么,并没有得到你的实际问题......

但是,下面是我摆弄的结果:

// 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;
}

编译并运行:

$ 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.

$

注意:

我刚认识到&#34;逆转&#34;树不再平衡。 因此,无法实现 O(ld(n))的最佳最坏情况时间复杂度。