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:
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 ∁
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.
Related
Attempting to compile the following function causes an error:
let balance (left : 'a t) (ele : 'a) (right : 'a t) : 'a t =
match left,ele,right with
| N (d',N (_,a,x,b),y,c),z,d when d' - depth d > 1 && ele < y
| N (d',a,x,N (_,b,y,c)),z,d when d' - depth d > 1 && ele > x
| a,x,N (d',N (_,b,y,c),z,d) when d' - depth a > 1 && ele < z
| a,x,N (d',b,y,N (_,c,z,d)) when d' - depth a > 1 && ele > y
-> new_node (new_node a x b) y (new_node c z d)
| _ -> new_node left ele right
However, both of the following functions will compile without issue:
let balance (left : 'a t) (ele : 'a) (right : 'a t) : 'a t =
match left,ele,right with
| N (d',N (_,a,x,b),y,c),z,d
| N (d',a,x,N (_,b,y,c)),z,d
| a,x,N (d',N (_,b,y,c),z,d)
| a,x,N (d',b,y,N (_,c,z,d))
-> new_node (new_node a x b) y (new_node c z d)
| _ -> new_node left ele right
let balance (left : 'a t) (ele : 'a) (right : 'a t) : 'a t =
match left,ele,right with
| N (d',N (_,a,x,b),y,c),z,d when d' - depth d > 1 && ele < y
-> new_node (new_node a x b) y (new_node c z d)
| _ -> new_node left ele right
How can I get the behavior specified in the first block? Obviously, I could copy the seventh line to each of the preceding patterns, but I'd prefer not to do so.
It's true, this is a limitation of OCaml patterns.
When you write this:
match x with
| 1
| 2 -> f x
You're actually writing just one pattern that looks like this:
match x with
| (1 | 2) -> f x
So this (if it were allowed):
match x with
| 1 when a
| 2 when b -> f x
would be equivalent to something like this:
match x with
| (1 when a | 2) when b -> f x
In other words, what you're trying to do is add when clauses into the middle of a pattern. This isn't supported. They're just a feature of match, not of patterns in general.
As an addendum to what Jeffrey Scofield has already said, beware the following trap.
match 42 with
| 1
| n when n mod 2 = 0 -> "foo"
| n -> "bar"
Or equivalently:
match 42 with
| (1 | n) when n mod 2 = 0 -> "foo"
| n -> "bar"
Both get you this error:
Error: Variable n must occur on both sides of this | pattern
A when conditional guard has to work for either pattern. That's why the following will work.
match (3, 2) with
| (1, n)
| (3, n) when n mod 2 = 0 -> "foo"
| n -> "bar"
Equivalently:
match (3, 2) with
| ((1, n) | (3, n)) when n mod 2 = 0 -> "foo"
| n -> "bar"
Be prepared for compiler warnings if you bind the same name to different values using patterns joined with |.
I am struggling to understand the logic of the code below. I know the code will return a list of Fibonacci numbers from the first till nth e.g. fib 3 will produce [2,1,1,0]. I do not understand how 'n' is split up in (x:y:xs).
I would appreciate any light on this.
Thanks
fib 1 = [1, 0]
fib n = x + y : (x:y:xs)
where (x:y:xs) = fib (n-1)
Your comment about "how" the code splits up the list returned by fib I cannot answer as I don't know all the internals of GHC. This process is called patter matching. In Python and other languages you may be familiar with, this can be done
a, b = (1,2)
# a == 1
# b == 2
Your function is of type
fib :: Int -> [Int]
so you can use pattern matching to extract the head, next head, and next tail of the list it returns, which is what happens in
where (x:y:xs) = fib (n-1)
Perhaps an area of confusion is where the list is being reconstructed so it can be appended to the rest of the list you are returning. Your function can also be written like this
fib 1 = [1, 0]
fib n = x + y : (fib (n-1))
where (x:y:xs) = fib (n-1)
I do not understand how n is split up in (x:y:xs).
n is not being split; the list resulting from fib is being split.
The original code:
fib 1 = [1, 0]
fib n = x + y : (x:y:xs)
where (x:y:xs) = fib (n-1)
Is equivalent to the following, with some of the syntactic sugar removed:
fib n =
if n == 1
then [1, 0]
else case fib (n - 1) of
x : (y : xs) -> (x + y) : (x : (y : xs))
_ -> error "pattern match failure"
Since this code just destructures the list and then rebuilds an identical one, the case branch can also be written using an “as” pattern, e.g.: res#(x : y : xs) -> (x + y) : res
So fib is a function which takes one parameter n, which may be of any numeric type. In the base case when n is 1, the code just returns a constant list [1, 0]. In the recursive case, fib calls itself recursively, replacing n with n - 1. The result will be a list, so the function then pattern-matches on that list to extract its components.
In the pattern x : y : xs, which is syntactic sugar for (:) x ((:) y xs), the operator (:) :: a -> [a] -> [a] is the data constructor for a list that is not empty, and x, y, and xs are variables; so this is equivalent to saying “if the input (the result of fib (n - 1)) is non-empty, then name its head x; and if its tail is non-empty, then name the head and tail of that y and xs respectively”. In other words, if it’s a list of at least two elements, then call the first element x, the second y, and the remainder xs (which may be empty).
In fact it can be implemented in that explicit way, as you’d do in a language that lacks pattern-matching, by using guards or if expressions. The result is quite unwieldy and error-prone, but it may be helpful as an illustration of how to mentally break it down:
fib n
| n == 1
= [1, 0]
| let temp1 = fib (n - 1)
, not (null temp1)
, let x = head temp1
, let temp2 = tail temp1
, not (null temp2)
, let y = head temp2
, let xs = tail temp2
= x + y : temp1
| otherwise
= error "pattern match failure"
fib n =
if n == 1
then [1, 0]
else let
temp1 = fib (n - 1)
in if not (null temp1)
then let
x = head temp1
temp2 = tail temp1
in if not (null temp2)
then let
y = head temp2
xs = tail temp2
in x + y : temp1
else error "pattern match failure"
else error "pattern match failure"
Obviously pattern matching is much simpler!
So here’s an example of how the original code would evaluate on the example input you gave, fib 3:
evaluate: fib 3
matches equation #2 with n₀ = 3: let (x₀ : y₀ : xs₀) = fib (3 - 1) in x₀ + y₀ : (x₀ : y₀ : xs₀)
evaluate: fib 2
matches equation #2 with n₁ = 2: let (x₁ : y₁ : xs₁) = fib (2 - 1) in x₁ + y₁ : (x₁ : y₁ : xs₁)
evaluate: fib 1
matches equation #1: [1, 0]
substitute: let (x₁ : y₁ : xs₁) = 1 : 0 : [] in x₁ + y₁ : (x₁ : y₁ : xs₁)
evaluate let with x₁ = 1, y₁ = 0, xs₁ = []: 1 + 0 : (1 : 0 : [])
substitute: let (x₀ : y₀ : xs₀) = 1 : 1 : [0] in x₀ + y₀ : (x₀ : y₀ : xs₀)
evaluate let with x₀ = 1, y₀ = 1, xs₀ = [0]: 1 + 1 : (1 : 1 : [0])
syntactic sugar for lists: [2, 1, 1, 0]
And a diagram, showing how it builds up a list where each element’s value refers to the subsequent two elements:
┌─────┬───────────┬───────┐ ┌─────┬───────────┬───────────┐ ┌─────┬───┬─────┐ ┌─────┬───┬───┐ ┌────┐
… fib 3───▶ (:) │ (+) x₁ y₁ │ fib 2─┼─▶ (:) │ (+) x₀ y₀ │ xs₁/fib 1─┼─▶ (:) │ 1 │ xs₀─┼─▶ (:) │ 0 │ ○─┼─▶ [] │
└─────┴─────┼──┼──┴───────┘ └─────┴──▲──┼──┼──┴───────────┘ └─────┴─▲─┴─────┘ └─────┴─▲─┴───┘ └────┘
└──┼─────────────────────┘ │ └────────────────────────┼─────────────────┘
└────────────────────────┴───────────────────────────┘
ASCII version:
+-----+-----------+-------+ +-----+-----------+-----------+ +-----+---+-----+ +-----+---+---+ +----+
| | | | | | | | | | | | | | | | | |
… fib 3---> (:) | (+) x1 y1 | fib 2-+---> (:) | (+) x0 y0 | xs1/fib 1-+---> (:) | 1 | xs0-+---> (:) | 0 | o-+---> [] |
| | | | | | | | | | | | | | | | | | | | | |
+-----+-----+--+--+-------+ +-----+--^--+--+--+-----------+ +-----+-^-+-----+ +-----+-^-+---+ +----+
| | | | | | |
+--+-----------------------+ | +--------------------------+-------------------+
| | |
+--------------------------+-----------------------------+
Notice the calls to error: if you try to evaluate a pattern match that isn’t exhaustive, it will throw an exception. In this case, fib will always have at least two elements, so the let binding is safe, but consider how you could change the structure of the code to avoid needing this partial match.
Below is the code for swapping nodes without changing data. I wonder whether swapping the next pointers of nodes required? Will swapping the current nodes doesn't swap the next pointers? Why?
void swapNodes(Node** head_ref, int x, int y)
{
// Nothing to do if x and y are same
if (x == y)
return;
Node **a = NULL, **b = NULL;
// search for x and y in the linked list
// and store therir pointer in a and b
while (*head_ref) {
if ((*head_ref)->data == x) {
a = head_ref;
}
else if ((*head_ref)->data == y) {
b = head_ref;
}
head_ref = &((*head_ref)->next);
}
// if we have found both a and b
// in the linked list swap current
// pointer and next pointer of these
if (a && b) {
swap(*a, *b);
swap(((*a)->next), ((*b)->next));
}
}
void swap(Node*& a, Node*& b)
{
Node* temp = a;
a = b;
b = temp;
}
Thank You.
whether swapping the next pointers of nodes required?
Yes it is required because the original nodes take place in different positions of the list.
Will swapping the current nodes doesn't swap the next pointers?
Yes, swapping current nodes doesn't swap the next pointers. Swapping current nodes means only swapping only pointers that point to the current nodes.
Consider for example the list
| A |next B| -> | B |next C| -> | C |next D| -> | D |next nullptr|
and let's assume that you need to swap nodes B and D. Then you'll get
---------------------
| |
| A |next D| ... | B |next C| -> | C |next B| ... | D |next nullptr|
| |
----------------------------------------------
So after the first swapping the node A points to node D but node D "points" to nullptr. Nodes B and C will be lost if not to swap their data members next.
Thus you need also to swap their data members next
--------------------------
| |
| A |next D| ... | B |next nullptr| | C |next B| ... | D |next C|
| |
---------------------------------------------------
and as result you'll get
| A |next D| -> | D |next C| -> | C |next B| -> | B |next nullptr|
Swapping the current nodes won't be enough.
When swapping a and b, their address is changed so their place in the list will be replaced
But you do not change the inner fields of each node.
Nodes Illustraion:
a - b - c - d
Let's take node a and c.
a->next == &b (True)
c->next == &d (True)
If we swap the nodes like this:
c - b - a - d
The address of node c and node a will change, but the list would look the same since their ->next values will not change
If we also swap the ->next values, the list will be really swapped
infix v;
infix &;
datatype s = P | Q | S
| ~ of s
| v of s * s
| & of s * s;
I made a function (s -> unit) to print type s as string
fun printS(P) = print "P"
| printS(Q) = print "Q"
| printS(P & Q) = print "P & Q";
My Question is how can I print s recursively if I have more complex s such as
P v ~ Q & P.
You can pretty-print an expression recursively by pattern-matching the sub-trees as variables and then refer to those sub-trees. In your example, you are only matching P & Q which is exactly one tree.
fun printS P = print "P"
| printS Q = print "Q"
| printS S = print "S"
| printS (p & q) = (print or printS ...; print or printS ...; ...)
By not referring to actual P and Q, but instead variables p and q, these could be any sub-expression. Since your function returns unit, you'd want to print multiple times. Except, perhaps, some of the things you want to print are recursive datatypes, so you could use your specialized printS instead.
I would probably convert this to a string and print the string once:
fun toString P = "P"
| toString Q = "Q"
| toString S = "S"
| toString (p & q) = "(" ^ toString p ^ " & " ^ toString q ^ ")"
| toString ... = ...
and then print it:
fun printS s = print (toString s)
The real challenge comes at printing the minimal amount of parentheses:
printS ((P v Q) & (Q v P))
should preferrably not print P v Q & Q v P, since those aren't the same expressions.
how can i use tree.hh: an STL-like C++ tree class to populate my tree and obtain the tree below. some help would be appreciate. A and G are root node
thank's
A G
______|____ |
/ | \ |
B C D H
| | | |
| E | |
\_____/ | |
| | |
F | |
|_________|______|
|
I
|
J
In then code above, i'm using depth first search to enumarate item in the list. i have few data formated like this
typedef tree<std::string> TreeNode;
typedef struct
{
int nBases;
char * name;
} BASES;
BASES rgbases[] =
{
{0xB, "J"},
{0xA, "I"},
{0x1, "H"},{0x0, "G"},
{0x5, "F"},{0x2, "E"},{0x1, "C"},{0x0, "A"},
{0x1, "D"},{0x0, "A"},
{0x1, "B"},{0x0, "A"}
};
//here i'm trying to populate my tree
void populateTree(TreeNode &tr, BASES *pBaseArray, int numBase)
{
int n = 0;
while ( n < numBase )
{
BASES *pBase = &pBaseArray[n];
if ( pBase->nBases > 0) // Check for children of the new node
populateTree(tr, pBaseArray + (n + 1),pBase->nBases);
// i suppose i need to insert tree code part here
n += pBase->nBases + 1;
}
}
void BuildTree(TreeNode &tr)
{
populateTree(tr, rgBases, _countof(rgBases));
}
A tree, spanning the original graph presented, could be obtained in removing the edges linking node A with B and D(or possibly the edges linking node A with C and D). The tree class would then be applicable:
A G A G
| | ______| |
| | / |
B C D H B C D H
| | | | | | | |
| E | | | E | |
\______/ | | \______/ | |
| | | | | |
F | | F | |
|_________|______| |__________|______|
| |
I I
| |
J J
Edges in the above tree giving rise to loops, could be recorded separately, that is AB and AD, could be noted in a structure, apart from the tree class. Merging the tree with such a structure would recover the original graph.