tree.hh - C++ Leaf Traversal - c++

The output from the following code is incorrect. It should only output the leaves in the tree:
tree<Node> gameTree;
tree<Node>::iterator root = gameTree.insert(gameTree.begin(),Node(14));
tree<Node>::iterator first = gameTree.append_child(root,Node(32.0));
tree<Node>::iterator second = gameTree.append_child(root,Node(64.0));
gameTree.append_child(second,Node(21.0));
gameTree.append_child(second,Node(24.0));
tree<Node>::iterator begin = gameTree.begin_leaf();
tree<Node>::iterator end = gameTree.end_leaf();
int x = 0;
while (begin != end)
{
cout << begin->value << endl;
begin++;
}
But it outputs:
32
64
21
24
when the output SHOULD be:
32
21
24

From the docs you should be using a leaf_iterator rather than an iterator, the output you're seeing is from an in order traversal, you want to do a leaf traversal I'm guessing.
btw, thanks for posting this I was just starting in a search for a tree container
hth

What's happening is that the iterator class is actually just a typedef for the pre_order_traversal class. So when you set the result of gameTree.beginLeaf() (which returns a leaf_iterator) to an iterator, it invokes the copy constructor of pre_order_iterator because there's a constructor defined for pre_order_traversal(const iterator_base&) (iterator_base is the superclass for all other iterators, including the leaf_iterator), so this creates a new pre_order_iterator from the leaf_iterator. Then when you use that iterator, it does a depth-first traversal rather than iterating through the leaves. If you switch to leaf_iterator instead of iterator, the problem will disappear.
This is also why the direct form mentioned in a comment below (where the value is not assigned to an iterator) works properly.

I don't know what tree<> is, nor do I know the semantics of append_child, but from what I see, 32, 64, 21 and 24 are all below the root of the hierarchy (children and grandchildren of 14); I don't see a problem.
Why exactly should 64 be skipped, but not 24?

Related

How binary search tree insertion works using recursion?

