void Insert(AVLnode * & root, string X)
{
if ( root == NULL)
{
root = GetNode(X);
}
else if ( root->info > X )
{
Insert(root->left,X);
if ( height(root->left) - height(root->right) == 2 )
if ( X < root->left->info )
RotateRR(root);
else
RotateLR(root);
}
else if ( root->info < X )
{
Insert(root->right,X);
if ( height(root->right) - height(root->left) == 2 )
if ( X > root->right->info )
RotateRR(root);
else
RotateLR(root);
}
root->height = max( height(root->left), height(root->right) )+1;
}
AVLnode* find(AVLnode* root,string X)
{
if (!root) return 0;
if ( root->info == X )
return root;
else if (root->info < X)
find(root->left,X);
else if (root->info > X)
find(root->right,X);
return 0;
}
int main(int argc,char* argv)
{
AVLnode* Dic;
Insert(Dic,"adf");
return 0;
}
The first time in Insert, root is NULL but when I debug, it skips root == null. What's going on?
The problem is in the AVLnode* Dic; statement of main(). You are sending an uninitialized pointer to insert() from main(). It contains garbage values. Initialize it to NULL
The first time it's not NULL. Variables do not auto-initialize to NULL or 0 in C++; they contain garbage (whatever the memory address they occupy contained before).
Replace AVLnode* Dic; with AVLnode* Dic = NULL; and try again.
"The first time in Insert", in the code you give, root is a "random"-ish value, because you never initialize Dic -- so it may well happen to be NULL when you're running without a debugger and otherwise if you are using a debugger. That's just a definite bug in your code, so add = 0 before the ; in the first line of main's body. After which, you may find more bugs (hard to say, since you don't show us GetNode or the Rotate thingies, even though you do show us the find function that's never ever called -- peculiar choice of code to show us, indeed).
Related
I need to implement this recursive function that will take a root of a BST and recursively count the number of nodes in it with two childrens, but i am not sure if my logic is correct?
My logic is:
If leaf or empty we return 0
You check if a node with two children we add one and call again on its left and right children
Else if a node doesnt have two children you call on its left and right subtrees without adding
Here is my function implementation
ps: assume everything in the BinarySearchTree class is implemented:
int count(BinarySearchTree *root )
{
if(root== nullptr)
{
return 0;
}
if(root->right != nullptr and root->left!= nullptr)
{
return 1+count(root->right)+count(root->left);
}
count(root->right);
count(root->left);
}
You need to sum up the counts even if your node doesn't have two children. Two count calls that you have after if are basically not used.
You can fix it like this:
int count(BinarySearchTree *root )
{
if (root== nullptr)
{
return 0;
}
int countForThisNode = root->right != nullptr and root->left!= nullptr;
return countForThisNode + count(root->right) + count(root->left);
}
In this case countForThisNode is 1 for the node that you want to count and 0 otherwise. All other nodes are added to the result no matter what.
I hope this is information you were asking for!
Your function has undefined behaviour because the control can be transfered to the closing brace without returning anything.
count(root->right);
count(root->left);
}
For starters as the list is not changed the parameter should have the qualifier const.
The function can be defined much simpler the following way
unsigned int count( const BinarySearchTree *root )
{
return root == nullptr ? 0
: ( root->left && root->right ) + count( root->left )
+ count( root->right );
}
An easy way to implement this function:
start from a standard enumeration of the nodes (can be prefix, infix, suffix, doesn't matter);
modify it so that at every node you increment the counter if there are two children.
Note that you need to look at the whole tree, as parts of it may be reached via single-childrened nodes.
visit(root):
if root.left != null:
visit(root.left)
if root.right != null:
visit(root.right)
becomes
visit(root):
count= root.left != null and root.right != null
if root.left != null:
count+= visit(root.left)
if root.right != null:
count+= visit(root.right)
return count
I have been working on this piece of code for a couple of days and it seems
to work just fine for search trees of relative small size, but working with higher ones gives segmentation fault.
I have tried to find the specific place where such error comes from by using printing flags, and it seems to break at the is_goal() function. But the code of that function can be assumed as correct.
So the problems seems to be a memory problem, that's why I have the queue in the heap, and also the Nodes that I am creating. But it still crashes.
Are there any more memory saving tricks that can be taking into account that I am not using? Or maybe there is a better way to save such nodes?
It is important to note that I need to use BFS (I can't use A* to make the search tree smaller).
Also if you need to know, the map is a hash table where I save the coloring of the nodes so I don't have duplicates when exploring (This is because the hash saves depending on the state information and not the Node information).
EDIT: i have been told to indicate the goal to accomplish, such is to find the goal state in the search tree, the goal is to be be able to iterate over
big problems like rubik 3x3x3, n-puzzle 4x4 5x5, tower of hanoi and such.To do so, the memory used has to be minimal since the search tree of such problems are really big, the final objective is to compare this algorithm with others like a*, dfid, ida*, and so on. I hope this is enough information.
Node* BFS(state_t start ){
state_t state, child;
int d, ruleid;
state_map_t *map = new_state_map();
ruleid_iterator_t iter;
std::queue<Node*> *open = new std::queue<Node*>();
state_map_add( map, &start, 1);
Node* n = new Node(start);
open->push(n);
while( !open->empty() ) {
n = open->front();
state = n->get_state();
open->pop();
if (is_goal(&state) == 1) return n;
init_fwd_iter( &iter, &state );
while( ( ruleid = next_ruleid( &iter ) ) >= 0 ) {
apply_fwd_rule( ruleid, &state, &child );
const int *old_child_c = state_map_get( map, &child );
if ( old_child_c == NULL ) {
state_map_add( map, &child, 1 );
Node* nchild = new Node(child);
open->push(nchild);
}
}
}
return NULL;
}
I see a number of memory leaks.
open is never deleted but maybe could allocated in the stack instead of in the heap.
std::queue<Node*> open;
More important none of the node you push in the queue are deleted this is probably the origin of very big memory consumption.
Delete the nodes that you remove from the queue and that you don't plan to reuse. Delete the nodes of the queue before your get rid of the queue.
Node* BFS(state_t start ){
state_t state, child;
int d, ruleid;
state_map_t *map = new_state_map();
ruleid_iterator_t iter;
std::queue<Node*> open;
state_map_add( map, &start, 1);
Node* n = new Node(start);
open.push(n);
while( !open.empty() ) {
n = open.front();
state = n->get_state();
open.pop();
if (is_goal(&state) == 1) {
for (std::queue<Node*>::iterator it = open.begin(); it != open.end(); ++it)
delete *it;
return n;
}
else {
delete n;
}
init_fwd_iter( &iter, &state );
while( ( ruleid = next_ruleid( &iter ) ) >= 0 ) {
apply_fwd_rule( ruleid, &state, &child );
const int *old_child_c = state_map_get( map, &child );
if ( old_child_c == NULL ) {
state_map_add( map, &child, 1 );
Node* nchild = new Node(child);
open.push(nchild);
}
}
}
return NULL;
}
Im trying to build a Huffman tree using an array. Everytime i combine two nodes, I add the new node to the array and sort it. My code works for some test cases but for others, it produces the wrong codes. Can someone please point me to the right direct in debugging? Thanks!
Here is a segment of my compress function.
while(tree->getSize() != 1)
{
right = tree->getMinNode();
left = tree->getMinNode();
Node *top = new Node;
top->initializeNode((char)1, left->getFrequency() + right->getFrequency(), left, right);
tree->insertNode(top);
} // while
root = tree->getRootNode();
tree->encodeTree(root, number, 0);
tree->printCode(data);
The getMinNode() function returns the smallest node and after I insert the node that combines the 2 smallest nodes, I use qsort to sort the array. This is the function i use to sort the array.
I am sorting: 1st with frequency, 2nd with data. If the node is not a leaf node, meaning it does not contain one of the characters presented in the uncompressed data, I find the minimum data in the subtree using the function getMinData().
int Tree::compareNodes(const void *a, const void *b)
{
if( ((Node *)a)->frequency < ((Node *)b)->frequency )
return -1;
if( ((Node *)a)->frequency > ((Node *)b)->frequency )
return 1;
if( ((Node *)a)->frequency == ((Node *)b)->frequency )
{
if( ((Node *)a)->isLeafNode() && ((Node *)b)->isLeafNode() )
{
if( (int)((Node *)a)->data < (int)((Node *)b)->data )
return -1;
if( (int)((Node *)a)->data > (int)((Node *)b)->data )
return 1;
} // if
else
{
int minA, minB;
minA = (int)((Node *)a)->data;
minB = (int)((Node *)b)->data;
if(!((Node *)a)->isLeafNode())
getMinData(a, &minA);
if(!((Node *)b)->isLeafNode())
getMinData(b, &minB);
if(minA < minB)
return -1;
if(minA > minB)
return 1;
}// else
} // if
return 0;
} // compareNodes()
Say if for example, i have the following text.
I agree that Miss Emily Grierson is a symbol of the Old South. Her house and family traditions support this suggestion. However, I do not see her as a victim of the values of chivalry, formal manners, and tradition. I consider these values to have positive effects of a person rather have negative impacts. If for any reason that had made Emily isolate herself from her community and ultimately kill a man she likes, it would be herself. She acts as her own antagonist in the story because she does not have conflict with anyone else except herself. She makes herself become a “victim,” as in being friendless and miserable. The traditions and manners taught to her may have effects on her behavior but it is her attitude towards the outside world that separates her from the rest of the townspeople
\n
with the '\n' at the end. some of the characters i get the correct huffman codes, but some others i don't. Ascii 83('S'), 120('x'), 84('T') are some of the characters with the wrong codes. Thanks!
I have an AVL tree class, I want to find balance factor of each node ( balance_factor: node->Left_child->height - node->right_Child->height )
Here is my code:
int tree::findBalanceFactor(node p){
int a;
if( p.lchild) p.lchild->balance_factor=findBalanceFactor( *p.lchild );
if( p.rchild) p.rchild->balance_factor=findBalanceFactor( *p.rchild );
if( p.rchild && p.lchild ) a=p.balance_factor = p.lchild->height - p.rchild->height ;
if( p.rchild && !p.lchild ) a=p.balance_factor = 0 - p.rchild->height;
if( !p.rchild && p.lchild ) a=p.balance_factor = p.lchild->height;
if( !p.rchild && !p.lchild ) a=p.balance_factor = 0;
cout << "md" << a << endl;
return a;
}
In the main function when I print root->balance_factor it shows me always number zero balance_factor is a public variable and in the constructor I assigned zero to that.
What is the wrong with my code?
There's a much simpler way to do this than testing every permutation of lchild and rchild:
int tree::findBalanceFactor(node &n) {
int lheight = 0;
int rheight = 0;
if (n.lchild) {
findBalanceFactor(*n.lchild);
lheight = n.lchild->height;
}
if (n.rchild) {
findBalanceFactor(*n.rchild);
rheight = n.rchild->height;
}
n.balance_factor = lheight - rheight;
std::cout << "md " << n.balance_factor << std::endl;
return n.balance_factor;
}
Since this otherwise seems to have ended up as an all-code answer, I'll add a brief note on how to get from the original code to this.
On one level, it's trivial to observe that each of the four branches in the original has the same form (left - right), but with left=0 whenever lchild is null, and right=0 whenever rchild is null.
More broadly, it's really useful to look for this kind of pattern (ie, that each branch has essentially the same expression). Writing out truth tables or otherwise partitioning your state space on paper, can help clarify these patterns in more complex code.
You should always aim to know what the general case is - whether because you implemented that first, or because you were able to factor it back out of several specific cases. Often implementing the general case will be good enough anyway, as well as being the easiest version of the logic to understand.
If the general case isn't good enough for some reason, then being easy to understand means it is still a good comment, as it provides a point of comparison for the special cases you actually implement.
I am guessing that the reason why the balance_factor of the root node is always 0 because of these 2 lines of code in the tree::findBalanceFactor method:
if( p.lchild) p.lchild->balance_factor=findBalanceFactor( *p.lchild );
if( p.rchild) p.rchild->balance_factor=findBalanceFactor( *p.rchild );
I suppose that the node struct/class looks something like this:
struct node {
struct node *lchild;
struct node *rchild;
int balance_factor;
int height;
};
What happens in findBalanceFactor( *p.lchild ) and findBalanceFactor( *p.rchild ) is that, we are passing new copies of p.lchild and p.rchild into findBalanceFactor (as seen from the pointer dereference), and hence the balance_factor attribute of the original p.lchild and p.rchild are not updated.
The solution will be to modify the tree::findBalanceFactor method to take in pointers to node, like this (I've taken the liberty to prettify the code a little):
int tree::findBalanceFactor(node *p) {
int a;
if (p->lchild) {
findBalanceFactor(p->lchild);
}
if (p->rchild) {
findBalanceFactor(p->rchild);
}
if (p->rchild && p->lchild) {
a = p->balance_factor = p->lchild->height - p->rchild->height;
} else if (p->rchild && !p->lchild) {
a = p->balance_factor = 0 - p->rchild->height;
} else if (!p->rchild && p->lchild) {
a = p->balance_factor = p->lchild->height;
} else {
// this is the case for !p->rchild && !p->lchild
a = p->balance_factor = 0;
}
cout << "md" << a << endl;
return a;
}
For p->lchild and p->rchild, we do not need to set their balance_factor another time, since the balance_factor of each node is already set in one of the 4 possible cases of the very long if statement.
I'm still working on my Field class, and tried to improve my piss-poor insertion/erase performance.
However, the new function works once, then breaks catastrophically when I use it a second time.
This is the code:
template <class T>
T *Field<T>::insert(const T *pPos, const T& data)
{
// Special case: field is empty. insert should still succeed.
// Special case: Pointing to one past the end. insert should still succeed
if( empty() || pPos == last() )
{
this->push_back(data);
return (this->last() - 1);
}
/* Explanation: Find cell before which to insert new value. Push_back new
new value, then keep swapping cells until reaching *pPos and swapping it
with data. The while fails, we exit, insert successful. */
T *p = ( std::find( this->first(), this->last(), *pPos ));
if( p != last() )
{
this->push_back(data);
T *right = (this->last() - 1);
T *left = (this->last() - 2);
while( *pPos != data )
std::iter_swap( left--, right-- );
// pPos *has* to be the destination of new value, so we simply return param.
return const_cast<T*>(pPos);
}
else
throw std::range_error("Not found");
}
Calling code from main
// Field already has push_back()ed values 10, 20, 30.
field->insert( &(*field)[2], 25 ); // field is a ptr (no reason, just bad choice)
Produces this output when printed on the console.
Field: 10 20 30 // Original Field
25 // Function return value
Field: 10 20 25 30 // Correct insertion.
New calling code from main
// Field already has push_back()ed values 10, 20, 30
field->insert( &(*field)[2], 25 );
field->insert( &(*field)[3], 35 );
Produces this output when printed on the console.
Field: 10 20 30
25
35
-4.2201...e+37, 10, 15, 20, 30
Windows has triggered a breakpoint in Pg_1.exe.
This may be due to a corruption in the heap (oh shit).
No symbols are loaded for any call stack frame.
The source code cannot be displayed.
The console then proceeds to never shutdown again until I close VSC++08 itself.
What? Why? How? What is my code doing!?
Additional Info
The Field has a size of three before the push, and a capacity of four. After two insertions, the Field is correctly increased to have a capacity of 8 (doubled), and stores five elements.
It doesn't matter where I insert my second element with insert(), it will fail the exact same way. Same output, even same number (I think) at the first cell.
Additional Code
Push_Back()
Note: This code was not changed during my refactoring. This function has always worked, so I highly doubt that this will be the problem-cause.
/* FieldImpl takes care of memory management. it stores the values v_, vused_,
and vsize_. Cells in the Field are only constructed when needed through a
placement new that is done through a helper function. */
template <class T>
void Field<T>::push_back(const T& data)
{
if( impl_.vsize_ == impl_.vused_ )
{
Field temp( (impl_.vsize_ == 0) ? 1
: (impl_.vsize_ * 2) );
while( temp.impl_.vused_ != this->impl_.vused_ )
temp.push_back( this->impl_.v_[temp.size()] );
temp.push_back(data);
impl_.Swap(temp.impl_);
}
else
{
// T *last() const { return &impl_.v_[impl_.vused_]; }
// Returns pointer to one past the last constructed block.
// variant: T *last() const { return impl_.v_; }
Helpers::construct( last(), data );
++impl_.vused_;
}
}
// ...
if( p != last() )
{
this->push_back(data);
After this line pPos may not be a valid pointer anymore.
The console then proceeds to never shutdown again until I close VSC++08 itself.
Tried clicking the Stop button in the debugger?
From the Debugger, and from ybungalobill, it is possible to see that pPos is invalidated after a special case in the
if( p != last()
{
this->push_back(data);
part of the code. If the array is resized, the pointer is invalidated. To bridge this, I simply stored const T pos = *pPos before the push and therefore removed the use of the *pPos pointer after a push.
Updated code:
const T pos = *pPos;
T *p = ( std::find( this->first(), this->last(), pos ) );
if( p != last() )
{
this->push_back(data);
p = ( std::find( this->first(), this->last(), pos ) );
T *right = (this->last() - 1);
T *left = (this->last() - 2);
while( *p != data )
std::iter_swap( left--, right-- );
return const_cast<T*>(p);
}