While working on a problem, I have tried the following solution. Somehow my output is stuck into infinite loop and not printing result or updated heap tree.
Given a tree where the left and right subtrees are min heaps, but the root node does not maintain the min heap property. Your code should modify the tree rooted at Node* n so it is a min heap. (This means you need to satisfy the min heap property:
it is okay for a node's value to be equal to one or both of its children, but the node's value must not be greater than either of its children. You do not have to try to balance the tree or make it a complete tree.)
#include <iostream>
#include <string>
You have the following class Node already defined.
You cannot change this class definition, so it is
shown here in a comment for your reference only:
class Node {
public:
int value;
Node *left, *right;
Node(int val = 0) { value = val; left = right = nullptr; }
~Node() {
delete left;
left = nullptr;
delete right;
right = nullptr;
}
};
This function has also previously been defined for you:
void printTreeVertical(const Node* n);
You can use it to print a verbose, vertical diagram of
a tree rooted at n. In this vertical format, a left child
is shown above a right child in the same column. If no
child exists, [null] is displayed.
*/
void downHeap(Node *n) {
Node *curr = new Node();
Node *mino = new Node();
if (n == nullptr ){
return;
} else if (n->left->value > n->value & n->right->value > n->value){
return;
// } else if (n->left== nullptr & n->right== nullptr) {
// return;
// }
} else {
// node* curr = new Node(n)
// n = new Node((std::min(n->left->value, n->right->value));
// if (n->left->value)
while(n->left!= nullptr & n->right!= nullptr){
if (n->left == nullptr){
mino = n->right;
} else if (n->right == nullptr) {
mino = n->left;
} else {
mino = (std::min(n->left, n->right));
}
std::cout << n->value << std::endl;
std::cout << mino->value << std::endl;
if(n->value > mino-> value){
curr->value = n->value;
n->value = mino->value;
mino->value = curr->value;
std::cout << n->value << std::endl;
std::cout << mino->value << std::endl;
downHeap(mino);
}
}
return;
}
}
// Implement downHeap() here.
// You can also use this compact printing function for debugging.
void printTree(Node *n) {
if (!n) return;
std::cout << n->value << "(";
printTree(n->left);
std::cout << ")(";
printTree(n->right);
std::cout << ")";
}
int main() {
Node *n = new Node(100);
n->left = new Node(1);
n->left->left = new Node(3);
n->right = new Node(2);
n->right->left = new Node(3);
n->right->right = new Node(4);
n->right->right->right = new Node(5);
std::cout << std::endl << "BEFORE - Vertical printout:" << std::endl;
printTreeVertical(n);
downHeap(n);
std::cout << "Compact printout:" << std::endl;
printTree(n);
std::cout << std::endl << " AFTER Vertical printout:" << std::endl;
printTreeVertical(n);
delete n;
n = nullptr;
return 0;
}
Please suggest what I am missing. I feel I am making it too complicated. Also, I do not have any other function like swap for converting the binary tree into heap min. I am not using an array or vector as well. So, if you can provide me simple solution I will appreciate it.
Your primary problem is this line of code:
mino = (std::min(n->left, n->right));
Here, you're comparing two pointers when you really want to compare the values in the two objects you're referring to, and return a pointer to the object that has the smaller value. That is:
mino = (n->left->value < n->right->value) ? n->left : n->right;
Also in this line of code:
} else if (n->left->value > n->value & n->right->value > n->value){
You probably want && (logical AND) rather than & (bitwise AND). See https://www.geeksforgeeks.org/what-are-the-differences-between-bitwise-and-logical-and-operators-in-cc/.
Finally, your code formatting is a little off so it's difficult to tell, but it looks like the return statement is outside the while loop in your downHeap function. If it is outside the loop body, then that could lead to an infinite loop.
This is the easiest solution I came up with.
Try this code for complete solution.
void downHeap(Node *n) {
// check if it is a leaf node
if (n->left == NULL && n->right == NULL) {
return;
}
if ((n->left != NULL) && (n->right != NULL)) {
if ((n->value <= n->left->value) && (n->value <= n->right->value)) {
return;
}
}
// Node passed in is not a leaf
// If left is null, we can focus on the right first
// If the right node has a greater value
if (n->right != NULL) {
if ((n->left == NULL) && (n->right->value < n->value)) {
int rightnodevalue = n->right->value;
int nodevalue = n->value;
n->value = rightnodevalue;
n->right->value = nodevalue;
if (n->right != NULL) {
downHeap(n->right);
return;
}
}
}
// Node passed in is not a leaf
// Left is not null
// First check if right is null
// If right is null, we can focus on the left first
// If the left node has a greater value
if (n->left != NULL) {
if ((n->right == NULL) && (n->left->value < n->value)) {
int leftnodevalue = n->left->value;
int nodevalue = n->value;
n->value = leftnodevalue;
n->left->value = nodevalue;
if (n->left != NULL) {
downHeap(n->left);
return;
}
}
}
// Node passed in is not a leaf
// Left is not null
// Right is not null
// If left is less than right
if ((n->left != NULL) && (n->right != NULL)) {
if (n->left->value < n->right->value) {
int leftnodevalue = n->left->value;
int nodevalue = n->value;
n->value = leftnodevalue;
n->left->value = nodevalue;
if (n->left != NULL) {
downHeap(n->left);
return;
}
}
else {
// Proceed to swap the parent and the right node
// Reference pointers for child's pointers
int rightnodevalue = n->right->value;
int nodevalue = n->value;
n->value = rightnodevalue;
n->right->value = nodevalue;
if (n->right != NULL) {
downHeap(n->right);
return;
}
}
}
return;
}
If you define a helper function to swap node values, you can make your code a lot cleaner and implement recursion quite easily. For example:
// DEFINE HELPER FUNCTION
void compareSwap(Node *a, Node *b) {
int temp;
if (a->value > b->value) {
temp = b->value;
b->value = a->value;
a->value = temp;
}
return;
}
void downHeap(Node *n) {
Node *compNode;
// 1. n is a leaf
if (!n->left && !n->right) {
return;
}
// 2. n has one left child
else if (n->left && !n->right) {
if (n->value > n->left->value) {
compareSwap(n, n->left);
downHeap(n->left);
}
return;
}
// 3. n has one right child
else if (!n->left && n->right) {
if (n->value > n->right->value) {
compareSwap(n, n->right);
downHeap(n->right);
}
return;
}
// 4. n has two children ... (n->left && n->right)
else {
// HEAP IS SATISFIED, RETURN NOTHING
if ((n->value <= n->left->value) && (n->value <= n->right->value)) {
return;
}
// RIGHT IS LESS THAN n BUT LEFT IS NOT, SWAP RIGHT
else if (((n->value <= n->left->value) && (n->value > n->right->value))) {
compareSwap(n, n->right);
downHeap(n->right);
return;
}
// LEFT IS LESS THAN n BUT RIGHT IS NOT, SWAP LEFT
else if (((n->value > n->left->value) && (n->value <= n->right->value))) {
compareSwap(n, n->left);
downHeap(n->left);
return;
}
// BOTH ARE LESS THAN, SWAP MIN
else {
compNode = (n->left->value < n->right->value) ? n->left : n->right;
compareSwap(n, compNode);
downHeap(compNode);
return;
}
}
}
Related
Consider the following AVL-tree implementation. Each node contains a list of numbers.The key is named workload, but consider it as a plain double variable. If a key is equal to the key of an already existing node, the number gets pushed into the list. Every time I pop a number from a list, I perform a check, if the node's list is empty -> remove the node. But, after the element with key=3 gets removed completely, the list of the node with key=4 is suddenly empty. I've been trying to solve it for over 10 hours now, it's actually the first time I ever needed to ask something here. Pardon me if I miss a few things.
#include<iostream>
#include <list>
using namespace std;
class BST
{
struct node
{
double workload;
list<int> numbers;
node* left;
node* right;
int height;
};
node* root;
unsigned long long size;
bool empty;
void makeEmpty(node* t)
{
if(t == NULL)
return;
makeEmpty(t->left);
makeEmpty(t->right);
delete t;
}
node* insert(double workload,int number, node* t)
{
if(t == NULL)
{
t = new node;
t->workload = workload;
t->numbers.push_back(number);
t->height = 0;
t->left = t->right = NULL;
}
else if(t->workload == workload){
t->numbers.push_back(number);
}
else if(workload < t->workload)
{
t->left = insert(workload, number, t->left);
if(height(t->left) - height(t->right) == 2)
{
if(workload < t->left->workload)
t = singleRightRotate(t);
else
t = doubleRightRotate(t);
}
}
else if(workload > t->workload)
{
t->right = insert(workload, number, t->right);
if(height(t->right) - height(t->left) == 2)
{
if(workload > t->right->workload)
t = singleLeftRotate(t);
else
t = doubleLeftRotate(t);
}
}
//if x == t->workload instead of using int workload. its a list and we push into it.
t->height = max(height(t->left), height(t->right))+1;
return t;
}
node* singleRightRotate(node* &t)
{
node* u = t->left;
t->left = u->right;
u->right = t;
t->height = max(height(t->left), height(t->right))+1;
u->height = max(height(u->left), t->height)+1;
return u;
}
node* singleLeftRotate(node* &t)
{
node* u = t->right;
t->right = u->left;
u->left = t;
t->height = max(height(t->left), height(t->right))+1;
u->height = max(height(t->right), t->height)+1 ;
return u;
}
node* doubleLeftRotate(node* &t)
{
t->right = singleRightRotate(t->right);
return singleLeftRotate(t);
}
node* doubleRightRotate(node* &t)
{
t->left = singleLeftRotate(t->left);
return singleRightRotate(t);
}
node* findMin(node* t)
{
if(t == NULL)
return NULL;
else if(t->left == NULL)
return t;
else
return findMin(t->left);
}
node* findMax(node* t)
{
if(t == NULL)
return NULL;
else if(t->right == NULL)
return t;
else
return findMax(t->right);
}
node* find(node* t,double workload){
if (t->workload == workload){
return t;
}
else if(workload < t->workload && t->left!=NULL)
return find(t->left,workload);
else if(workload > t->workload && t->right!=NULL)
return find(t->right,workload);
else{
cout << "Null node encountered" << endl;
return t;
}
}
node* remove(double x, node* t)
{
node* temp;
// Element not found
if(t == NULL)
return NULL;
// Searching for element
if(x < t->workload)
t->left = remove(x, t->left);
else if(x > t->workload)
t->right = remove(x, t->right);
// Element found
// With 2 children
else if(t->left && t->right)
{
temp = findMin(t->right);
t->workload = temp->workload;
t->right = remove(t->workload, t->right);
}
// With one or zero child
else
{
temp = t;
if(t->left == NULL)
t = t->right;
else if(t->right == NULL)
t = t->left;
delete temp;
}
if(t == NULL)
return t;
t->height = max(height(t->left), height(t->right))+1;
// If node is unbalanced
// If left node is deleted, right case
if(height(t->left) - height(t->right) == -2)
{
// right right case
if(height(t->right->right) - height(t->right->left) == 1)
return singleLeftRotate(t);
// right left case
else
return doubleLeftRotate(t);
}
// If right node is deleted, left case
else if(height(t->right) - height(t->left) == 2)
{
// left left case
if(height(t->left->left) - height(t->left->right) == 1){
return singleRightRotate(t);
}
// left right case
else
return doubleRightRotate(t);
}
return t;
}
int height(node* t)
{
return (t == NULL ? -1 : t->height);
}
int getBalance(node* t)
{
if(t == NULL)
return 0;
else
return height(t->left) - height(t->right);
}
void inorder(node* t)
{
if(t == NULL)
return;
inorder(t->left);
cout << t->workload<< " ";
inorder(t->right);
}
//Reverse inorder (Sorted highest to lowest)
void rinorder(node* t)
{
if(t == NULL)
return;
rinorder(t->right);
cout << t->workload << " ";
rinorder(t->left);
}
void preorder(node* t)
{
if (t == NULL)
return;
cout << t->workload << " ";
preorder(t->left);
preorder(t->right);
}
void postorder(node* t)
{
if (t == NULL)
return;
postorder(t->left);
postorder(t->right);
cout << t->workload << " ";
}
public:
BST()
{
root = NULL;
}
void insert(double workload, int number)
{
root = insert(workload, number, root);
}
void remove(double workload)
{
root = remove(workload, root);
}
void displayrin()
{
cout << "Rinorder: ";
rinorder(root);
cout << endl;
}
void displayin()
{
cout << "Inorder: ";
inorder(root);
cout << endl;
}
void displaypost()
{
cout << "Postorder: ";
postorder(root);
cout << endl;
}
void displaypre()
{
cout << "Preorder: ";
preorder(root);
cout << endl;
}
double getMax(){
return findMax(root)->workload;
}
int getMaxNum(){
return find(root,getMax())->numbers.front();
}
int getNum(double workload){
return find(root,workload)->numbers.front();
}
//We pop a Num from a node
void popnumber(double workload){
node *t = find(root,workload);
if(t!=NULL){
if(!t->numbers.empty()){
t->numbers.pop_front();
//If the Num list of the node is empty, remove node
if(t->numbers.empty()){
remove(t->workload);
}
}
}
}
};
int main()
{
BST t;
//key value pairs
t.insert(2,1);
t.insert(3,1);
t.insert(3,2);
t.insert(4,7);
cout << t.getNum(4) << endl;
cout << t.getNum(3)<<endl;
t.popnumber(3);
cout << t.getNum(3)<<endl;
t.popnumber(3);
t.displayin();
t.displaypost();
t.displaypre();
t.displayrin();
cout << t.getNum(4) << endl;
cout << "The max is : " << t.getMax() << endl;
cout << "The top Num of the Max is : " << t.getMaxNum() << endl;
return 0;
}
As mentioned in the comments, the problem is in the "Element found With 2 children" section of remove.
To remove the element, you find the next element in the tree. Your implementation then wants to copy the contents of the found node (temp). You copy the workload value, so that both t and temp have the same workload value (4). You do not copy the numbers list. The t node has a workload of 4 and an empty numbers list, while temp has a workload of 4 and a numbers list consisting of one element, 7. You then delete temp, losing the list.
One fix would be to copy (or move) numbers from temp to t before removing it from the tree. Adding a MoveData method to node that would move the data fields (while not altering the tree specific fields) would make it easier to add new data fields.
Another fix would be to change how you're doing the data update. If you update all pointers (and other tree related fields like height), then you don't have to worry about the data (and any pointers/iterators to the nodes would not be invalidated).
I am using the Following code to Implement the AVL Tree Insertion but its not display in proper order nor its updating height I also left some function because when insertion completed than i will be able to complete those fucntions
AVLNode.cpp
#include <iostream>
#include <string>
#include "AVLNode.h"
using namespace std;
AVLNode::AVLNode(string ss, string na){
ssn = ss;
name = na;
height = 0;
left = NULL;
right = NULL;
parent = NULL;
}
AVLNode.h
#include <iostream>
#include <string>
using namespace std;
struct AVLNode{
string ssn;
string name;
AVLNode *left;
AVLNode *right;
AVLNode *parent;
int height;
AVLNode(string ss, string na);
};
AVLTree.cpp
#include <iostream>
#include <string>
#include <stdio.h>
#include "AVLTree.h"
#include <iomanip>
#include <queue>
using namespace std;
AVLTree::AVLTree(){
root = NULL;
}
AVLTree::~AVLTree(){
}
AVLNode* AVLTree::getRoot(){
return root;
}
// search value ss in the AVL tree
bool AVLTree::find(string ss){
if (root == NULL) {
return false;
}
AVLNode* node = root;
while (node != NULL) {
if (ss.compare(node->ssn) == 0) {
return true;
}
if (ss.compare(node->ssn) < 0) {
node = node->left;
}
else{
node = node->right;
}
}
return false;
}
// return the height of the subtree rooted at node
// if subtree is empty, height is -1
// if subtree has one node, height is 0
int AVLTree::height(AVLNode* node){
if(node != NULL){
return node->height;
}
else{
return -1;
}
}
// return the balance factor of the node
int AVLTree::balanceFactor(AVLNode* node){
return height(node->left) - height(node->right);
}
// update the height of the node
// this should be done whenever the tree is modified
void AVLTree::updateHeight(AVLNode* node){
int hl = height(node->left);
int hr = height(node->right);
node->height = (hl > hr ? hl : hr) + 1;
}
// rotate right the subtree rooted at node
// return the new root of the subtree
AVLNode* AVLTree::rotateRight(AVLNode* node){
AVLNode* lp = node->left; // left child of node
if (node->parent != NULL) { // node is not root
if (node->parent->left == node) { // node is a left child
node->parent->left = lp;
}else{
node->parent->right = lp; // node is a right child
}
}
if (lp->right != NULL) { // pointer update
lp->right->parent = node;
}
lp->parent = node->parent;
node->left = lp->right;
lp->right = node;
node->parent = lp;
updateHeight(node); // after rotation, update height
updateHeight(lp); // after rotation, update height
if (node == root) {
root = lp;
}
return lp; // lp is the new root of the subtree
}
// rotate left the subtree rooted at node
// return the new root of the subtree
AVLNode* AVLTree::rotateLeft(AVLNode* node){
AVLNode* rp = node->right;
if (node->parent!=NULL) {
if (node->parent->left == node) {
node->parent->left = rp;
}else{
node->parent->right = rp;
}
}
if (rp->left != NULL) {
rp->left->parent = node;
}
rp->parent = node->parent;
node->right = rp->left;
rp->left = node;
node->parent = rp;
node->parent = rp;
updateHeight(node);
updateHeight(rp);
if (node == root) {
root = rp;
}
return rp;
}
// rebalance a tree rooted at node
// return the new root of the subtree
AVLNode* AVLTree::balance(AVLNode* node){
updateHeight(node);
if (balanceFactor(node) == 2) {
if (balanceFactor(node->left) < 0) {
node->left = rotateLeft(node->left); // for left right case
}
AVLNode* temp = rotateRight(node);
updateHeight(temp);
return temp;
}
if (balanceFactor(node) == -2) {
if (balanceFactor(node->right) > 0) {
node->right = rotateRight(node->right); // for right left case
}
AVLNode* temp2 = rotateLeft(node);
updateHeight(temp2);
return temp2;
}
return node;
}
// insert a new node with (ss, na) to the AVL tree
// if there exists ss value, return false
// otherwise, insert it, balance the tree, return true
bool AVLTree::insert(string ss, string na){
AVLNode *newNode=new AVLNode(ss,na);
AVLNode *Iterator;
if(root==NULL){
cout<<"Root Node Inserted"<<endl;
root=newNode;
} else {
Iterator = root;
int rootTempValue = atoi((Iterator->ssn).c_str());
int addTempValue = atoi((newNode->ssn).c_str());
if(rootTempValue <= addTempValue ){
// Right Portion of the tree
while(Iterator->right != NULL){
cout << "In the Right portion" <<endl;
int rootTempValue2 = atoi((Iterator->right->ssn).c_str());
int addTempValue2 = atoi((newNode->ssn).c_str()) ;
if(rootTempValue2 <= addTempValue2 )
Iterator = Iterator->right;
else
Iterator = Iterator->left;
//Iterator = Iterator->right;
}
Iterator->right = newNode ;
newNode->parent = Iterator ;
} else {
// Left Portion of the tree
while(Iterator->left != NULL){
//Iterator = Iterator->left;
int rootTempValue2 = atoi((Iterator->left->ssn).c_str());
int addTempValue2 = atoi((newNode->ssn).c_str()) ;
if(rootTempValue2 <= addTempValue2 )
Iterator = Iterator->right;
else
Iterator = Iterator->left;
}
newNode->parent = Iterator;
newNode->right = NULL ;
newNode->left = NULL;
Iterator->left = newNode ;
cout << "In the left portion : " <<Iterator->left->ssn<<endl;
}
}
balance(newNode);
updateHeight(newNode);
return true;
}
AVLNode* AVLTree::maxOfSubtree(AVLNode* node){
if (node == NULL) {
return NULL;
}
while (node->right != NULL) {
node = node->right;
}
return node;
}
// delete the node containing value ss
// if there is not such node, return false
// otherwise, delete the node, balance the tree, return true
bool AVLTree::deleteNode(string ss){
// please implement here
return true;
}
// internal function
// do not call it directly
void AVLTree::print(AVLNode* x, int indent){
if(x == NULL)
return;
if (x->right != NULL) {
print(x->right, indent+4);
}
if (indent != 0) {
cout << std::setw(indent) << ' ';
}
if(x->right != NULL){
cout << " /\n" << std::setw(indent) << ' ';
}
cout << x->ssn << endl;
if (x->left != NULL) {
cout << std::setw(indent) << ' ' <<" \\\n";
print(x->left, indent+4);
}
}
// print out the structure of the binary tree
// use it for debugging, I love this function
void AVLTree::print(){
int count = 0;
print(root, count);
}
// it does not level order traversal
// it prints out the number of node
// use it mainly for debugging
void AVLTree::levelOrder(){
// please implement it
}
main.cpp
#include <iostream>
#include "AVLTree.h"
int main(int argc, char** argv) {
AVLTree temp;
temp.insert("05", "a");
temp.insert("04", "b");
temp.insert("09", "c");
//temp.insert("03", "d");
//temp.insert("06", "d");
// temp.insert("07", "d");
//temp.insert("02", "d");
temp.print();
cout<<endl;
cout<<"The Height Of The Tree is :" << temp.height(temp.getRoot())<<endl;
cin.get();
return 0;
}
Your AVLTree has a complex class invariant and expressing it is generally a good idea for an efficient debug.
If you write a method like
bool
AVLTree::invariant() const {
if (root == NULL)
return true;
std::stack<AVLNode*> stack;
stack.push_back(root);
while (!stack.empty()) {
AVLNode* currentNode = stack.back();
int leftHeight = -1, rightHeight = -1;
if (currentNode->left) {
leftHeight = currentNode->left->height;
if (currentNode->left->parent != currentNode)
return false;
if (currentNode->left.height+1 != currentNode->height)
return false;
}
if (currentNode->right) {
rightHeight = currentNode->right->height;
if (currentNode->left->parent != currentNode)
return false;
if (currentNode->left.height+1 != currentNode->height)
return false;
}
if (leftHeigth > rightHeigth+1 || rightHeight > leftHeight+1)
return false;
if (currentNode->left)
stack.push_back(currentNode->left);
else {
do {
stack.pop_back();
AVLNode* parentNode = !stack.empty() ? stack.back() : NULL;
if (currentNode && parentNode->right != currentNode && parentNode->right) {
stack.push_back(parentNode->right);
break;
};
currentNode = parentNode;
} while (currentNode);
};
};
return true;
}
you can then debug your main function by adding into it the following code
assert(temp.invariant());
temp.insert("05", "a");
assert(temp.invariant());
temp.insert("04", "b");
assert(temp.invariant());
temp.insert("09", "c");
assert(temp.invariant());
As soon as you have identified the insertion that fails, you just have to break on the return false; in the invariant method that is executed. At this point you should be able to understand the origin of the bug.
Why not just use a std::stack? Recursion is basically just looping off of the call stack as it is.
if (!root)
root = new AVLNode(ss, na);
else
{
AVLNode *current = root;
AVLNode *previous = NULL;
std::stack<AVLNode*> rstack;
while (current != NULL)
{
previous = current;
//Use String Compare instead of cast
if (ss.compare(current->ssn) < 0) //If ss less than current
...
rstack.push(previous);
}
...
...
while (!rstack.empty())
{
rstack.top() = balance(rstack.top());
rstack.pop();
}
}
the following code is for removing a node of a binary tree. I have stepped through the code and I'm pretty sure the problem lies in the last "else if" in destroy(). I'm trying to replace a given node with a smallest node then delete that given node. remove() and findsmallest work like they should I think. when I reprint the tree its like no changes have been made.I'm obviously a beginner, so any hints/help will be much appreciated!
void remove(Key k)
{
remove(k, root);
}
void remove(Key k, BinarySearchTreeNode<Key, Value> * n)
{
if (n)
{
if (root->key == k)
removeRoot();
else
{
//1 child
if ( (n->left != nullptr) && (k < n->key) )
{
if (k == n->left->key)
destroy(n->left, true);
else
remove(k, n->left);
}
else if (n->right && k > n->key )
{
if (k == n->right->key)
destroy(n->right, false);
else
remove(k, n->right);
}
else
{
cout << "no remove\n";
}
}
}
else
cout << "trww is empty";
}
void destroy(BinarySearchTreeNode<Key, Value> * n, bool isLeft)
{
if (n == nullptr)
{
return;
}
else if (!n->left && !n->right)
{
n->left = nullptr;
n->right = nullptr;
n->parent = nullptr;
delete n;
n = nullptr;
}
else if (!n->left && n->right)
{
isLeft ? n->parent->left = n->right : n->parent->right = n->right;
cout << "killing " << n->key << endl;
n->parent = nullptr;
n->left = nullptr;
n->right = nullptr;
delete n;
n = nullptr;
}
else if (n->left && !n->right)
{
isLeft ? n->parent->left = n->left : n->parent->right = n->left;
cout << "killing " << n->key << endl;
n->parent = nullptr;
n->left = nullptr;
n->right = nullptr;
delete n;
n = nullptr;
}
/* The program goes to the code below*/
else if (n->left && n->right)
{
BinarySearchTreeNode<Key, Value> * small = findSmallest(n->right);
if (isLeft)
n->parent->left = small;
else
n->parent->right = small;
small->parent = n->parent;
small->left = n->left;
small->right = n->right;
n->parent = nullptr;
n->left = nullptr;
n->right = nullptr;
//Key smallKey = small->key;
//Value smallValue = small->value;
cout << "killing " << n->key << endl;
delete n;
n = nullptr;
}
else
cout << "fail";
}
BinarySearchTreeNode<Key, Value> * findSmallest(BinarySearchTreeNode<Key, Value> * n)
{
if (!n)
return part;
else
{
if (n->left)
return findSmallest(n->left);
else
return n;
}
}
You give the node to destroy() as a pointer. This means you can do all the things you did, except change the variable in to calling method.
When you say n= nullptr; in destroy() it only changes the local variable. It doesn't change the calling variable, for example n->right to nullptr so it will still point to the place where the deleted object was.
If you set the parameter to be a reference to a pointer (*&) you can change the calling variable and actually remove the pointer to the node.
The reason why it looks like the original tree is because the memory allocated to the deleted node happened not to be reused yet. Later it would be and your tree would cause access to a wrong pointer and maybe crash. The behaviour is undefined.
So I have been learning all about Binary Trees and decided to write a simple program to demonstrate to myself that I can implement my knowledge into working code. All I am trying to do with this code is add 4 numbers into a binary tree and output the numbers in order from least to greatest. Although, I did run into a problem with my code. When i run the code, Visual Studio breaks it at lines 29 and 59. I believe the problem has to do with the recursive function addLeaf but maybe its something else. Any advise, solutions, or input would be greatly appreciated.!
#include "stdafx.h"
#include <iostream>
#include <cstdlib>
#include <fstream>
using namespace std;
struct node
{
int data;
node* left;
node* right;
};
node* root = NULL;
node* createLeaf(int data)
{
node* n = new node;
n->data = data;
n->left = NULL;
n->right = NULL;
return n;
}
void addLeaf(int data)
{
node* curr = root;
//If tree is empty, create first node
if(root == NULL)
{
root = createLeaf(data);
}
//Left(Less than)
else if(data < curr->data)
{
//Check for curr->left
if(curr->left != NULL)
{
addLeaf(data);
}
else //Adds node to left if null
{
curr->left = createLeaf(data);
}
}
//Right(greater than)
else if(data > curr->data)
{
//Check for curr->right
if(curr->right != NULL)
{
addLeaf(data);
}
else //Adds node if right is Null
{
curr->right = createLeaf(data);
}
}
else
{
cout << "The data " << data << " has already been received\n";
}
}
void printTree(node* Ptr)
{
if(root != NULL)
{
if(Ptr->left != NULL)
{
printTree(Ptr->left);
}
cout << Ptr->data << " ";
if(Ptr->right != NULL)
{
printTree(Ptr->right);
}
cout << Ptr->data << " ";
}
else
{
cout << "The Tree is empty\n";
}
}
int main()
{
int data[4] = {1, 7, 5, 4};
node* Ptr = root;
for(int i = 0; i < 4; i++)
{
addLeaf(data[i]);
}
printTree(Ptr);
system("PAUSE");
return 0;
}
one problem I can spot:
void addLeaf(int data)
{
node* curr = root;
.....
//Check for curr->left
if(curr->left != NULL)
{
addLeaf(data);
}
your so-called recursion did nothing. It only keep on calling addLeaf function, and the function keep on checking if root's left is not null and in turn call the addLeaf again.
Refactor all your code. Don't use any global variable. Make sure you passed correct parameters (e.g. you should pass the next level node to addLeaf)
The addleaf function is going to run infinitely. You only keep adding to the root without any check.
You assign Ptr to root, but then using new, assign it to some new address in memory, which the root does not point to.
You have to pass Ptr by reference to addLeaf, otherwise changes will be made to its copy which is destroyed as addLeaf terminates.
printTree prints the current node value twice (a copy paste error?)
Here is the complete code :
#include "stdafx.h"
#include <iostream>
#include <cstdlib>
#include <fstream>
using namespace std;
struct node
{
int data;
node* left;
node* right;
};
node* root = NULL;
node* createLeaf(int data)
{
node* n = new node;
n->data = data;
n->left = NULL;
n->right = NULL;
return n;
}
void addLeaf(node* &curr, int data)
{
//If tree is empty, create first node
if(curr == NULL)
{
curr = createLeaf(data);
}
//Left(Less than)
else if(data < curr->data)
{
addLeaf (curr->left, data);
}
//Right(greater than)
else if(data > curr->data)
{
addLeaf(curr->right, data);
}
else
{
cout << "The data " << data << " has already been received\n";
}
}
void printTree(node* Ptr)
{
if(root != NULL)
{
if(Ptr->left != NULL)
{
printTree(Ptr->left);
}
cout << Ptr->data << " ";
if(Ptr->right != NULL)
{
printTree(Ptr->right);
}
}
else
{
cout << "The Tree is empty\n";
}
}
int main()
{
int data[4] = {1, 7, 5, 4};
for(int i = 0; i < 4; i++)
{
addLeaf(root, data[i]);
}
printTree(root);
system("PAUSE");
return 0;
}
After a few questions and some nice answers and friendly helpers here. I got the sulotion to my porblem with the deleting in the binary tree, i got suggested that, i can not just delet the largest number in the tree cause its may not the last or it has childrens 1 ,2 or none, so i made the code down below, i used a lot commenting hope that can help you people help me. What i actually dont know now, is how do i call this RemoveLargest() function in my public and then later in main, even though i dont know if the code will run properly.
#include <iostream>
#include <string>
#include <cstdlib>
using namespace std;
template<class T>
class BinaryTree
{
struct Node
{
T data;
Node* lChildptr;
Node* rChildptr;
Node(T dataNew)
{
data = dataNew;
lChildptr = NULL;
rChildptr = NULL;
}
};
private:
Node* root;
void Insert(T newData, Node* &theRoot) //Insert elements into the tree start.
{
if(theRoot == NULL)
{
theRoot = new Node(newData);
return;
}
if(newData < theRoot->data)
Insert(newData, theRoot->lChildptr);
else
Insert(newData, theRoot->rChildptr);
} //end.
void PrintTree(Node* theRoot) //print me the tree /start
{
if(theRoot != NULL)
{
PrintTree(theRoot->lChildptr);
cout<< theRoot->data<<" \n";
PrintTree(theRoot->rChildptr);
}
} //end.
T Largest( Node* theRoot) // show me largest number /start.
{
if ( root == NULL )
{
cout<<"There is no tree";
return -1;
}
if (theRoot->rChildptr != NULL)
{
return Largest(theRoot->rChildptr);
}
T value = theRoot->data;
return value;
} //end.
void RemoveLargest(Node* theRoot) //remove the largest priority number from tree /start.
{
Node* current; //the current tree?
Node* parent; //the parent of the current node?
current=theRoot;
// 3 cases :
// 1. We're removing a leaf node
// 2. We're removing a node with a single child
// 3. we're removing a node with 2 children
//Node with single child.
if((current->lChildptr == NULL && current->rChildptr != NULL)||(current->lChildptr != NULL && current->rChildptr == NULL))
{
if(current->lChildptr == NULL && current->rChildptr != NULL)
{
if(parent->lChildptr==current)
{
parent->lChildptr = current->rChildptr;
delete current;
}
else
{
parent->rChildptr = current->rChildptr;
delete current;
}
}
else //left child ok, no right child
{
if(parent->lChildptr==current)
{
parent->lChildptr = current->lChildptr;
delete current;
}
else
{
parent->rChildptr = current->lChildptr;
delete current;
}
}
return;
}
//We found a leaf(a node with not a single child)
if(current->lChildptr == NULL && current->rChildptr == NULL)
{
if (parent->lChildptr == current)
parent->lChildptr = NULL;
else
parent->rChildptr = NULL;
delete current;
return;
}
//Node with 2 children
// replace node with smallest value in right subtree
if (current->lChildptr != NULL && current->rChildptr != NULL)
{
Node* checkr;
checkr = current->rChildptr;
if((checkr->lChildptr == NULL)&&(checkr->rChildptr == NULL))
{
current=checkr;
delete checkr;
current->rChildptr = NULL;
}
else //right child has children
{
//if the node's right child has a left child
//Move all the way down left to locate smallest element
if ((current->rChildptr)->lChildptr != NULL)
{
Node* lcurr;
Node* lcurrp;
lcurrp = current->rChildptr;
lcurr = (current->rChildptr)->lChildptr;
while(lcurr->lChildptr != NULL)
{
lcurrp = lcurr;
lcurr = lcurr->lChildptr;
}
current->data = lcurr->data;
delete lcurr;
lcurrp->lChildptr = NULL;
}
else
{
Node* temp;
temp = current->rChildptr;
current->data = temp ->data;
current->rChildptr = temp->rChildptr;
delete temp;
}
}
return;
}
};
public:
BinaryTree()
{
root = NULL;
}
void AddItem(T newData)
{
Insert(newData, root);
}
void PrintTree()
{
PrintTree(root);
}
T Largest()
{
return Largest(root);
}
void RemoveLargest()
{
RemoveLargest();
}
};
int main()
{
BinaryTree<int> *myBT = new BinaryTree<int>();
myBT->AddItem(5);
myBT->AddItem(1);
myBT->AddItem(4);
myBT->AddItem(2);
myBT->AddItem(3);
//for(int i = 0; i < 10; i++) //randommal tolti fel/fill with random
//myBT->AddItem(rand() % 100);
cout << "BinaryTree:" << endl; //kilistazaa a fat/ list my tree
myBT->PrintTree();
cout << "Largest element: " << myBT->Largest() << endl; //visszaadja a legnagyobb elemet/shows the largest number
myBT->RemoveLargest(); //suposed to delet the largest number
myBT->PrintTree(); //shows list again
}
edited the code, now its running, its creating the tree, shows the largest, but after i call my remove function still crashing... =/
Like I said before, I think you're making things overly complicated. You have to think of what it means that your node is the largest one, in the context of a binary search tree and the relationship between the keys in its nodes.
If a node is the largest one in the tree it cannot possibly have a right child pointer, because the right child would have to have a larger key. And then, if you know that it has at most a left child, you just replace your node with its possibly null left child, and you're done.
T ExtractLargest(Node*& n){
if (!n)
return -1;
if (n->rChildptr)
return ExtractLargest(n->rChildptr);
T result = n->data;
Node *d = n;
n = n->lChildptr;
delete d;
return result;
}