I'm having some trouble understanding the recursive part of binary search tree insertion.
bstnode* insert(bstnode* root,int data)
{
if(root==NULL){
bstnode* tmp= new bstnode();
tmp->data=data;
tmp->left=tmp->right=NULL;
return tmp;
}
if(data<root->data)
root->left = insert(root->left, data);
else
root->right = insert(root->right, data); //can't understand the logic here
return root;
}
/* consider following BST with their addresses[]:
15 [100]
/ \
10 20 [200]
\
tmp [300]
*/
According to me root->right = insert(root->right, data); should store the address of the newly created node in root->right so this code shouldn't work for tree with height>2.
However, it is working perfectly for any number of nodes.
I must be missing some crucial details here.
suppose I want to insert 25 in BST i.e. insert(root,25);
as 25>15:- I'm breaking down the recursive part here:
root->right = insert(root->right, 25);
or 15->right = insert(15->right,25); Here, recursively calling it again because 25>20
insert(root->right, 25) => root->right->right = insert(root->right->right, 25);
or insert(15->right, 25) => 20->right = insert(20->right, 25);
insert(20->right,25) is NULL so a new node tmp is created.
insert(20->right,25); returns tmp.
unwinding the recursion now.
//20->right = insert(20->right, 25);
so,
20->right= 300 (tmp address);
//insert(15->right, 25) => 20->right
//and 15->right = insert(15->right,25);
15->right = 20->next;
therefore 15->right = [300] address.
or
root->right = [300] address.
what's wrong with my approach?
Again an overview of recursive calls:
15->right = insert(15->right,25);
15->right = [20->right = insert(20->right,25)]; //20->right is NULL so creating new node
15->right = [20->right= 300 address of tmp];
15->right = [20->right or 300]
15->right = [300] // but in reality 15->right = [200]
you are forgetting that root->right is the root->right of the address you are passing into the function as root. every call to insert passes in root->right or root->left depending on which way you traverse.
This statement is incorrect:
root->right = root->right->right = tmp;
once an iteration of the function is returned it is removed from the stack so in this case we have 3 calls I will put your numbers in place of the pointer value.
insert(15->right,25)
insert(20->right,25)
the last one is null so it creates the node with 25 and returns it to the call insert(20->right,25) and sets 25 as 20->right so you have a tree that looks like this
/* consider following BST with their addresses[]:
20 [200]
\
25 [300]
*/
it then returns this tree to the call insert(15->right,25) and sets that trees right to the tree we just returned which so we get your final tree
/* consider following BST with their addresses[]:
15 [100]
/ \
30 20 [200]
\
25 [300]
*/
EDIT: let me see if I can clarify. Lets look at your tree again
/* consider following BST with their addresses[]:
15 [100]
/ \
10 20 [200]
\
tmp [300]
*/
we want to insert 25 so we call (again I will use the value at that node of the tree to represent the pointer we are passing)
insert(15, 25)
this then calls insert on root->right which happens to be 20
insert(20, 25)
this calls insert again on 20 right node now which happens to be null
insert(null,25)
so lets now look at the returns
insert(null,25) returns a node with 25 in it and then is remove from the stack
return 25;
insert(20,25) gets its return of a node with 25. it sets its right child to 25 which looks like this
20->right = 25;
return 20;
now we are back to the original call of insert(15,25). it got returned 20. so it does
15->right = 20;
return 15;
I think the confusion may be coming from two different sources for you.
First the tree commented into your code would not be possible. Second is that a new node is only created when the function is passed in a null pointer. Only values less than 15 can go to the left. It would be something like this instead (depending on add order):
15
/ \
20
/ \
30
When you go to add 25 to this it will end up as follows:
15
/ \
20
/ \
30
/
25
I will try and step through the code on this to explain. When adding 25 to the original tree on the first function call the first node is not NULL and 25 > 15 so the
else
{
root->right = insert(root->right, data);
}
is called. This calls the same insert function recursively but is now using the 20 node as it's comparison. Again not null and 25 > 20 so call insert on right node as above. This again calls the recursive function but now on 30. 25<30 so it calls the function on the left node. At this point the function as been passed in a NULL pointer as there is nothing there and a new node is created and placed in this spot.
Note that insert() always returns the root that was passed to it as an argument unless root == NULL. There's therefore no way for the new node you insert to "walk up the tree". What happens in the recursive call doesn't matter -- you always return the same root that you were passed in the non-NULL case.
Despite the way some people teach recursion, I think it helps (for my brain anyway) to not try to unroll the recursion, and instead consider whether the logic makes sense:
If you are passed a non-NULL node and data < root->data, would you get the correct result if you do root->left = insert(root->left, data) and assume the insert() magically "just works" (i.e., that it inserts data into the left tree and returns the root of that tree)?
If the logic checks out for both the left and right case, you then consider the base case: If you are passed a NULL node, will you return the correct one-element tree?
If the logic checks out for the base case too, then you know your code must be correct, since the recursive steps make sense and you know that you will land in a base case that also makes sense (since you will eventually reach a NULL node as you walk down the tree).
In a way you are correct. You can never have a sub-tree (not tree) of height >2.
In this code, you will never have a root->right->right because, as far as the code is concerned, when you call
root->left = insert(root->left, data);
the (local) root pointer is now pointing to the node you just inserted. the (local) root is pointing to root->left.
Therefore, you CAN have a tree of any height(However, the local root pointer is pointing to a sub-tree of height <2)

Beginner difficulty with vectors and while-loops in C++

