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 to have the different trees in text files that should already be in the correct order for insert. In my normal alphabet, I worked out my balanced text file for preorder traversal looks like
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
,
.
?
This text file prints out preorder traversal
,
.
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
The problem I am having is with the Morse code textfile. I understand that the characters for Morse code are not the same for the normal alphabet. From lest to greatest, this is Morse code
- 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
applying the same formula for the tree (so it has the same sequence as the alphabetical one above, my text file looks like
-.. 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
But this also does not print out the tree in alphabetical order for Morse code for preorder.
This is how I am inserting into the tree
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);
}
}
And this is how I am printing out the results
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);
}
}
(the same code is for the alphabet except it uses chars and getLetter() but other than that it is identical)
If I am just approaching this incorrectly, I could use any help in the right direction.
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:
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 ∁
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.