So I have this small program that creates a min heap and insert values based on user input. If the users says change value 10 to 20, the program should change all occurrences of 10 to 20 and then heapify. When the user gives the print command the program should traverse the tree in postorder and print all the values. So I have written program but its giving me the incorrect output when I print. What am I doing wrong here:
int pArray[500];
int i = 0;
//Definition of Node for tree
struct TNode {
int data;
TNode* left;
TNode* right;
};
void Heapify(TNode* root, TNode* child);
// Function to create a new Node in heap
TNode* GetNewNode(int data) {
TNode* newNode = new TNode();
newNode->data = data;
newNode->left = newNode->right = NULL;
return newNode;
}
// To insert data in the tree, returns address of root node
TNode* Insert(TNode* root,int data) {
if(root == NULL) { // empty tree
root = GetNewNode(data);
}
// if the left child is empty fill that in
else if(root->left == NULL) {
root->left = Insert(root->left,data);
}
// else, insert in right subtree.
else if(root->right == NULL){
root->right = Insert(root->right,data);
}
else {
root->left = Insert(root->left,data);
}
Heapify(root, root->left);
Heapify(root, root->right);
return root;
}
void Heapify(TNode* root, TNode* child){
if(root != NULL && child != NULL){
if(root->data > child->data){
int temp = child->data;
child->data = root->data;
root->data = temp;
}
}
}
void Change(TNode* root,int from, int to) {
if (root == NULL)
return;
else if (root->data == from)
root->data = to;
Change(root->left, from, to);
Change(root->right, from, to);
}
void postOrder(TNode* n){
if ( n ) {
postOrder(n->left);
postOrder(n->right);
pArray[i] = n->data;
i++;
}
}
What am I doing wrong here?
I'm going to assume that you've verified the heap before you print it. Your tree implementation is a bit confusing, but it looks like it should work. I would suggest, however, that the first thing you do is print the tree before calling your Change method, just to make sure that you have a valid heap.
Assuming that you have a valid heap, your Change method has a problem: it never calls Heapify. You end up changing values in the heap and not rearranging. So of course it's going to be out of order when you output it.
When you change an item's value, you have to move that node (or the node's value) to its proper final position in the tree before you change any other value. You can probably make that work with your current model (by calling Heapify repeatedly until the node is in its proper position). Provided that you're increasing the value. If you're decreasing the value (i.e. changing 20 to 10), then you have a problem because your code has no way to move an item up the tree.
As #noobProgrammer pointed out in his comment, a binary heap typically is implemented as an array rather than as a tree. It's a whole lot easier to implement that way, uses less memory, and is much more efficient. If you're interested in how that's done, you should read my multi-part blog series on heaps and priority queues. The first entry, Priority queues, describes the problem. From there you can follow the links to learn about binary heaps and how they're implemented. The code samples are in C#, but if you read the first two introductory articles and understand the concepts, you'll be able to convert to C++ without trouble.
Related
I have a class that is a tree that is made up of nodes that have parent, leftChild, and rightSibling pointers. My intent was to delete the tree from the bottom to the top. With the way I have it set up currently, the nodes don't get "deleted" because the nodes that point to them are still pointing to that location, which should be nothing which causes an error.
Any help would be greatly appreciated. I've looked around but I haven't found a situation that is similar to mine.
OrgTree::~OrgTree()
{
TreeNode * curr = root;
while (curr->leftChild != nullptr)
{
if (curr->leftChild != nullptr)
{
curr = curr->leftChild;
}
}
while (root != nullptr)
{
if ((curr == root) && (curr->leftChild == nullptr))
{
delete(curr);
}
else
{
if (curr->leftChild == nullptr)
{
curr = curr->parent;
}
TreeNode * temp = curr->leftChild;
TreeNode * prev = curr;
while (temp->rightSibling != nullptr)
{
prev = temp;
temp = temp->rightSibling;
if (temp->rightSibling == nullptr)
{
prev->rightSibling = nullptr;
}
}
while (temp->leftChild != nullptr)
{
prev = temp;
temp = temp->leftChild;
if (temp->leftChild == nullptr)
{
prev->leftChild = nullptr;
}
}
delete(temp);
}
}
}
Ok, so... Your algorithm looks like:
Travel to deepest, left-most node.
Move up (1) to parent
Travel to right-most sibling of that node AND Unlink that node from prev
Travel to Deepest, left-most node of that node AND unlink that node from prev
delete whatever node you land on
My first thought is to use an std::vector<TreeNode*> when allocating the nodes and just deleting the nodes from the list. If I knew how many nodes I needed before constructing the tree, I might even be tempted to use std::vector<TreeNode> and hand out pointers like &myVector[mCursor++].
But, if we were going to go with the fully dynamic route and avoid pre-steps to track nodes as they are allocated, then what you are trying to do is called Post Order Traversal. There are several algorithms for post-order traversal of a binary tree, including ones without recursion. Here's one that uses a stack (although you should use std::stack<TreeNode*>).
Here's the recursive code Source:
/* Given a binary tree, delete its nodes according to the
"bottom-up" postorder traversal. */
static void deletePostorder(TreeNode* node)
{
if (node == NULL)
return;
// first recur on left subtree
deletePostorder(node->leftChild);
// then recur on right subtree
deletePostorder(node->rightSibling);
// now deal with the node
delete node;
}
OrgTree::~OrgTree()
{
deletePostorder(root);
}
Do you have control over TreeNode?
If so, you can make the TreeNode destructor delete their left and right child and your top level destructor is just
OrgTree::~OrgTree() {
delete(root);
}
I'm writing an insert algorithm for an ordered linked list. I've got most of the algorithm completed, but the one while loop condition is throwing me off. I think the rest of it I have correct, but any help with it would be appreciated, thanks!
bool MyLinkedList::Insert(ListNode *newNode)
{
// Assume ListNode is a structure and contains the variable int key;
// Assume the function returns true if it successfully inserts the node
ListNode *back = NULL, *temp = head;
if(head == NULL) // Check for inserting first node into an empty list
{
head = newNode;
return true;
}
else
{ // Search for insert location
while((**???**) && (**???**))
{
back = temp; // Advance to next node
temp = temp -> next;
{
// Check for inserting at head of the list
if(back == NULL)
{
newNode -> next = head; // Insert at head of list
head = newNode;
return true;
}
else // Insert elsewhere in the list
{
newNode -> next = temp;
back -> next = newNode;
return true;
}
}
return false; // Should never get here
}
I am assuming you have the following structure for ListNode (based on your prior comment).
struct ListNode {
int Key;
double dataValue;
ListNode *next;
}
On the assumption that the list is ordered based on the key values, the while loop condition should look like this:
while((temp != NULL) && (temp->Key < newNode->Key))
The rest of the code seems to agree with it.
The second argument would need change if the comparison methodology for ordering the sorted list is different than simple key comparison.
while((**???**) && (**???**))
You need to insert your comparisons here. Whatever kind of data is inside the ListNode, you should have some way of comparing two of them. I suspect you have an overloaded operator if it isn't a primitive type.
Hey guys I'm just practicing recursive code on a binary search tree. I'm getting a seg fault but I'm not sure where the problem is (probably something stupid staring me right in the face). I have other functions that are working fine like counting the number of nodes or counting the height of the tree. This function in particular is giving me trouble. I'm coding in c++.
//wrapper function
int table::in_order_successor()
{
node * temp;
temp = root;
in_order_successor(root, temp);
}
//Find the in-order successor
int table::in_order_successor(node * root, node * temp)
{
if(root == NULL) return 0;
if(root->right != NULL)
if(root->data == temp->data)
in_order_successor(root, temp->right);
in_order_successor(root, temp->left);
return temp->data;
}
The idea I had was to get the function to go right once from the root and then continue left as far as possible. To get it to go right once I want to only go right if my root->data is equal to my temp->data (the data is just a randomly generated int).
For Seg fault, you should check whether temp is null, as you code might pass temp->right and temp->left to it, which might be null.
if(temp == NULL) return 0; // add this check
But there is another problem in your code: you never reuse the return value. Then it will just iterate. Suppose you would like to return the data stored in the leaf node after your traversal, then the code could look like this:
//Find the in-order successor
int table::in_order_successor(node * root, node * temp) {
if(root == NULL) return 0;
if(temp == NULL) return 0; // add this check
if(root->right != NULL) {
// check by pointer instead of the data unless each
// node->data is unique. Otherwise unwanted moving
// right will occur.
if(root == temp) {
if (temp->right != null) {
// use `return` here instead of plain function call to get
// the update of the rest of the recursion.
return in_order_successor(root, temp->right);
}
}
}
if (temp->left != null) {
// if have left child, return what you will find in the next step
return in_order_successor(root, temp->left); // use return here
} else {
// reach the left-most leaf after first steping right at root node.
return temp->data;
}
}
Also
if(temp->left != NULL)
in_order_successor(root, temp->left);
and
if(!temp-> left)
return temp->data;
I've checked the boards and could not find any help with this. I find it easy to implement recursive functions given base and general cases, but this doesn't work the way I do it. I'm supposed to iterate down a list until I reach the tail of a linked list. If the next node is NULL, then I have to store the value at the last node, remove that node, and return the value. So it's similar to a dequeue method, except it's performed recursively. What am I doing wrong?
int LinkedList::removeTailRec(Node *n)
{
// check for the base case(s)
if(n->next == NULL)
{
Node *tmp = new Node();
tmp = n;
int val = n->value;
tmp = NULL;
return val;
}
else
return removeTailRec(n->next);
// else call the recursive method
}
First, I recommend you use nullptr instead of NULL.
Then, onto your code. You're actually not removing anything from your list.
if(n->next == NULL)
{
Node *tmp = new Node();
^^^^^^^^^^
//Useless, and dangerous. This memory is never free'd
tmp = n;
int val = n->value;
tmp = NULL;
^^^^^^^^^^
//You just set a local variable to NULL, you're not deleting anything
return val;
}
If you want to remove the node, you'll have to keep a reference to the previous node (e.g. having a doubly linked list, that is, having a pointer to the next element and a pointer to the previous element in each node, or working on the previous node directly).
Set this previous node's next to nullptr, store the node's value and then delete the Node pointer.
One way to do this is to work with the pointer to the next node :
int LinkedList::removeTailRec(Node *n)
{
//EDIT: Adding a check for n validity
if(!n){
//Here, you should have a way of detecting
//a call to your method with a null pointer
return 0;
}
Node* nextNode = n->next;
// check for the base case(s)
if(nextNode->next == nullptr)
{
//Get the next node value
int val = nextNode->value;
//Set the current node next member to nullptr
n->next = nullptr;
//Free the last node
delete nextNode;
return val;
}
else{
return removeTailRec(n->next);
}
// else call the recursive method
}
You are storing the result but not deleting it from linked list. You can return result in another variable (pointer : result).
Node* getTail(Node *n,int *result){
//u can even free the memory
if(!n->next)
{
result=n->value;
return NULL;
}
n->next=getTail(n->next,result);
}
or you can do it other way
int getTail(Node *n)
{
if(!n) return 0;
if(n->next)
{
if(!n->next->next)
{
Node *frnode=n->next;
int result=n->next->value;
n->next=NULL;
delete frnode;
return result;
}
getTail(n->next);
}
You are not removing last node in your code, and you leak another (temporary) node here.
To remove last node you have to zero the link in the previous node.
Your code should look like
...
if (n == NULL || n->next == NULL)
throw std::out_of_range("node");
if(n->next->next == NULL)
{
int val = n->next->value;
delete n->next;
n->next = NULL;
return val;
}
else ...
Be aware of the fact that c++ is not a functional language and has no optimizations for tail recursion, so in real application as your lists grow big enough you'll eventually have failure with stack overflow =) use Haskell or Erlang for this style of programming, in c++ use for or while.
You should set the Node n's previous Node's next field to NULL when n is the tail Node.
So I'm working on a BST, building the delete tools.
My code sequence seems to work right - Save not updating the parent or root and setting the pointer that sent it down to the deleted Node's address to NULL.
I'm passing a pointer to a pointer in my Erase and RemoveNode functions, so as to directly effect the left, right, or root data members that actually lead to the recursive call. In walking through the code, it sets *N to NULL in the remove function, but this is not reflected in the data of the calling object. Am I incorrect in using the pointer-of-a-pointer method? If so, is there a way I can recursively delete and be able to modify the prior node if the link is destroyed?
Node struct:
struct tNode
{
tNode(int n)
{
data = n;
left = NULL;
right = NULL;
}
//Works, cleans all linked objects.
//Must remember to null links when removing wanted nodes
~tNode(void)
{
//cout << "Deleting " << data << endl;
delete left;
delete right;
}
// Data members
int data;
tNode* left;
tNode* right;
};
Eraser function to recurse over the tree:
void BinSearchTree::Erase(int n, tNode** N)
{
tNode* node = *N;
if (root)
{
if (node->data > n) // post order, to avoid moving many times over
{
if (node->left)
{
Erase(n, &node->left);
}
}
else
{
if (node->right)
{
Erase(n, &node->right);
}
}
if (node->data == n)
{
RemoveNode(&node);
}
}
}
And the RemoveNode function to handle actual deletion:
void BinSearchTree::RemoveNode(tNode** N)
{
tNode* node = *N;
if (!node->left && !node->right) // is leaf
{
delete node; // remove node
size--;
*N = NULL; // null pointer for above node/structure
}
else if (!node->left) // right child
{
tNode* temp = node->right; // to strip out copied node when finished
node->data = node->right->data; // copy right node into current node
node->right = node->right->right;
node->left = node->right->left;
temp->right = NULL; // NULL because node destructor is recursive
temp->left = NULL; // ^^
delete temp;
size--;
}
else if (!node->right) // left child
{
tNode* temp = node->left; // to strip out copied node when finished
node->data = node->left->data; // copy left node into current node
node->right = node->left->right;
node->left = node->left->left;
temp->right = NULL; // NULL because node destructor is recursive
temp->left = NULL; // ^^
delete temp;
size--;
}
else // 2 children
{
tNode* temp = node->right; // find ideal child -> left-most right child
tNode* parent = NULL; // keep track of owner of ideal child
while (temp->left)
{
parent = temp;
temp = temp->left;
}
node->data = temp->data; // copy ideal child to root
if (parent)
{
parent->left = temp->right; // case that left-most child has right child of it's own
}
RemoveNode(&temp);
size--;
}
}
I think I see it. When you call RemoveNode() from Erase(), you pass it the value &node. Pass in N instead.
Here's what's happening: The line tNode* node = *N; creates a local variable on the stack. A copy of *N. And while that variable has the same value as *N (at first), it's stored in a different place in memory: node is on the stack, and *N is somewhere in the heap.
So, since you pass &node to RemoveNode(), node is what gets changed. Not *N - it's somewhere else. But if you pass in, you're changing what you want to.
Hope that helps!
PS: If that's not clear, let me know! Writing about double-pointers might just be harder than using them...
Save yourself the trouble of using double pointers and just use a reference to pointer. They have the same semantic of normal pointers, but assigning them will actually change the passed pointer.
void BinSearchTree::Erase(int item, tNode*& node);
Also, use expressive names and save the single letter variable names for loops.