Update:
So it turns out there were two issues:
The first is that I checked the [k-1] index before I checked k == 0. This was a crash, although mostly fixable, and not the primary issue I posted about.
The primary issue is that the code seems to execute only after I press ctrl+z. Not sure why that would be.
Original:
So, learning from Stroustrup's text in C++ programming, I got to an example on vectors and tried implementing it myself. The gist is that the program user enters a bunch of words, and the program alphabetizes them, and then prints them without repeats. I managed to get working code using a for statement, but one of my initial attempts confuses me as to why this one doesn't work.
To be clear, I'm not asking to improve this code. I already have better, working code. I'm wondering here why the code below doesn't work.
The "error" I get is that the code compiles and runs fine, but when I input words, nothing happens and I'm prompted to input more.
I'm certain there's an obvious mistake, but I've been looking everywhere for the last 8 hours (no exaggeration) just devoted to finding the error on my own. But I can't.
int main() {
vector<string> warray; string wentry; int k = 0;
cout << "Enter words and I'll alphabetize and delete repeats:\n\n";
while (cin >> wentry) warray.push_back(wentry);
sort(warray.begin(), warray.end());
while (k < warray.size()) {
if (warray[k - 1] != warray[k] || k == 0) cout << warray[k] << "\n";
++k;
}
}
My reasoning for why this should work is this: I initialize my array of words, my word entry per input, and a variable to index word output.
Then I have a while statement so that every input is stacked at the end of the array.
Then I sort my array.
Then I use my index which starts at 0 to output the 0th item of the array.
Then so long as there are words in the array not yet reached by the index, the index will check that the word is not a repeat of the prior index position, and then print if not.
No matter what whappens, the index is incremented by one, and the check begins again.
Words are printed until the index runs through and checks all the words in the array.
Then we wait for new entries, although this gets kind of screwy with the above code, since the sorting is done before the checking. This is explicitly not my concern, however. I only intend for this to work once.
To end the cycle of input you need to insert EOF character which is ctrl+d. However, there are other problems in your code. You have k = 0 to start with so the moment you will try warray[k - 1] your code will crash.
At the point where you take
warray[k - 1]
for the first time, k is zero, so you want to get the warray value at index -1, which is not necessarily defined in memory (and even if, I wouldn't do this anyway). So as it compiles, I guess the address is defined in your case by accident.
I would try simply reversing the OR combination in your if-condition:
if (k == 0 || warray[k - 1] != warray[k])
thus for the first iteration (k == 0) it won't check the second condition because the first condition is then already fulfilled.
Does it work then?
You're stuck in the while loop because you don't have a way of breaking out of it. That being said, you can use Ctrl + d (or use Ctrl + z if executing on windows in the command prompt) to break out of the loop and continue executing the code.
As for while loop at the bottom which prints out the sorted vector of values, your program is going to crash as user902384 suggested because your program will first check for warray[k - 1].
Ideally, you want to change the last part of your program to:
while (k < warray.size())
{
if (k == 0 || warray[k - 1] != warray[k])
cout << warray[k] << "\n";
++k;
}
This way, the k == 0 check passes and your program will skip checking warray[k - 1] != warray[k] (which would equal warray[-1] != warray[0] when k=0).
You just needed to reverse:
if (warray[k - 1] != warray[k] || k == 0)
to
if (k == 0 || warray[k - 1] != warray[k] )
for terminating this condition if k = 0.
An alternative.
Although it can termed as a bit off topic, considering you want to work with std::vector<>, but std::set<> is an excellent container which satisfies your current two conditions:
Sort the strings in alphabetical order.
Delete all the repetitions.
Include <set> in your .cpp file, and create a set object, insert all the std::string and iterate through the set to get your ordered, duplicate-free strings!
The code:
int main() {
//Define a set container.
set<string> s;
//A temporary string variable.
string temp;
//Inserting strings into the set.
while (cin >> temp) s.insert(temp);
//Create a set<int> iterator.
set<string>::iterator it;
//Scanning the set
for(it = s.begin(); it != s.end(); ++it)
{
//To access the element pointed by the iterator,
//use *it.
cout<<*it<<endl;
}
return 0;
}
I just recommended this container, because you will study set in Stroustrup's text, and it is very easy and convenient instead of laboring over a vector.

c++ ignoring same number in an array

I have an array of random numbers, for example
6 5 4 4 8
I need to sort it and remove/ignore the same numbers while printing afterwards, so what I did is I sorted everything with bubble sorth algorithm and got something like this
4 4 5 6 8
Now in order to print only different numbers I wrote this for loop
for(int i=0;i<n;i++){
if(mrst[i]!=mrst[i-1] && mrst[i]>0){
outFile << mrst[i] << " ";
}
}
My question is, the array I have is at the interval of [0:12], though the first time when I call it, it checks an array index of -1 to see if there was the same number before, but it doesn't really exist, but the value stored in there usually is a huge one, so is there a possibility that there may be stored 4 and because of it, the first number won't be printed out. If so, how to prevent it, rewrite the code so it would be optimal?
Perhaps, you're looking for std::unique algorithm:
std::sort(mrst, mrst + n);
auto last = std::unique(mrst, mrst + n);
for(auto elem = mrst; elem != last; ++elem)
outFile << *elem << " ";
Well, as you noted already, you cannot do the check mrst[i] != mrst[i-1] in case i == 0. So I'm sure you can think of a way of not doing that check in exactly this case ... (This looks very much like a homework assignment, so I'm not really willing to give you a complete solution, but I guess I hinted enough)
Note also that it's undefined behaviour to access memory outside the boundaries of an array, so what you're doing there can do anything from working correctly to crashing your program, entirely at the discretion of the compiler.
Basically you can read from any place in heap. So mrst[-1] may give you some garbage from the memory. But you really should avoid doing this. In your case you can just change "mrst[i]!=mrst[i-1] && mrst[i]>0" to "i==0 || mrst[i]!=mrst[i-1]".
In c++ "A || B" don't execute "B" if the "A" is ok.

Map - finding nearest value?

