binary tree traversal why need to check pre->right != current - c++

In a binary tree traversal algorithm like below cited from this question, why do we need to check the second condition
pre->right != current? is this a loop condition? when would this happen?
pre = current->left;
while(pre->right != NULL && pre->right != current)
pre = pre->right;

Because the latter code makes a cycle (i.e. child pointing to a parent):
pre->right = current;
The cycle is deleted later, however, but the pre->right != current test tris to avoid following the cycle endlessly.

Consider the tree given below,
A
/ \
B C
/ \ /\
D E F G
The node A which is the root is initialized as current. Now the code given by you tries to find out the immediate predecessor of A in inoreder traversal. As we know the inorder traversal of the given tree is as follows,
D B E A F C G
So the code identifies E as the immediate predecessor of A.

[Pertaining to your Question-code]
Assume tree:
A
/ \
B C
It's In-order traversal = B,A,C
Now consider, B was already printed by
if(current->left == NULL)
{
printf(" %d ", current->data);
current = current->right;
}
So, The Condition:
pre->right != current
is required to break while loop (which may be cyclic at times), exactly when our aim is to print node A.
In this case, at the end of the while loop i.e. while(pre->right != NULL && pre->right != current), we'll have :
1) pre pointing to left node B - which is already printed
2) current pointing to middle node A - Next to be print, thus breaking cycle link we've created just for this. Following part takes care of this:
else
{
pre->right = NULL; // Break cyclic link we've created for printing 'A'
printf(" %d ",current->data);// prints 'A'
current = current->right; // Now, Aim for 'C'
}

Related

Linked list operation on nodes (floyd cycle detection)

Structure
SinglyLinkedListNode {
int data;
SinglyLinkedListNode* next;
};
Function
bool has_cycle(SinglyLinkedListNode* head) {
SinglyLinkedListNode* s=head,*f=head->next;
while(s != NULL && f != NULL && f->next != NULL)
{
s = s->next;
f = f->next->next;
if(s->data == f->data)
return true;
}
return false;
}
According to the algorithm, if the slow pointer s and fast pointer f arrive on the same node the list is said to have a cycle. I'm assuming the same node will have the same data but then why am I getting failed test cases?
When I change (s->data = f->data) to (s == f) it works fine.
What is the difference between s == f and s->data == f->data?
The main issue here is your final checking condition. This will fail in a test case where there can be duplicates present (in the loop). When you are checking for the "same node" checking if the pointer value is same is better because it will always be unique, i.e., every node has an unique address but it is not necessary for it to be true for the value the node contains. For example:
1 -> 3 ->4 ->5 -> 6 -> 4 -> 7 -> NULL
//Note giving relative indexing(0th, 1st, .. and random addressing for understanding)
Iter 1: s is at 1(0th node, 1000010092) while f is at 3(1st node, 21983193)
Iter 2: s is at 3(1st node, 21983193) while f is at 5(3rd node, 129764714)
Iter 3: s is at 4(2nd node, 12984124) while f is at 4(5th node, 149284124)
See the ambiguity!!
Even though your algorithm is giving a TRUE a cycle doesn't exist.
But if you checked by the addressing, this false positive wouldn't have happened.
Tip: check if there are duplicates in any problem, they tend to be added to bring up such issues.

Building a binary tree from a string

