I'm trying to create an AVL Tree iterator, but I'm having trouble doing so. This is the code I have to get the first node, which successfully returns the minimum.
AVLPtr node = iter->list->root;
AVLPtr current = iter->current;
AVLPtr last = iter->last;
AVLPtr parent;
if(current == NULL || current->parent == NULL)
parent = NULL;
else
parent = iter->current->parent;
if(last == NULL && current == NULL){
while(node->leftChild != NULL){
node = node->leftChild;
iter->current = node;
}
}
I'm getting a SegFault when I go to get the next node. I think this is because I am actually changing the parent of the node to NULL in my first if statement. I then mess up my list by eventually making the root the minimum in the while loop. My question is how do I get this first node without changing the parent or root nodes? Or is there something else that I am missing?
EDIT: Should I extract the object that each node in the tree holds into a separate linked list by using a recursive inorder call?
I do not know what do you mean by first element, but I will assume that you mean the leftmost leaf. If so, then you can find it this way:
AVLPtr first = iter->list->root;
AVLPtr last = iter->list->root;
while(first->leftChild != NULL){
first = first->leftChild;
}
iter->current = first;
You should always change iter->current and use its links to left, right and parent.
Related
I was trying to perform deletion in a binary search tree (BST), but it was giving a segmentation fault after printing the deleted array.
treeNode *minVal(treeNode *root)
{
if(root == NULL || root->left==NULL)
return root;
else
minVal(root->left);
}
treeNode *deleteBST(treeNode *root,int value)
{
treeNode *tempNode;
if(value>root->value)
deleteBST(root->right,value);
else if(value<root->value)
deleteBST(root->left,value);
else
{
if(root->left==NULL)
{
tempNode = root->right;
free(root);
return tempNode;
}
else if(root->right==NULL)
{
tempNode = root->left;
free(root);
return tempNode;
}
else
{
tempNode = minVal(root->right);
root->value=tempNode->value;
root->right = deleteBST(root->right,tempNode->value);
}
}
return root;
}
Presumably the point of deleteBST() returning a treeNode * is that the return value points to the new root of the (sub)tree. The new root will differ from the original one if the deleted value was found in the original root, so some means of updating the root is required.
That needs to be handled appropriately by this function's callers, including this function itself when it performs recursive calls. Your function fails to do this.
Your function also fails to properly handle the case when the specified value is not found in the tree. It will eventually attempt to dereference a null pointer if such a value is passed.
And the actual deletion performed by your function is totally inadequate. It frees the node where the value is found, but it does not adjust the subtree rooted at that node to have a valid structure, and it leaves the parent of the deleted node with a (then) invalid child pointer.
The general scheme for deletion from a BST would be like this:
if the root, R, of the tree is null then return null; otherwise,
if the value to delete is less than the value of R, then
delete it from the left subtree and update R's left pointer to point to the new root of the left subtree; otherwise,
if the value to delete is greater than the value of R, then
delete it from the right subtree and update R's right pointer to point to the new root of the right subtree; otherwise,
the value to delete is the value of R itself. In this case,
Select a new root for this subtree:
if both R's children are null then the new root is also null.
if exactly one child is null then the other is the new root.
if neither child is null then you can choose either the smallest node in the right subtree or the largest one in the left subtree. These are R's immediate in-order successor and predecessor, respectively.
In the case where neither of R's children is null, update the subtree appropriately. Supposing that the smallest node of the right subtree, MR, is the selected new root, you must
remove MR from its current parent by updating the parent's pointer to it to point instead at MR's right child (which might or might not be null). Including when the parent is R.
update MR's left and right child pointers to be the same as R's.
Free R.
return the root of the subtree (original or new, as appropriate)
updated working code is attached with comments to the errors.
treeNode *minVal(treeNode *root)
{
if(root == NULL || root->left==NULL)
return root;
else
return minVal(root->left);//1.returning a value is a must here
}
treeNode *deleteBST(treeNode *root,int value)
{
treeNode *tempNode;
if(root==NULL)//2.handling the base case
return NULL;
if(value>root->value)
return deleteBST(root->right,value);
else if(value<root->value)
return deleteBST(root->left,value);
else
{
if(root->left==NULL)
{
tempNode = root->right;
free(root);
return tempNode;
}
else if(root->right==NULL)
{
tempNode = root->left;
free(root);
return tempNode;
}
else
{
tempNode = minVal(root->right);
root->value=tempNode->value;
root->right = deleteBST(root->right,tempNode->value);
return root;//can be skipped
}
}
return root;
}
void MorrisTraversal(tNode* root)
{
tNode *current, *pre;
if (root == NULL)
return;
current = root;
while (current != NULL)
if (current->left == NULL) {
current = current->right;
}
else {
pre = current->left;
while (pre->right != NULL
&& pre->right != current)
pre = pre->right;
if (pre->right == NULL) {
pre->right = current;
current = current->left;
}
else {
pre->right = NULL;
current = current->right;
}
}
}
}
I use this function to travers the bst, i also have a function (delete) that takes a node as parameter and delets it from the tree.
I'd like for example to remove from the tree all nodes whose value is 4, is it possible to do so using the functions mentioned above?
Like traversing the tree one time and removing all the nodes with a certain property.
I hope my problem it's clear...
Thanks in advance!
It is possible, but you will need to modify your Traversal function.
Currently MorrisTraversal traverses the tree, but it doesn't do anything to any node. You could modify MorrisTraversal to call a function on the current node (probably on the line after while (current != NULL).
I would first try putting a simple print function/line there that prints the value of the current node and run it to verify your tree traversal works as expected.
Then you could change the print function to modify the node in some way.
If you do delete the node, you will have to be careful to clean up the tree. Eg. if you have the following tree Where A is the root node:
A-B-C
|
D-E
|
F
What happens if you delete B? Will you move C, A. or D into B's place?
Good luck!
I have the following binary search tree, with root node 20. The question I'm trying to answer is, if we apply the function t = deleteRoot(t), what will be the value of the new root node, as well as its immediate left and right children (e.g. the current root node is 20 with immediate left child 11 and immediate right child 32). I scribbled at least 10 pages over the last 2 hours trying to solve this, but the recursion is killing me. Can someone please help me visualize this - i.e some way of thinking which allows me to deal with recursion. I'm not very good at visualizing how recursion works but I can somewhat implement it. Thanks very much. By the way, the answer is root node: 21 with left child 11 and right child 32.
My attempt:
The question tells us to start with t=deleteRoot(t).
parent = node containing 25
succ = node containing 21
succval = 21
then we get to
t = TreeDelete(t, succval)
then I get a bit lost as to how the TreeDelete function works
t->left = TreeDelete(t->left, key) ...etc
deleteRoot(Tree t) function
// delete root of tree
Tree deleteRoot(Tree t)
{
Link newRoot;
// if no subtrees, tree empty after delete
if (t->left == NULL && t->right == NULL) {
free(t);
return NULL;
}
// if only right subtree, make it the new root
else if (t->left == NULL && t->right != NULL) {
newRoot = t->right;
free(t);
return newRoot;
}
// if only left subtree, make it the new root
else if (t->left != NULL && t->right == NULL) {
newRoot = t->left;
free(t);
return newRoot;
}
// else (t->left != NULL && t->right != NULL)
// so has two subtrees
// - find inorder successor (grab value)
// - delete inorder successor node
// - move its value to root
Link parent = t;
Link succ = t->right; // not null!
while (succ->left != NULL) {
parent = succ;
succ = succ->left;
}
int succVal = succ->value;
t = TreeDelete(t,succVal);
t->value = succVal;
return t;
}
Tree TreeDelete(Tree t, Key k) function:
Tree TreeDelete(Tree t, Key k)
{
Tree deleteRoot(Tree);
if (t == NULL)
return NULL;
int diff = cmp(k,key(t->value));
if (diff == 0)
t = deleteRoot(t);
else if (diff < 0)
t->left = TreeDelete(t->left, k);
else if (diff > 0)
t->right = TreeDelete(t->right, k);
return t;
}
By the way, the answer is root node: 21 with left child 11 and right child 32.
Well, it is one solution but not the only solution.
18 with left child 11 and right child 32 will also be a solution.
When deleting the root, the new root can be selected as
The highest number in the left subtree
or
The lowest number in the right subtree
So copy the value of the selected node to the current root. And then delete the selected node. If the selected node has children, you can repeat the process recursively.
In the case of deletion, if the node to be deleted has two children:
Find the successor or the predecessor
Replace the node with the contents of the successor/predecessor
Call delete on the successor/predecessor (this way the size will be decremented)
Return the node
The successor is the highest element on the right subtree while the predecessor is the lowest element on the left subtree. In your case, the successor would be 21 and the predecessor would be 18.
I am trying to delete the whole binary search tree ( every node in the tree), which one of these functions do you think will work better?
private:
struct Node {
string value;
Node* left;
Node* right;
};
Node* root;
public:
BST() {
root = NULL;
}
~BST() {
delete root->left;
delete root->right;
}
or:
...
void destroyTree (Node*& tree) {
while (tree != NULL) {
tree = tree->left;
delete tree;
}
while (tree != NULL) {
tree = tree->right;
delete tree;
}
delete tree;
}
Neither the proposed destructor ~BST() nor the proposed function destroyTree()of the class BST will delete the BST instance and will be better than the other.
Explanation 1 - what the destructor ~BST() is doing ?
The proposed source is simple delete root->left; followed by delete
root->right; and will delete only 2 nodes of the BinarySearchTree.
The node root is not check with NULL and otherwise is never deleted,
The node root->left is not check with NULL too,
The node root->right is not check with NULL too,
Explanation 2 - what the function destroyTree() is doing ?
Two while-loops to try the exploration of the tree, one for the left
branch and one for the right branch. The condition (tree != NULL) is
present only to exit from the loop but doesn't check if the current
node could be deleted.
With the left loop, only ->left nodes of the root->left will be deleted until tree->left == NULL and CRASH when trying to delete tree;,
Even after adding a if (tree==NULL) break; to exit from the loop before calling the delete tree; a new CRASH in the right loop,
And the last delete tree; is a non-sense because at this position, tree is always '== NULL`.
Bonus Solution - based to a modification of the function destroyTree().
A recursive function will be the simplest way to delete all created
and inserted nodes. But be aware with the size of the BinarySearchTree
and especially the deepest branch.
void destroyTree(Node *cur_node) {
if (cur_node!=NULL) {
// explore and delete on left
destroyTree(cur_node->left); // recursive-call
// explore and delete on right
destroyTree(cur_node->right); // recursive-call
// delete each node
delete cur_node;
}
}
I am trying to implement binary search tree operations and got stuck at deletion.
11
/ \
10 14
Using inorder traversal as representation of tree initially output is 10 11 14.
Deleting node 10, output expected is 11 14 but I am getting 0 11 14.
Deleting node 14, output expected is just 11 but I am getting 0 11 67837.
Please explain why I am getting wrong output. I am not looking for any code :).
typedef struct _node{
int data;
struct _node *left;
struct _node *right;
} Node;
Node* bstree_search(Node *root, int key)
{
if(root == NULL){
return root;
}
// Based on binary search relation, key can be found in either left,
// right, or root.
if(key > root->data)
return bstree_search(root->right, key);
else if(key < root->data)
return bstree_search(root->left, key);
else
return root;
}
void bstree_insert(Node **adroot, int value)
{
// since address of address(root is itself address) is passed we can change root.
if(*adroot == NULL){
*adroot = malloc(sizeof(**adroot));
(*adroot)->data = value;
(*adroot)->right = (*adroot)->left = NULL;
return;
}
if(value > (*adroot)->data)
bstree_insert(&(*adroot)->right, value);
else
bstree_insert(&(*adroot)->left, value);
}
void bstree_inorder_walk(Node *root)
{
if(root != NULL){
bstree_inorder_walk(root->left);
printf("%d ",root->data);
bstree_inorder_walk(root->right);
}
}
void bstree_delete(Node **adnode)
{
//Node with no children or only one child
Node *node, *temp;
node = temp = *adnode;
if((*adnode)->right == NULL || (*adnode)->left == NULL){
if((*adnode)->right == NULL){
*adnode = (*adnode)->left;
}else{
*adnode = (*adnode)->right;
}
}else{ // Node with two children
}
free(temp);
}
int main()
{
Node *root = NULL;
Node *needle = NULL;
int i,elems[] = {11,10,14};
for(i = 0; i < 3; ++i)
bstree_insert(&root,elems[i]);
bstree_inorder_walk(root);
printf("\n");
needle = bstree_search(root, 10);
bstree_delete(&needle);
bstree_inorder_walk(root);
printf("\n");
needle = bstree_search(root, 14);
bstree_delete(&needle);
bstree_inorder_walk(root);
printf("\n");
}
Please explain why I am getting wrong
output.
Your delete function must also change the parent of the deleted Node. For example, when you delete the node holding 10, you must set the root Node's left child to NULL. Since you don't do this, when you later traverse the tree, you print out data that has already been freed.
I did not look at any code other than delete, so I can't make any guarantees about it working once this change is made.
You're getting wrong output because your deletion code is buggy (okay, maybe that's stating the obvious).
To delete from a binary search tree, you first find the node to be deleted. If it's a leaf node, you set the pointer to it in its parent node to NULL, and free the node. If it's not a leaf node, you take one of two leaf nodes (either the left-most child in the right sub-tree, or the right-most child in the left sub-tree) and insert that in place of the node you need to delete, set the pointer to that node in its previous parent to NULL, and delete the node you've now "spliced out" of the tree.
A couple of things really quick,
first when you allocate the node, you really should be doing the malloc on the sizeof the type (ie Node).
Second, if you have 2 children it looks like you are not really deleting the node and rebuilding the search tree by promoting one of the children.
Other people have already got you other obvious errors.