Related
So, I'm working on this project for Comp 272, Data Structures and Algorithms, and before anyone asks I have no one to help me. It's an online program through Athabasca University and for some unknown reason they didn't supply me with a tutor for this course, which is a first... So... Yeah. The question is as follows:
"(20 marks) Exercise 8.2. Illustrate what happens when the sequence 1, 5, 2, 4, 3 is added to an empty ScapegoatTree, and show where the credits described in the proof of Lemma 8.3 go, and how they are used during this sequence of additions."
This is my code, its complete and it compiles:
/*
Name: Westcott.
Assignment: 2, Question 3.
Date: 08-26-2022.
"(20 marks) Exercise 8.2. Illustrate what happens when the sequence 1, 5, 2, 4, 3 is added to an empty
ScapegoatTree, and show where the credits described in the proof of Lemma 8.3 go, and how they are used
during this sequence of additions."
*/
#include <iostream>
using namespace std;
class Node { // Originally I did this with Node as a subclass of sgTree but I found that this
public: // way was easier. This is actually my second attempt, from scratch, at doing this
int data; // problem. First version developed so many bugs I couldn't keep up with them.
Node* left;
Node* right;
Node* parent;
Node() : data(0), parent(NULL), left(NULL), right(NULL) {};
Node(int x) : data(x), parent(NULL), left(NULL), right(NULL) {};
~Node() {}; // Normally I would do a little more work on clean up but... Yea this problem didn't leave me much room.
Node* binarySearch(Node* root, int x); // The Node class only holds binarySearch in addition to its
// constructors/destructor, and of course the Node*'s left, right and parent.
};
class sgTree { // The sgTree keeps track of the root, n (the number of nodes in the tree), and q which is
public: // as Pat put it a 'high water mark'.
Node* root;
int n;
int q;
sgTree() : root(new Node()), n(1), q(1) {}
sgTree(int x) : root(new Node(x)), n(0), q(0) {}
~sgTree() {
delete root;
}
bool add(int x); // The add function is compounded, within it are findDepth and rebuild.
bool removeX(int x); // removeX works, but it didn't have a big part to play in this question,
int findDepth(Node* addedNode); // but I'll include it to maintain our sorted set interface.
void printTree(Node* u, int space) { // This was extra function I wrote to help me problem solve.
cout << "BINARY TREE DISPLAY" << endl; // this version only prints a title and then it calls printTreeSub on line 46.
cout << "________________________________________________\n\n" << endl;
printTreeSub(u, space);
cout << "________________________________________________\n\n" << endl;
}
int printTreeSub(Node* u, int space); // Function definition for this is on line 81.
int storeInArray(Node* ptr, Node* arr[], int i);// this is our function for storing all the elements of a tree in an array.
int size(Node* u); // this is size, defined on line 74.
void rebuild(Node* u); // And rebuild and buildBalanced are the stars of the show, defined on lines 262 and 282
Node* buildBalanced(Node** a, int i, int ns); // just above the main() funciton.
};
int log32(int q) { // As you can see there's two versions of this function.
int c = 0; // this is supposed to return the log of n to base 3/2.
while (q != 0) { // The version below I got from this website:
q = q / 2; // https://www.geeksforgeeks.org/scapegoat-tree-set-1-introduction-insertion/
c++; // It works fine but I prefer the one I wrote.
} // this is a much simpler function. It just divides q until its zero
return c; // and increments c on each division. Its not exact but it is based on what Pat said
} // in this lecture: https://www.youtube.com/watch?v=OGNUoDPVRCc&t=4852s
/*
static int const log32(int n)
{
double const log23 = 2.4663034623764317;
return (int)ceil(log23 * log(n));
}
*/
int sgTree::size(Node* u) {
if (u == NULL) {
return 0;
}
return 1 + size(u->left) + size(u->right); // Recursion in size();
}
int sgTree::printTreeSub(Node* u, int space) { // Here is my strange print function
if (u == NULL) return space; // I say strange because I'm not even 100% sure
space--; // how I got it to work. The order itself I worked out, but I built it
space -= printTreeSub(u->left, space); // and, originally, got a half decent tree, but then I just kept playing
if (u->right == NULL && u->left == NULL) { // around with increments, decrements, and returned values
cout << "\n\n\n" << u->data << "\n\n\n" << endl; // of space until it just sort of came together.
return 1; // Basically it prints the left most Node first and then prints every node
} // beneath that using recursion. I realized that by setting the for loop
for (int i = space; i >= 0; i--) { // on line 89 I could imitate different nodes having different heights in
cout << " "; // the tree. I figured that using n as an input I could take advantage of
} // the recursion to get an accurate tree. That much I understand.
cout << " " << u->data << "'s children are: "; // But it didn't work out quite how I wanted it to so I just kept playing
if (u->left != NULL) { // with space increments and decrements on different sides of the tree until
cout << u->left->data; // I got something pretty good.
}
else {
cout << "NULL";
}
if (u->right != NULL) {
cout << " and " << u->right->data;
}
else {
cout << " NULL";
}
cout << "\n\n" << endl;
space--;
space -= printTreeSub(u->right, space);
return 1;
}
int sgTree::storeInArray(Node* ptr, Node* a[], int i) { // This function took me a while to figure out.
if (ptr == NULL) { // The recursive insertions of values using i, when
return i; // i is defined by the very same recursion, makes this
} // a bit of a challenge to get your head around.
i = storeInArray(ptr->left, a, i); // Basically its just taking advantage on an inOrder
a[i] = ptr; // transversal to get the values stored into the array
i++; // in order from least to greatest.
return storeInArray(ptr->right, a, i);
}
Node* Node::binarySearch(Node* root, int x) { // I covered this in another question.
if (root->data == x) {
return root;
}
else if (x < root->data) {
if (root->left == NULL) {
return root;
}
return binarySearch(root->left, x);
}
else if (x > root->data) {
if (root->right == NULL) {
return root;
}
return binarySearch(root->right, x);
}
}
bool sgTree::add(int x) { // The add function itself isn't too difficult.
Node* addedNode = new Node(x); // We make a Node using our data, then we search for that Node
Node* parent = root->binarySearch(root, x); // in the tree. I amended binarySearch to return the parent
addedNode->parent = parent; // if it hits a NULL child, on lines 127 and 133.
if (x < parent->data) { // That way the new Node can just go into the returned parents child
parent->left = addedNode; // here is where we choose whether it enters the left or the right.
}
else if (x > parent->data) {
parent->right = addedNode;
}
int h = findDepth(addedNode); // We run findDepth() on the addedNode. I realize that this probably should
// have been a part of the binarySearch, it means we go down
if (h > log32(q)) { // the tree twice instead of once. I did look at changing binarySearch into searchAndDepth
// having binarySearch return an int for the height isn't a problem, but then that would
// mess up removeX and, I don't know. What's more important?
Node* w = addedNode->parent; // If this were going to be a database hosting millions of pieces of data I would give
while (3 * size(w) < 2 * size(w->parent)) { // that alot more consideration but, this is just an exercise after all so...
w = w->parent; // From there, we compare our height to the value output by log32(q) on line 152.
}
rebuild(w); // This expression 3 * size(w) < 2 * size(w->parent) is the formula on page 178 rewritten
//rebuild(root); // as a cross multiplication, clever. It keeps going up the tree until we find the scapegoat w.
// This is a much nicer result.
//See line 311.
} // Now, this is where my problems began. Pat says that this line should read: rebuild(w->parent);
n++; // but when I do that I get an error when w is the root. Because then w->parent is NULL. And in that case
q++; // line 258 throws an error because we're trying to set p equal to NULL's parent. It's not there.
return true; // So my work around was to just offset this by one and send rebuild(w). But that doesn't seem
} // to balance the tree just right. In fact, the best tree results when we replace w with root.
// and just rebalance the whole tree. But in any case, we increment n and q and lets pick this up on line 256.
int sgTree::findDepth(Node* addedNode) {
int d = 0;
while (addedNode != root) {
addedNode = addedNode->parent;
d++;
}
return d;
}
bool sgTree::removeX(int x) {
Node* u = root->binarySearch(root, x);
if (u->left == NULL && u->right == NULL) {
if (u == u->parent->left) {
u->parent->left = NULL;
}
if (u == u->parent->right) {
u->parent->right = NULL;
}
cout << u->data << " deleted" << endl;
n--;
delete u;
return true;
}
if (u->left != NULL && u->right == NULL) {
if (u->parent->left = u) {
u->parent->left = u->left;
}
else if (u->parent->right = u) {
u->parent->right = u->left;
}
cout << u->data << " deleted" << endl;
n--;
delete u;
return true;
}
if (u->left == NULL && u->right != NULL) {
if (u == u->parent->left) {
u->parent->left = u->right;
u->right->parent = u->parent;
}
else if (u == u->parent->right) {
u->parent->right = u->right;
u->right->parent = u->parent;
}
cout << u->data << " deleted" << endl;
n--;
delete u;
return true;
}
if (u->left != NULL && u->right != NULL) {
Node* X = u->right;
if (X->left == NULL) {
X->left = u->left;
if (u->parent != NULL) {
if (u->parent->right == u) {
u->parent->right == X;
}
else if (u->parent->left == u) {
u->parent->left = X;
}
}
else {
root = X;
}
X->parent = u->parent;
cout << u->data << " deleted" << endl;
n--;
delete u;
return true;
}
while (X->left != NULL) {
X = X->left;
}
X->parent->left = NULL;
X->left = u->left;
X->right = u->right;
if (u->parent != NULL) {
X->parent = u->parent;
}
cout << u->data << " deleted" << endl;
n--;
root = X;
delete u;
return true;
}
}
void sgTree::rebuild(Node* u) {
int ns = size(u); // Everything is pretty kosher here. Just get the number of nodes in the subtree.
Node* p = u->parent; // Originally I had n here instead of ns and... I don't want to talk about how long it took me to find that mistake...
/* It's funny because while writing the comments for this I'm like "Oh, hang on, if I just push the definition of p behind the if statement on line 262
and evaluate for whether or not u is NULL instead of p, that should solve all my problems! Yea, no, it doesn't. Because then for some reason it tries rebalancing
empty tree and... Yea I just have to stop myself from trying to fix this because everytime I do I get caught in an infinite loop of me chasing my tail in errors.
I think a solution could be found in buildBalanced, and I literally went through that function line by line, trying to comprehend a work around. I've included at
a photograph of that white board. Yea this is the code that Pat gave us... and its garbage. It doesn't work. Maybe its a C++ thing, I don't know... But I'm
getting frustrated again so I'm going to stop thinking about this part RIGHT HERE, and move on LOL*/
Node** a = new Node * [ns]; // a Node pointer-pointer array... again, another fine piece of code from the textbook. Sorry, trying to stay positive here.
storeInArray(u, a, 0); // See Line 112
if (p == NULL) { // Okay, once we have our array we use buildBalanced to rebuild the subtree with respect to which
root = buildBalanced(a, 0, ns); // child u is relative to its parent.
root->parent = NULL; // See line 281 for buildBalanced().
}
else if (p->right == u) {
p->right = buildBalanced(a, 0, ns);
p->right->parent = p;
}
else {
p->left = buildBalanced(a, 0, ns);
p->left->parent = p;
}
}
Node* sgTree::buildBalanced(Node** a, int i, int ns) { // This is without a doubt one of the hardest functions I've ever had
if (ns == 0) { // the displeasure of trying to understand... Trying to stay positive.
return NULL; // I've gone through it, in a line by line implementation of the array:
} // a[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10} you can find that analysis in
int m = ns / 2; // the photo buildBalanced_Analysis.
a[i + m]->left = buildBalanced(a, i, m); // As confusing as it is, I have to admit that it is a beautiful function.
if (a[i + m]->left != NULL) { // It basically uses the two integers i and m to simultaneously
a[i + m]->left->parent = a[i + m]; // regulate the organization of the new tree and to specifically
} // grab the right value from the array when its needed.
a[i + m]->right = buildBalanced(a, i + m + 1, ns - m - 1); // but trying to map this out didn't help me to solve the issues I've been having.
if (a[i + m]->right != NULL) {
a[i + m]->right->parent = a[i + m];
}
return a[i + m];
}
int main() {
sgTree newTree(1);
int a[] = { 5, 2, 4, 3 };
for (int i = 0; i < (sizeof(a) / sizeof(a[0])); i++) {
newTree.add(a[i]);
}
newTree.printTree(newTree.root, newTree.n);
/*
This is a nice test, when paired with rebuild(root), that too me is the only thing that approaches redeeming this whole question.
sgTree newTreeB(1);
int b[] = { 2, 3, 4, 5, 6, 7, 8, 9, 10 };
for (int i = 0; i < (sizeof(b) / sizeof(b[0])); i++) {
newTreeB.add(b[i]);
}
newTreeB.printTree(newTreeB.root, newTreeB.n);
*/
}
Now the issue itself is not that hard to understand. My tree should look like this:
But instead, it looks like this, with 5 at the root and the values 1 and 4 as the leaves:
I'm confident that the problem lives somewhere around line 159 and in those first few calls to buildBalanced. The comments in the code itself elaborate more on the issue. I've spent days just pouring over this trying everything I can think of to make it work and... Yeah... I just can't figure it out.
As you will see in the below output, nodes with values 10 and 15 are not being added.
The whole code is below
..............
.............
...............
..............
.............
#include<iostream>
using namespace std;
#define SPACE 10
class TreeNode{
public:
int value;
TreeNode *left;
TreeNode *right;
TreeNode(){
value = 0;
left = NULL;
right = NULL;
}
TreeNode(int v){
value = v;
left = NULL;
right = NULL;
}
};
class BST{
public:
TreeNode *root;
BST(){
root = NULL;
}
bool isEmpty(){
if(root == NULL)
return true;
else
return false;
};
void insertNode(TreeNode *new_node){
if(root == NULL){
root = new_node;
cout<<"Node entered at root"<<endl;
}
else{
TreeNode *temp = root;
while(temp!=NULL){
if(new_node->value == temp->value){
cout<<"Node already exist"<<endl;
break;
}
else if((new_node->value < temp->value) && (temp ->left == NULL)){
temp->left = new_node;
cout<<"Inserted at right"<<endl;
break;
}
else if (new_node->value < temp->value){
temp = temp->left;
break;
}
else if((new_node->value > temp->value) && (temp ->right == NULL)){
temp->right = new_node;
cout<<"Inserted at left"<<endl;
break;
}
else if (new_node->value > temp->value){
temp = temp->right;
break;
}
}
}
}
void print2D(TreeNode * r, int space) {
if (r == NULL) // Base case 1
return;
space += SPACE; // Increase distance between levels 2
print2D(r -> right, space); // Process right child first 3
cout << endl;
for (int i = SPACE; i < space; i++) // 5
cout << " "; // 5.1
cout << r -> value << "\n"; // 6
print2D(r -> left, space); // Process left child 7
}
};
int main(){
BST obj;
int option, val;
do {
cout << "What operation do you want to perform? " <<
" Select Option number. Enter 0 to exit." << endl;
cout << "1. Insert Node" << endl;
//cout << "2. Search Node" << endl;
//cout << "3. Delete Node" << endl;
cout << "2. Print/Traversal BST values" << endl;
//cout << "5. Height of Tree" << endl;
//cout << "6. Clear Screen" << endl;
cout << "0. Exit Program" << endl;
cin >> option;
//Node n1;
TreeNode *newNode = new TreeNode();
switch (option){
case 0:
break;
case 1:
cout<<"Insert Node"<<endl;
cout<<"Enter the value of the node"<<endl;
cin>>val;
newNode->value = val;
obj.insertNode(newNode);
break;
case 2:
cout<<"Print value"<<endl;
obj.print2D(obj.root, 5);
break;
default:
cout<<"Enter appropriate option"<<endl;
} //switch
}while(option!=0);
}
OUTPUT:
What operation do you want to perform? Select Option number. Enter 0 to exit.
1. Insert Node
2. Print/Traversal BST values
0. Exit Program
1
Insert Node
Enter the value of the node
30
Node entered at root
What operation do you want to perform? Select Option number. Enter 0 to exit.
1. Insert Node
2. Print/Traversal BST values
0. Exit Program
1
Insert Node
Enter the value of the node
18
Inserted at right
What operation do you want to perform? Select Option number. Enter 0 to exit.
1. Insert Node
2. Print/Traversal BST values
0. Exit Program
1
Insert Node
Enter the value of the node
45
Inserted at left
What operation do you want to perform? Select Option number. Enter 0 to exit.
1. Insert Node
2. Print/Traversal BST values
0. Exit Program
1
Insert Node
Enter the value of the node
10
What operation do you want to perform? Select Option number. Enter 0 to exit.
1. Insert Node
2. Print/Traversal BST values
0. Exit Program
1
Insert Node
Enter the value of the node
15
What operation do you want to perform? Select Option number. Enter 0 to exit.
1. Insert Node
2. Print/Traversal BST values
0. Exit Program
2
Print value
45
30
18
As you see the node 10 and 15 is not being added to the tree. I've tried every single way.
Plz if anyone has solution do provide it. Thank you
Make temp=temp->left in first else if block and remove second else if block and do same for 3rd and 4 th else if block
I am trying to mirror the binary tree without recursive methods by using two queues and a binary tree which I have created.
Following is the function which i have used.
root is the pointer to the root node of the original binary tree and mirrior_root is of a mirrored binary tree.
The error seems to be lies in the logic part !
Help would be appreciated !
#include<iostream>
#include<queue>
using namespace std;
class Node
{
public:
Node *lchild;
int data;
Node *rchild;
};
class Tree
{
public:
Node *root;
Node *mirror_root;
Tree()
{
root = NULL;
}
void create_Tree()
{
Node *p;
Node *t;
int x;
queue <Node *> q;
root = new Node ;
cout << "Enter the data you want to insert in root";
cin >> x;
root->data = x;
root->lchild = root ->rchild = NULL;
q.emplace(root);
while(! q.empty())
{
p = q.front();
q.pop();
cout << "Enter the left child of " << p->data << ":";
cin >> x;
if(x != -1)
{
t= new Node;
t->data = x;
t->lchild = t->rchild = NULL;
p->lchild = t;
q.emplace(t);
}
cout << "Enter the right child of " << p->data << ":";
cin >> x;
if(x != -1)
{
t= new Node;
t->data = x;
t->lchild = t->rchild = NULL;
p->rchild = t;
q.emplace(t);
}
}
}
void Preorder(Node *p)
{
if(p)
{
cout << p->data << " " ;
Preorder(p->lchild);
Preorder(p->rchild);
}
}
void Level_order(Node *p)
{
queue <Node *> q;
q.emplace(p);
cout << p->data << " " ;
while(!q.empty())
{
p = q.front();
q.pop();
if(p->lchild)
{
cout << p->lchild->data << " ";
q.emplace(p->lchild);
}
if(p->rchild)
{
cout << p->rchild->data << " ";
q.emplace(p->rchild);
}
}
}
void mirror_tree(Node *p)
{
Node *mirror_root;
Node *t;
Node *k;
queue <Node *> q_root;
queue <Node *> q_mirror;
mirror_root = new Node;
mirror_root->data = p->data;
mirror_root->lchild = mirror_root->rchild = NULL;
t=mirror_root;
q_root.emplace(p);
q_mirror.emplace(t);
while(!q_root.empty())
{
p=q_root.front();
q_root.pop();
t = q_mirror.front();
q_mirror.pop();
if(p->lchild)
{
k = new Node;
k->data = p->lchild->data;
k->lchild = k->rchild = NULL;
t->rchild = k;
q_root.emplace(p->lchild);
q_mirror.emplace(t->rchild);
}
if(p->rchild)
{
k = new Node;
k->data = p->rchild ->data;
k->lchild = k->rchild = NULL;
t->lchild = k;
q_root.emplace(p->rchild);
q_mirror.emplace(t->lchild);
}
}
}
};
int main()
{
Tree bt;
bt.create_Tree();
bt.mirror_tree(bt.root);
cout << "Level order of mirrored binary tree is : ";
bt.Level_order(bt.mirror_root);
}
Here is input and output
Enter the data you want to insert in root: 5
Enter the left child of 5:6
Enter the right child of 5:7
Enter the left child of 6:8
Enter the right child of 6:9
Enter the left child of 7:10
Enter the right child of 7:11
Enter the left child of 8:-1
Enter the right child of 8:-1
Enter the left child of 9:-1
Enter the right child of 9:-1
Enter the left child of 10:-1
Enter the right child of 10:-1
Enter the left child of 11:-1
Enter the right child of 11:-1
Level order of mirrored binary tree is : 7769539
Output which i expected is
Level order of mirrored binary tree is 5 7 6 11 10 9 8
The problem is that you declare Node *mirror_root as a local variable in mirror_tree, while you want the code to give a value to the class member with the same name.
So remove that line from the mirror_tree function.
I have been asked in an interviews to print the boundary of the Binary Tree. For example.
1
/ \
2 3
/ \ / \
4 5 6 7
/ \ \
8 9 10
Answer will be : 1, 2, 4, 8, 9, 10, 7, 3
I have given the following answer.
First Method :
I have used a Bool variable to solve the above problem.
void printLeftEdges(BinaryTree *p, bool print) {
if (!p) return;
if (print || (!p->left && !p->right))
cout << p->data << " ";
printLeftEdges(p->left, print);
printLeftEdges(p->right, false);
}
void printRightEdges(BinaryTree *p, bool print) {
if (!p) return;
printRightEdges(p->left, false);
printRightEdges(p->right, print);
if (print || (!p->left && !p->right))
cout << p->data << " ";
}
void printOuterEdges(BinaryTree *root) {
if (!root) return;
cout << root->data << " ";
printLeftEdges(root->left, true);
printRightEdges(root->right, true);
}
His Response : You have used Bool variable so many times. Can you solve this without using that.
Second Method :
I simply used tree traversal to solve this problem.
1. Print the left boundary in top-down manner.
2. Print all leaf nodes from left to right, which can again be sub-divided into two sub-parts:
2.1 Print all leaf nodes of left sub-tree from left to right.
2.2 Print all leaf nodes of right subtree from left to right.
3. Print the right boundary in bottom-up manner.
His Response : He was not happy with this method too. He told that you are traversing the tree 3 times. That is too much. Give another solution if you have any.
Third Method :
This time i have went for Level Order traversal (BFS).
1: Print starting and ending node of each level
2: For each other node check if its both the children are <b>NULL</b> then print that node too.
His Response : He was not seems happy with this method too because this method takes extra memory of order O(n).
My question is that Tell me a method which traverse tree single times, do not use any Bool variable and do not use any extra memory. Is it possible?
I guess this should do the trick:
traverse(BinaryTree *root)
{
if (!root) return;
cout << p->data << " ";
if (root->left ) traverseL(root->left ); //special function for outer left
if (root->right) traverseR(root->right); //special function for outer right
}
traverseL(BinaryTree *p)
{
cout << p->data << " ";
if (root->left ) traverseL(root->left ); //still in outer left
if (root->right) traverseC(root->right);
}
traverseR(BinaryTree *p)
{
if (root->left ) traverseC(root->left );
if (root->right) traverseR(root->right); //still in outer right
cout << p->data << " ";
}
traverseC(BinaryTree *p)
{
if (!root->left && !root->right) //bottom reached
cout << p->data << " ";
else
{
if (root->left ) traverseC(root->left );
if (root->right) traverseC(root->right);
}
}
Start with the traverse function.
Got rid of the null-queries at the beginning of each method (avoids one function call at each end).
Does not need bool variables, simply uses three different traversal methods:
one for the left edge, outputting the node before traversal
one for the right edge, outputting the node after traversal
one for all other nodes, outputting the node if there are no siblings.
Below is a recursive solution in Python3 with time complexity O(n). Algorithm here is to print left most nodes from top to bottom, leaf nodes from left to right and right most nodes from bottom to top. Adding boolean flags (isLeft,isRight) for left and right tree traversal simplifies the code and drives the time complexity of O(n).
#Print tree boundary nodes
def TreeBoundry(node,isLeft,isRight):
#Left most node and leaf nodes
if(isLeft or isLeaf(node)): print(node.data,end=' ')
#Process next left node
if(node.getLeft() is not None): TreeBoundry(node.getLeft(), True,False)
#Process next right node
if(node.getRight() is not None):TreeBoundry(node.getRight(), False,True)
#Right most node
if(isRight and not isLeft and not isLeaf(node)):print(node.data,end=' ')
#Check is a node is leaf
def isLeaf(node):
if (node.getLeft() is None and node.getRight() is None):
return True
else:
return False
#Get started
#https://github.com/harishvc/challenges/blob/master/binary-tree-edge-nodes.py
TreeBoundry(root,True,True)
Method O(n) No extra space and single traversal of tree.
I divided the Tree Nodes into four types of nodes
Type 1 -> Nodes which form the left boundary(eg 8)
Type 0 -> Nodes which do not form the boundar(eg 12)
Type 3 -> Nodes which form the right boundary(eg 22)
Leaf Nodes(eg 4,10,14)
In my method i am just doing recurrsion method of tree traversal (just modified) where my function is of this form
void recFunc(btNode *temp,int type)
{
//Leaf Nodes
if((temp->left == NULL)&&(temp->right == NULL))
cout << temp->data << " ";
// type -1 Nodes must be printed before their children
else if(type == 1)cout << temp->data << " ";
else {;}
if(type == 3)
{
if(temp->left)recFunc(temp->left,0);
if(temp->right)recFunc(temp->right,3);
//type 3 nodes must be printed after their children
cout << temp->data << " ";
}
else if(type == 1)
{
if(temp->left)recFunc(temp->left,1);
if(temp->right)recFunc(temp->right,0);
}
else if(type == 0)
{
if(temp->left)recFunc(temp->left,0);
if(temp->right)recFunc(temp->right,0);
}
else {;}
}
where i have modofied the
In my recurrsive function Nodes of type 1 must make their left nodes
as type 1 and must be printed before calling their children(if they
exist)
Nodes Of Type 3 must be printed in reverse order .So they must be
printed after call to their children.They must also assign their
right children as Type 3 Nodes
Nodes Of Type 0 must not be printed and they assign their children as
type 0 Nodes
Leaf Nodes must be directly printed only and return
Link to Code
//4 diff list for 4 different part of the solution
1)left border 2)right border 3)leaf in left tree 4)leaf in right tree
public class PRintBinaryTreeBoundary {
ArrayList<TreeNode> leftBorderList=new ArrayList<>();
ArrayList<TreeNode> leftLEafNode=new ArrayList<>();
ArrayList<TreeNode> rightBorderList=new ArrayList<>();
ArrayList<TreeNode> rightLEafNode=new ArrayList<>();
public static void main(String[] args) {
// TODO Auto-generated method stub
/* 1
/ \
2 3
/ \ / \
4 5 6 7
/ \ \
8 9 10*/
TreeNode one=new TreeNode(1);
TreeNode two=new TreeNode(2);
TreeNode three=new TreeNode(3);
TreeNode four=new TreeNode(4);
TreeNode five=new TreeNode(5);
TreeNode six=new TreeNode(6);
TreeNode seven=new TreeNode(7);
TreeNode eight=new TreeNode(8);
TreeNode nine=new TreeNode(9);
TreeNode ten=new TreeNode(10);
one.left=two; one.right=three;
two.left=four;two.right=five;
three.left=six;three.right=seven;
five.left=eight;
six.right=nine;
seven.right=ten;
PRintBinaryTreeBoundary p=new PRintBinaryTreeBoundary();
p.print(one);
}
private void print(TreeNode one) {
System.out.println(one.val);
populateLeftBorderList(one.left);
populateRightBorderList(one.right);
populateLeafOfLeftTree(one.left);
populateLeafOfRightTree(one.right);
System.out.println(this.leftBorderList);
System.out.println(this.leftLEafNode);
System.out.println(this.rightLEafNode);
Collections.reverse(this.rightBorderList);
System.out.println(this.rightBorderList);
}
private void populateLeftBorderList(TreeNode node) {
TreeNode n = node;
while (n != null) {
this.leftBorderList.add(n);
n = n.left;
}
}
private void populateRightBorderList(TreeNode node) {
TreeNode n = node;
while (n != null) {
this.rightBorderList.add(n);
n = n.right;
}
}
private void populateLeafOfLeftTree(TreeNode leftnode) {
Queue<TreeNode> q = new LinkedList<>();
q.add(leftnode);
while (!q.isEmpty()) {
TreeNode n = q.remove();
if (null == n.left && null == n.right && !this.leftBorderList.contains(n)) {
leftLEafNode.add(n);
}
if (null != n.left)
q.add(n.left);
if (null != n.right)
q.add(n.right);
}
}
private void populateLeafOfRightTree(TreeNode rightNode) {
Queue<TreeNode> q = new LinkedList<>();
q.add(rightNode);
while (!q.isEmpty()) {
TreeNode n = q.remove();
if (null == n.left && null == n.right && !this.rightBorderList.contains(n)) {
rightLEafNode.add(n);
}
if (null != n.left)
q.add(n.left);
if (null != n.right)
q.add(n.right);
}
}
}
Hope this helps:
// Java program to print boundary traversal of binary tree
/* A binary tree node has data, pointer to left child
and a pointer to right child */
class Node {
int data;
Node left, right;
Node(int item)
{
data = item;
left = right = null;
}
}
class BinaryTree {
Node root;
// A simple function to print leaf nodes of a binary tree
void printLeaves(Node node)
{
if (node != null) {
printLeaves(node.left);
// Print it if it is a leaf node
if (node.left == null && node.right == null)
System.out.print(node.data + " ");
printLeaves(node.right);
}
}
// A function to print all left boundary nodes, except a leaf node.
// Print the nodes in TOP DOWN manner
void printBoundaryLeft(Node node)
{
if (node != null) {
if (node.left != null) {
// to ensure top down order, print the node
// before calling itself for left subtree
System.out.print(node.data + " ");
printBoundaryLeft(node.left);
}
else if (node.right != null) {
System.out.print(node.data + " ");
printBoundaryLeft(node.right);
}
// do nothing if it is a leaf node, this way we avoid
// duplicates in output
}
}
// A function to print all right boundary nodes, except a leaf node
// Print the nodes in BOTTOM UP manner
void printBoundaryRight(Node node)
{
if (node != null) {
if (node.right != null) {
// to ensure bottom up order, first call for right
// subtree, then print this node
printBoundaryRight(node.right);
System.out.print(node.data + " ");
}
else if (node.left != null) {
printBoundaryRight(node.left);
System.out.print(node.data + " ");
}
// do nothing if it is a leaf node, this way we avoid
// duplicates in output
}
}
// A function to do boundary traversal of a given binary tree
void printBoundary(Node node)
{
if (node != null) {
System.out.print(node.data + " ");
// Print the left boundary in top-down manner.
printBoundaryLeft(node.left);
// Print all leaf nodes
printLeaves(node.left);
printLeaves(node.right);
// Print the right boundary in bottom-up manner
printBoundaryRight(node.right);
}
}
// Driver program to test above functions
public static void main(String args[])
{
BinaryTree tree = new BinaryTree();
tree.root = new Node(20);
tree.root.left = new Node(8);
tree.root.left.left = new Node(4);
tree.root.left.right = new Node(12);
tree.root.left.right.left = new Node(10);
tree.root.left.right.right = new Node(14);
tree.root.right = new Node(22);
tree.root.right.right = new Node(25);
tree.printBoundary(tree.root);
}
}
Boundary Traversal of binary tree
Below is a Java O(n) time complexity solution that solves the problem of counting duplicates (ex: left node that is also leaf node)
class Node {
Node left;
Node right;
int data;
Node(int d) {
data = d;
left = right = null;
}
}
class BinaryTree {
Node root;
public void getBoundary() {
preorderLeft(root);
inorderLeaves(root);
postorderRight(root);
}
public boolean isLeaf(Node node) {
if (node != null && node.left == null && node.right == null) return true;
return false;
}
public void preorderLeft(Node start) {
if (start != null && isLeaf(start) == false) System.out.print(start.data + " ");
if (start.left != null) preorderLeftSide(start.left);
}
public void inorderLeaves(Node start) {
if(start == null) return;
if(start.left != null) inorderLeaves(start.left);
if(start.left == null && start.right == null) System.out.print(start.data + " ");
if(start.right != null) inorderLeaves(start.right);
}
public void postorderRight(Node start) {
if(start.right != null) postorderRightSide(start.right);
if(start != null && isLeaf(start) == false) System.out.print(start.data + " ");
}
}
This YouTube video was very helpful. The author write comments explaining each method and shows how to skip duplicates. https://youtu.be/7GzuxmZ34cI
By using vertical distance from the root node and level we can solve it using list and map.
map<int,int>tmap; #store the vertical distance and level
list<int>llist; #store the node values
void Buildfunction(root,d, l){
if(root == NULL){
return;
} else if(tmap.count(d) == 0){
tmap[d] = l;
llist.push_back(root->data);
} else if((root->left == NULL && root->right==NULL) || tmap[d] < l){
tmap[d] = l;
llist.push_back(root->data);
}
Buildfunction(root->left,d--,l++);
Buildfunction(root->right,d++,l++);
}
where d pointing to vertical distance from current node respect to root
and l pointing to level of the current node starting from 0
The following python solution worked for me. It handles all the cases.
Based on the solution of #azt
class Node:
def __init__(self, data):
self.data = data
self.left = None
self.right = None
def printLeaves(root):
if (root):
printLeaves(root.left)
if root.left is None and root.right is None:
print(root.data),
printLeaves(root.right)
def printBoundaryC(node):
if not node.left or not node.right:
print(node.data)
if node.left:
printBoundaryC(node.left)
if node.right:
printBoundaryC(node.right)
def printBoundaryLeft(root):
print(root.data)
if root.left:
printBoundaryLeft(root.left)
if root.right:
printBoundaryC(root.right)
def printBoundaryRight(root):
if root.right:
printBoundaryRight(root.right)
elif root.left:
printBoundaryC(root.left)
print(root.data)
def printBoundary(root):
if (root):
print(root.data)
if root.left:
printBoundaryLeft(root.left)
if root.right:
printBoundaryRight(root.right)
root = Node(20)
root.left = Node(8)
root.left.left = Node(4)
root.left.right = Node(12)
root.left.right.left = Node(10)
root.left.right.left.right = Node(5)
root.left.right.right = Node(14)
root.right = Node(22)
root.right.right = Node(25)
printBoundary(root)
I am trying to solve this problem, I think I have come up with a correct answer, but I am keep getting WA (wrong answer) response from the judge.
http://uva.onlinejudge.org/index.php?option=onlinejudge&page=show_problem&problem=1452
The problem distilled, is, given a 1 - * relationship between party and person, 1 - * relationship between person and club. Find a 1 - 1 relationship between person and club such that for all person related to a club, the number of persons belong to a any party is less than half of the number of club.
For example, let say we have
Person1 belongs to Party1 and Club1, Club2
Person2 belongs to Party2 and Club2, Club3
Person3 Belongs to Party3 and Club3, Club1
There are two assignments possible.
Person1 Club1
Person2 Club2
Person3 Club3
and
Person1 Club2
Person2 Club3
Person3 Club1
My idea is to model this problem as a maximum flow problem as follow:
For simplicity, let say there are two parties, four persons, and three clubs.
0 is the master source
1, 2 are the nodes representing the two parties
3, 4, 5, 6 are the nodes representing the four persons
7, 8, 9 are the nodes representing the three clubs.
10 is the master sink
master source connects to each party with capacity = (3 + 1)/2 - 1 = 1. That represents there can only be at most 1 person of 1 party representing in the council (or otherwise 2 will be equals to or more than half)
for each party person pair, have a link of capacity 1. That represents each person have only 1 party and used one seat in the previously allocated number.
for each person club pair, have a link of capacity 1. That represents each person can represent one club only.
Last but not least, all clubs goes to sink with capacity 1.
If the graph above has a maximum flow equals to the number of clubs - then there exist an assignment.
I can prove the design is correct as follow:
=>
If there exist a maximum flow of the size, each club node must be sending flow of value 1, implies each club node has exactly one person representing it. The representation respect the constraint of party participation as it has at most that many person in a party representing by the party node flow.
<=
If there is a representation, construct the flow as above, so that a flow exist. The flow is maximum because the maximal possible flow is constrainted by edge connecting to the sink.
So something must be wrong either with the arguments above, or with the implementation.
Without further ado, this is my source code:
#include "stdafx.h"
// http://uva.onlinejudge.org/index.php?option=onlinejudge&page=show_problem&problem=1452
// #define LOG
#include "UVa10511.h"
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <map>
#include <queue>
using namespace std;
int UVa10511_assign_person_number(map<string, int>& person_numbers, map<int, string>& person_namings, string person_name);
int UVa10511_assign_party_number(map<string, int>& party_numbers, map<int, string>& party_namings, string party_name);
int UVa10511_assign_club_number(map<string, int>& club_numbers, map<int, string>& club_namings, string club_name);
int UVa10511_Edmonds_Karps(vector<vector<int>>& capacities, vector<vector<int>>& adjacency_list, int src, int dst);
int UVa10511()
{
string line;
int number_of_test_cases;
cin >> number_of_test_cases;
getline(cin, line); // consume the blank link after the number of test cases
getline(cin, line); // consume the blank link before the first test case
for (int test_case = 0; test_case < number_of_test_cases; test_case++)
{
map<string, int> person_numbers;
map<int, string> person_namings;
map<string, int> party_numbers;
map<int, string> party_namings;
map<string, int> club_numbers;
map<int, string> club_namings;
vector<pair<int, int>> party_members;
vector<pair<int, int>> person_clubs;
while(getline(cin, line) && line != "" && line != " ")
{
string person_name;
string party_name;
string club_name;
stringstream sin(line);
sin >> person_name >> party_name;
int person_id = UVa10511_assign_person_number(person_numbers, person_namings, person_name);
int party_id = UVa10511_assign_party_number(party_numbers, party_namings, party_name);
party_members.push_back(pair<int, int>(party_id, person_id));
while(sin >> club_name)
{
int club_id = UVa10511_assign_club_number(club_numbers, club_namings, club_name);
person_clubs.push_back(pair<int, int>(person_id, club_id));
}
}
int number_of_parties = party_numbers.size();
int number_of_persons = person_numbers.size();
int number_of_clubs = club_numbers.size();
int number_of_nodes =
/* master source */ 1 +
/* parties */ number_of_parties +
/* person */ number_of_persons +
/* clubs */ number_of_clubs +
/* master sink */ 1;
vector<vector<int>> capacities;
vector<vector<int>> adjacency_list;
capacities.resize(number_of_nodes);
adjacency_list.resize(number_of_nodes);
for (int src = 0; src < number_of_nodes; src++)
{
capacities[src].resize(number_of_nodes);
for (int dst = 0; dst < number_of_nodes; dst++)
{
capacities[src][dst] = 0;
}
}
int max_party_participants = (number_of_clubs - 1) / 2; // Floor intended, not equal or more than half
for (int p = 0; p < number_of_parties; p++)
{
int party_node = p + 1;
capacities[0][party_node] = max_party_participants;
adjacency_list[0].push_back(party_node);
adjacency_list[party_node].push_back(0);
}
int person_node_start = 1 + number_of_parties;
for (vector<pair<int, int>>::iterator pmi = party_members.begin(); pmi != party_members.end(); pmi++)
{
int party_id = pmi->first;
int person_id = pmi->second;
int party_node = party_id + 1;
int person_node = person_node_start + person_id;
capacities[party_node][person_node] = 1;
adjacency_list[party_node].push_back(person_node);
adjacency_list[person_node].push_back(party_node);
}
int club_node_start = 1 + number_of_parties + number_of_persons;
for (vector<pair<int, int>>::iterator pci = person_clubs.begin(); pci != person_clubs.end(); pci++)
{
int person_id = pci->first;
int club_id = pci->second;
int person_node = person_node_start + person_id;
int club_node = club_node_start + club_id;
capacities[person_node][club_node] = 1;
adjacency_list[person_node].push_back(club_node);
adjacency_list[club_node].push_back(person_node);
}
for (int c = 0; c < number_of_clubs; c++)
{
int club_node = club_node_start + c;
capacities[club_node][number_of_nodes - 1] = 1;
adjacency_list[club_node].push_back(number_of_nodes - 1);
adjacency_list[number_of_nodes - 1].push_back(club_node);
}
#ifdef LOG
cout << "digraph {" << endl;
for (int src = 0; src < number_of_nodes; src++)
{
for (vector<int>::iterator di = adjacency_list[src].begin(); di != adjacency_list[src].end(); di++)
{
int dst = *di;
cout << src << "->" << dst << " [label=\"" << capacities[src][dst] << "\"];" << endl;
}
}
cout << "}" << endl;
#endif
int total_flow = UVa10511_Edmonds_Karps(capacities, adjacency_list, 0, number_of_nodes - 1);
if (test_case > 0)
{
cout << endl;
}
if (total_flow == number_of_clubs)
{
for (vector<pair<int, int>>::iterator pci = person_clubs.begin(); pci != person_clubs.end(); pci++)
{
int person_id = pci->first;
int club_id = pci->second;
int person_node = person_node_start + person_id;
int club_node = club_node_start + club_id;
if (capacities[person_node][club_node] == 0)
{
cout << person_namings[person_id] << " " << club_namings[club_id] << endl;
}
}
}
else
{
cout << "Impossible." << endl;
}
}
return 0;
}
int UVa10511_assign_party_number(map<string, int>& party_numbers, map<int, string>& party_namings, string party_name)
{
int party_number;
map<string, int>::iterator probe = party_numbers.find(party_name);
if (probe == party_numbers.end())
{
party_number = party_numbers.size();
party_numbers.insert(pair<string, int>(party_name, party_number));
party_namings.insert(pair<int, string>(party_number, party_name));
}
else
{
party_number = probe->second;
}
return party_number;
}
int UVa10511_assign_person_number(map<string, int>& person_numbers, map<int, string>& person_namings, string person_name)
{
int person_number;
map<string, int>::iterator probe = person_numbers.find(person_name);
if (probe == person_numbers.end())
{
person_number = person_numbers.size();
person_numbers.insert(pair<string, int>(person_name, person_number));
person_namings.insert(pair<int, string>(person_number, person_name));
}
else
{
person_number = probe->second;
}
return person_number;
}
int UVa10511_assign_club_number(map<string, int>& club_numbers, map<int, string>& club_namings, string club_name)
{
int club_number;
map<string, int>::iterator probe = club_numbers.find(club_name);
if (probe == club_numbers.end())
{
club_number = club_numbers.size();
club_numbers.insert(pair<string, int>(club_name, club_number));
club_namings.insert(pair<int, string>(club_number, club_name));
}
else
{
club_number = probe->second;
}
return club_number;
}
int UVa10511_Edmonds_Karps(vector<vector<int>>& capacities, vector<vector<int>>& adjacency_list, int src, int dst)
{
int total_flow = 0;
// Step 2: Edmonds Karp's
vector<int> parents; // Allow back-tracking the path found from bfs
int number_of_nodes = capacities.size();
parents.resize(number_of_nodes); // avoid reallocation
while (true)
{
// Step 2.1: Use BFS to find an augmenting flow
queue<int> bfs_queue;
for (int n = 0; n < number_of_nodes; n++)
{
parents[n] = -1; // indicating the node is not enqueued
}
parents[src] = -2; // indicating the node is enqueued but no actual parent because this is the root
bfs_queue.push(src);
while (bfs_queue.size() > 0)
{
int current = bfs_queue.front();
bfs_queue.pop();
for (vector<int>::iterator ni = adjacency_list[current].begin(); ni != adjacency_list[current].end(); ni++)
{
int neighbor = *ni;
if (parents[neighbor] == -1 && capacities[current][neighbor] > 0)
{
parents[neighbor] = current;
bfs_queue.push(neighbor);
if (neighbor == dst)
{
break;
}
}
}
if (parents[dst] != -1)
{
break;
}
}
if (parents[dst] == -1)
{
break;
}
else
{
// We have found an augmenting path, go through the path and find the max flow through this path
int cur = dst;
bool first = true;
int max_flow_through_path = 0;
while (true)
{
int src = parents[cur];
if (src != -2)
{
int dst = cur;
int available = capacities[src][dst];
#ifdef LOG
cout << src << "--" << available << "->" << dst << endl;
#endif
cur = parents[cur];
if (first)
{
max_flow_through_path = available;
first = false;
}
else
{
max_flow_through_path = min(max_flow_through_path, available);
}
}
else
{
break;
}
}
#ifdef LOG
cout << "flowing " << max_flow_through_path << endl << endl;
#endif
total_flow += max_flow_through_path;
// Flow the max flow through the augmenting path
cur = dst;
while (true)
{
int src = parents[cur];
if (src != -2)
{
capacities[src][cur] -= max_flow_through_path;
capacities[cur][src] += max_flow_through_path;
cur = parents[cur];
}
else
{
break;
}
}
}
}
return total_flow;
}
The source code is also posted in
https://github.com/cshung/Competition/blob/master/Competition/UVa10511.cpp
The same Edmonds Karps procedure is used to pass some other UVa problems, so I think it should be fine.
UVa820, UVa10480, UVa10779, UVa11506, UVa563 are all accepted with this Edmonds Karp procedure
(These code can be found in the Git repository as well)
I have even debugging the case where Edmond Karps make a wrong choice to being with a fixed it with an augmenting path for this test case
1
Person1 Party1 Club1 Club2
Person2 Party2 Club3
Person3 Party3 Club1
As my Edmond Karps used BFS in the adjacency list order, The chosen paths are
Master Source -> Party1 -> Person1 -> Club1 -> Master Sink
Master Source -> Party2 -> Person2 -> Club3 -> Master Sink
Master Source -> Party3 -> Person3 -> Club1 -> Person1 -> Club2 -> Master Sink [This used the reverse edge and proved going through reverse edge works]
Now I am really stuck, really don't know what's wrong, any help is appreciated.
Your thinking for this problem is correct, it is a typical problem that use maximum flow algorithm.
I have read your code over and over again, I can't find any mistake. Then I change the way you handle the input, then I got accept from UVA.
Just change the code
// you code
cin >> number_of_test_cases;
getline(cin, line); // consume the blank link before the first test case
getline(cin, line); // consume the blank link before the first test case
//line 43
while(getline(cin, line) && line != "" && line != " ")
// change to
scanf("%d\n", &number_of_test_cases);
//line 43
// while(getline(cin, line) && line.length() > 0)
After change the code, I got accept from uva .
Hope get accept response from you.