I'm trying to build a tree from a string. The string is of the form: ((. (.A.E))(.I.O)), where the 5 leaf nodes of the tree are represented with a period.
I'm unable to determine how to solve this problem; I've tried tweaking the solution to a similar problem offered on this website: https://www.geeksforgeeks.org/construct-binary-tree-string-bracket-representation/.
Would really appreciate any help you could provide, as I prepare for coding interviews.
Thanks!
As I see this, there are just some rules to be followed. Based on the character being processed you have the following options:
If it's a "(", it means you must build your tree deeper, either to the left or to the right, based on the actions you took prior to this one
If it's a ".", you should read the next element in the string to determine the node value and after that you should go back one step in the recursion as the "." represents a leaf
If it's a ")", that means you finished building the subtree of a node and so you must go back one step in the recursion again
Some advices about how to implement this:
Write a recursive function that takes a string as input
The function should also return a string representing the string that remains to be further processed
If at any step your string is empty it means that the string given to be processed is not valid
You should check for the ")" every time you finish building the left or right subtree of a node
Hope this helps and good luck at your interviews!
The solution that I came up with is an iterative solution based on a stack. It has a few rules to follow:
push anything that comes to the stack
If you encounter ) of the stack, start removing elements untill you encounter a (, and then pop that out too.
When you pop the elements in step 2, store them in a vector, except ) and (.
Create a tree Node and mark the parent's children as all the elements in the vector.
push the parent Node back onto the stack.
Let's see with your example:
S = "((a($Z))(An))", changed ' ' -> 'a' for clarity.
Note: Stack growing towards the right.
Stack["((a($Z"]
encounter ')'
Stack["((a"], vector<"Z$">
reverse vector -> vector<"$Z">
Parent Node -> N(id='1'), children -> <N(id='$'), N(id='Z')>
push N(1) to stack
Stack["((a1]
encounter ')'
Stack["("], vector<"1a">
reverse vector -> vector<"a1">
Parent Node -> N(id='2'), children -> <N(id='a'), N(id=1)>
push N(2) to stack
Stack["(2(An"]
encounter ')'
...
you can continue this to get to the top. When you are done, i.e. the string is exhausted, you will get exactly one element left in the stack which would be your parent element or the root of the tree.
Code:
Node* solve(string s) {
stack<Node *> st;
int idx = 0, rt = 1;
while (idx < s.size()) {
Node *n = get_node(s[idx]);
st.push(n);
++idx;
if (st.top()->v == ')') {
st.pop();
vector<Node *> child;
while (st.size() && st.top()->v != '(') {
child.push_back(st.top()); st.pop();
}
if (st.top()->v == '(') st.pop();
Node *par = get_node('0' + rt++);
reverse(child.begin(), child.end());
for (Node *t : child) {
t->parent = par;
par->child.push_back(t);
}
st.push(par);
}
}
return st.top();
}
Full Working code
This code is a general implementation, so any node can have as many children, so n-arry tree construction.
eg:
input: ((a($Zk))(An))
output:
Parent: 4: 2 3
Parent: 2: a 1
Parent: 3: A n
Parent: 1: $ Z k

Wrong output when merging linked lists

Currently I have the following function to merge two sorted linked lists of type mylist. At the moment, there are some bugs that I have not been able to pinpoint and fix so far. What the function is basically supposed to do is, lets say A = 1 2 3 and B = 3 4 5. Then when I merge both (assuming both lists are sorted), A will become 1 2 3 3 4 5 and B will become null.
At the moment, for example when I try, A = 1 2 3 and B = 4 5 6 and merge both, A becomes 6 and B becomes 4. I know there are problems with the algorithm but I've not been able to pinpoint and fix yet. I'm new to programming. Any help will be appreciated!
void mylist::merge(mylist& b)
{
if (!this->isSorted() || !b.isSorted())
cout << "error" << endl;
Node* ptr1 = b.head;
Node* prev_a = NULL;
Node* curr_a = head;
Node* curr_b = ptr1;
while (curr_b) {
if (curr_a && head < ptr1) {
prev_a=curr_a;
curr_a = curr_a->next;
}
else {
Node* b_next = curr_b->next;
curr_b->next = curr_a;
if (prev_a) prev_a->next = curr_b;
else head = curr_b; // curr_b is first element in 'a'
if (curr_a) {
prev_a = curr_a;
curr_a = curr_a->next;
}
curr_b = b_next;
}
}
return;
}
EDIT:
I have made the following changes as mentioned but I still get A = 6 and B = 4 after merging A = 1 2 3 & B = 4 5 6.
void mylist::merge(mylist& b)
{
if (!this->isSorted() || !b.isSorted())
cout << "error" << endl;
Node* ptr1 = b.head;
Node* prev_a = NULL;
Node* curr_a = head;
Node* curr_b = ptr1;
while (curr_b) {
if (curr_a && head->key < ptr1->key) {
prev_a=curr_a;
curr_a = curr_a->next;
}
else {
Node* b_next = curr_b->next;
curr_b->next = curr_a;
if (prev_a) prev_a->next = curr_b;
else head = curr_b; // curr_b is first element in 'a'
prev_a = curr_a;
curr_b = b_next;
}
return;
}
1) Sorting problem:
in your instruction
if (curr_a && head < ptr1) { // argh !!!
you compare two pointers to Node (i.e. their addresses) and not the value pointed to.
2) Extreme case (that applies to your test data):
If first element of list b is greater than any elements of list a (supposing that you've corrected problem #1), then you will loop until curr_a is null, without ever having set prev_a. You would then insert the elements of b at the head of a (in the reverse order)
3) First merge in the middle of list a:
In a normal merge, you could cycle through list a until you have the first element of list b which is smaller than the element of a. prev_ais still not set at this moment. So you'll connect the next-element of current-element of b to the current element of a (which is ok), but then, as prev_a is NULL, you'll connect the head of a to the current element of b, thus LOOSING the whole chain of elements in a that were before the current one.
Steps to the solution:
If it's for an assignment given by your teacher:
while (curr_b) {
if (curr_a && curr_a->key < curr_b->key) { // assuming data is stored in the node and has a comparator defined
prev_a = curr_a; // keep track of it (WAS MISSING)
curr_a = curr_a->next;
}
else {
Node* b_next = curr_b->next;
curr_b->next = curr_a;
if (prev_a) prev_a->next = curr_b;
else head = curr_b;
prev_a = curr_b; // THE ELEMENT you've inserted is now prev_a
// curr_a SHALL not change since the next element of b can also be smaller than it
curr_b = b_next;
}
}
If it's for real code, you should really consider standard <list> container and its existing merge() function ;-)
EDIT: I've just realised that there was another issue and updated also the else part in the loop above. And I realized I was so focused on the key comparison, that I didn't notcie the wrong pointers were used, so that it didn't succeed in all the test cases !
The comparison 'head < ptr1' is meaningless. Those are pointers, not values.
ptr1 seems redundant with curr_b
You seem to start by looking for the tail of A. Why not make that a function in its own right?
Continuing with that divide and conquer approach, I'd make functions that test if a list is empty, pop the head off a list returning what it popped, and a function that appends something to the end. Then your final answer is:
mylist::merge(mylist &b) {
while (!b.empty())
push_back(b.pop_front());
}

Making adjacency list, weird bug?

Edit: Original problem fixed.
New problem: While loop doesn't break for or statement:
while(m->next != NULL || m->val != n)
{
cout<<"Looking for main node. Comparing"<<n<<" to "<<m->val<<endl;
m = m->next;
}
It prints out all the comparisons, including the two that are exactly alike. Any reason why this wouldn't be breaking it?
m = NULL is assignment statement, m == NULL is the comparison statement to be used in your if statement
Note:
Checking m for NULL should be done before using it for even printing (in cout)
If you want to continue the while loop till the last element or till val equals n, then it should be like this
while(m != NULL && m->val != n)
{
cout<<"Looking for main node. Comparing"<<n<<" to "<<m->val<<endl;
m = m->next;
}

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.