I am trying find nearest RGB value in QMap (I know it probably should be HSV, but that is not the problem). Here is what I got so far:
it = images_map.find(current_rgb);
if(it != images_map.begin()){
mi = images_map.lowerBound(current_rgb).value();
}
else{
mi = images_map.upperBound(current_rgb).value();
}
My map looks like this has that indexes:
images_map[ 4283914078 ]
images_map[ 4284046165 ]
images_map[ 4284902241 ]
images_map[ 4289239953 ]
images_map[ 4282200377 ]
images_map[ 4289440688 ]
When my current_rgb is for example 4285046165 it is OK, but if there is some value greater than greatest index, program crashes. What am I doing wrong?
Possibly because .value() tries to de-reference a non-existing item?
This looks like your own custom map implementation (or wrapper), but your logic appears to be incorrect
You call lowerBound every time - except if the item you are looking for is the first in the map
If it is the first in the map, you do a search again???
If it's not you search again (which if already found is repeating the operation again), else if not found, looks for nearest (which is okay), however do you handle the case where there is none (i.e. in lowerBound)?
The logic should be something like:
it = images_map.find(current_rgb);
if(it == images_map.end())
{
it = images_map.lowerBound(current_rgb);
if (it == images_map.begin())
{
it = images_map.upperBound(current_rgb);
if (it == images_map.end())
// throw error
}
// now you know you have a valid iterator - de-reference
mi = *it.value();
}
Call
images_map.upperBound(current_rgb)
May return
images_map.end()
In that case you should not call value().
You can solve the iterator out of range problem by adding sentinel values 0x000000 and 0xFFFFFF (once). That way, you always have a valid lower- and upperbound. Of course, this may affect the outcome of your algorithm. E.g. if your "smallest" real color was pure blue (0x0000FF), then dark blue (0x00007F) will now find black, not pure blue. This is easily fixed by two comparisons, of course.
With the sentinels in place, call QMap::lower_bound. You need to check whether you've actually found a precise match: if *lower_bound is the value you want, return it. Else, lower_bound points to the first element that's bigger than your input. Therefore, --lowerbound points to the last element that's smaller than your input. Check which of the two is closer.
Note that the only way lower_bound can point to begin is when your input is precisely 0x000000 (the sentinel), in which case you won't get to --lower_bound. No range error there. By the same logic, the end sentinel 0xFFFFFF means you'll always find an lower_bound.

How to print out a BST in C++

My C++ program creates a binary search tree. I know how to print out the values in pre-order, post-order, and in-order.
However, I want to do something a little more difficult. I want to print out the values the way they would look if someone drew the tree on paper. It would have the root at the center at the top, it's left child right under and to the left of it, and it's right child right under and to the right of it. The rest of the nodes would be drawn accordingly.
How can I do that?
This article contains code for what you need, it seems:
alt text http://www.cpp-programming.net/wp-content/uploads/2007/12/ascii_tree.jpg
Edit: that site went offline
Here's another one exploring some other options.
Here's approximate pseudo-code to do it. The basic idea is walk the tree layer-by-layer, printing all the node in each layer on one line. Each node is separated by twice as much space as the nodes below it. Since the tree is not all of uniform depth, it is artificially padded with virtual nodes to take up the blank spaces where nodes don't exist.
measure the depth of the tree, call that D
have two queues, called Q1 and Q2
enque the top node of the tree in Q1
for (i = D; --i>=0; ){
foreach node in Q1 {
on first iteration of this inner loop, print 2^i - 1 spaces,
else print 2^(i+1) - 1 spaces.
if node == null print blank
else print node.value
if node.left exists enque node.left in Q2
else enque null in Q2
if node.right exists enque node.right in Q2
else enque null in Q2
}
copy Q2 to Q1
clear Q2
print end-of-line
}
Each space that is printed is the width of one numeric field. Suppose the tree has depth D = 4. Then the printing goes like this:
// it looks like this, and the space sequences are
i = 3: -------n 7
i = 2: ---n-------n 3 7
i = 1: -n---n---n---n 1 3 3 3
i = 0: n-n-n-n-n-n-n-n 0 1 1 1 1 1 1 1
void print(node *p,int start)
{
start++;
if (p->right != NULL)
{
print(p->right,start);
}
for (int i = 0; i <= start; i++)
{
cout<<" ";
}
cout << p->value<<endl;
if (p->left != NULL)
{
print(p->left, start);
}
}
One way is to use graphviz. Specifically, use its "dot" program, but getting the output to look exactly as you describe may not be possible.
well, in a terminal it's hard...since it may not fit. But there are graph drawing libraries out there that can make nice pictures for you. There is graphvis that is one of the most popular.
edit:
if you really just wan to print text, graphvis has a markup language that a user can pass to graphvis that in turn makes the nice pictures.