Binary tree Node pointers - c++

I have a struct for my binary tree
struct BST::Node
{
Key key;
Item item;
Node* leftChild;
Node* rightChild;
Node(Key k, Item i)
{
key = k;
item = i;
leftChild = nullptr;
rightChild = nullptr;
}
};
I am trying to insert into the tree however I am getting an error saying if there is a handler for this exception the program may be safely continued. I think there might be something wrong with the way I am using pointers but I'm not 100% sure what it is, any help would be appreciated, thanks. This is my insert method that has to use recursion
void BST::insert(Key k, Item i)
{
insertRec(k, i, root);
}
void BST::insertRec(Key k, Item i, Node* n)
{
if (n == NULL)
{
n->item = i;
n->key = k;
}
else if (k < n->key)
{
insertRec(k, i, n->leftChild);
}
else if (k > n->key)
{
insertRec(k, i, n->rightChild);
}
}
Node* root is a nullptr.

Look closely at the following snippet from your code:
void BST::insertRec(Key k, Item i, Node* n)
{
if (n == NULL)
{
n->item = i;
n->key = k;
}
You are setting n->item = i when n == NULL. This is wrong! NULL pointers don't point at valid objects.
Instead, you should just allocate a new node:
if (n == NULL)
{
n = new Node(k, i);
}
But remember, when you are removing a node from your tree, after returning the value, you should always delete it.
Moreover, you should allocate your root during the construction of you BST class using the same method, and delete it during destruction.

Few things you need to take care:
1) inside
if (n == NULL)
{
n->item = i;
n->key = k;
}
above block before assigning item and key values, you need to allocate memory to the node.
n = new Node(i,k);
2) Now even after following the first point mentioned above the new node created will not be assigned to the root of BST(if tree is empty) as the root is passed by value. So either pass root as reference or as a pointer to pointer. Change the new node creation part as per your decision to pass by reference or by pointer to pointer.

Related

Maintaining parent pointers during a recursive AVL Tree insert in C++

I am seeking a way to recursively maintain the parent pointer in my AVL tree insert.
I am aware that this is not the usual process however I am meant to have a function to manually rotate the nodes so the parent is necessary.
The closest I've gotten is to maintain the parents of the root and the nodes that are not pointing to NULL. all the others will just point to themselves. If I uncomment my other parent insertion, I get segfaults.
AVL::node *AVL::insert(int k, string d, node *&n)
{
//recursive base case, I imagine n->parent = n should not be here
if (n == NULL) {
n = new node;
n->left = NULL;
n->right = NULL;
n->key = k;
n->data = d;
n->height = 1;
n->parent = n;
return n;
}
if (n->key > k) {
if (n->left != NULL) {
n->left->parent = n;
insert(k, d, n->left);
} else {
//n->left->parent = n;
// this creates SEGFAULT
insert(k, d, n->left);
}
} else if (n->key < k) {
if (n->right != NULL) {
n->right->parent = n;
insert(k, d, n->right);
} else {
//n->right->parent = n;
// this creates SEGFAULT
insert(k, d, n->right);
}
} else {
return n;
}
// insert height management here
updateHeight(n);
return n;
}
You almost got it. The remaining piece of the puzzle you missed is:
insert(k, d, n->left);
Your approach of passing in a reference to what would become the pointer that's would be pointing to the newly created node in your AVL tree (in this case this would be n->left), is the right approach.
Your missing piece is making the obvious observation that the new node needs to know it's parent, and you're staring at it, right here, on the above line. It's n:
insert(k, d, n, n->left);
Now, insert() knows the parent node (and the other recursive call, that uses n->right, does the same thing):
AVL::node *AVL::insert(int k, string d, node *parent, node *&n)
You can completely broom away all that convoluted logic that attempts to fiddle with parent, and whether the pointers were nullptr before/after the recursive calls. Your recursive insert() knows exactly what the parent is, in a much simpler fashion:
if (n == NULL) {
n = new node;
n->left = NULL;
n->right = NULL;
n->parent = parent;
That's pretty much it, this becomes a big, fat, nothingburger. Presumably, the initial call to insert(), that start rolling the ball down the hill with the AVL tree's root node will pass a nullptr for the parent parameter, and everything works out by itself.

Binary Tree Destructor Issue

I have recently been implementing a binary tree in my free-time and I do believe I have it working correctly. However, I have ran into a mysterious segmentation fault when running a simple test. Here is my implementation of the binary search tree:
//the binary search tree class
template <class M>
class BS_Tree {
private:
//node structure
struct Node {
M data; //the key of the node
Node* left,* right,* parent; //node pointers to left right and parent
Node(M key, Node* p) //parameterized node constructor
: data(key), left(nullptr), right(nullptr), parent(p) {}
};
Node* root; //the root node of the binary search tree
bool is_left(Node* n) {return n->parent->left == n;} //utility function
void destroy(Node* n); //used for tree destruction
void duplicate(Node* const &, Node* &); //used for copy construction
public:
BS_Tree() {root = nullptr;} //constructor
~BS_Tree() {destroy(root);} //destructor
BS_Tree(const BS_Tree &); //copy constructor
BS_Tree &operator=(const BS_Tree &); //copy assignment operator
Node* find(M key); //find function
void insert(M); //insert function
void erase(Node*); //erase function
Node* get_root() {return root;}
};
//destroy function used for tree destruction
template <class M>
void BS_Tree<M>::destroy(Node* n) {
if(n) { //recursively erase the tree
if(n->left) destroy(n->left);
if(n->right) destroy(n->right);
delete n;
}
}
//duplicate function used for copy construction
template <class M>
void BS_Tree<M>::duplicate(Node* const &one, Node* &two) {
if(!one) two = nullptr;
else { //recursively duplicate the tree
two = new Node(one->data);
duplicate(one->left, two->left);
duplicate(one->right, two->right);
}
}
//copy constructor
template <class M>
BS_Tree<M>::BS_Tree(const BS_Tree &b) {
if(!b.root) root = nullptr; //update root
else duplicate(b.root, this->root); //call duplicate function
}
//copy assignment operator
template <class M>
BS_Tree<M> &BS_Tree<M>::operator=(const BS_Tree &b) {
if(!b.root) root = nullptr; //update root
else { //destroy current tree and duplicate source tree
this->~BS_Tree();
duplicate(b.root, this->root);
}
}
//function to find a key and return a pointer
template <class M>
typename BS_Tree<M>::Node* BS_Tree<M>::find(M key) {
Node* i = root; //create an index
while(i) {
//try to find the key
if (i->data == key) return i;
if(i->data > key) i = i->left;
else i = i->right;
}
//return a pointer to the key, nullptr if not found
return i;
}
//function to insert a new node
template <class M>
void BS_Tree<M>::insert(M key) {
if(!root) { //if no tree, make new node the root
root = new Node(key, nullptr);
return;
}
Node* i = root; //create an index
while(true) { //find insertion point and insert new node
if(i->data > key) {
if(!i->left) {
i->left = new Node(key, i);
return;
}
else i = i->left;
}
if(i->data <= key) {
if(!i->right) {
i->right = new Node(key, i);
return;
}
else i = i->right;
}
}
}
//Function to erase a node
template <class M>
void BS_Tree<M>::erase(Node* n) {
if(n) {
//no children case
if(!n->left && !n->right) {
if(root == n) root = nullptr; //if node is root, make root null
else { //if node is a child, update parent's children
if(is_left(n)) n->parent->left = nullptr;
else n->parent->right = nullptr;
}
delete n; //erase the node
return;
}
//one child cases
if(!n->left) {
if(n == root){ //if node is root, update root
root = n->right;
n->right->parent = nullptr;
} else { //if node is a child, update parent's children and nodes parent
if(is_left(n)) n->parent->left = n->right;
else n->parent->right = n->right;
n->right->parent = n->parent;
}
delete n; //erase the node
return;
}
if(!n->right) {
if(n == root){ //if node is root, update root
root = n->left;
n->left->parent = nullptr;
} else { //if node is a child, update parent's children and nodes parent
if(is_left(n)) n->parent->left = n->left;
else n->parent->right = n->left;
n->left->parent = n->parent;
}
delete n; //erase the node
return;
}
//two children case
else {
Node* i = n; //create an index
i = i->right; //find successor
while(i->left) i = i->left;
n->data = i->data; //set nodes data to successor's data
if(is_left(i)) i->parent->left = i->right; //update successor's parent and its child
else i->parent->right = i->right;
if(i->right) i->right->parent = i->parent;
delete i; //erase successor node
return;
}
}
}
As for the test, it is a simple linear vector element insert vs time performance check. It takes a max number of elements and an increment of elements for each test. It then runs the test for each increment and times the insertions. It works fine for the first few iterations (i.e n = 10000, 20000, 30000, 40000), but then I reach a segmentation fault after insertion when the 50000 element tree destructor is called. It is hinting at the line:
if(n->right) destroy(n->right);
I understand that I am doing an incremental insertion so all of my elements are on the right side of the tree, but I am having a hard time figuring out where I went wrong and why it only messes up on this iteration.
My test implematation:
int main(){
//number of elements, max test elements, and test increment
int n, t = 100000, i = 10000;
//run the test a number of times
for(n = i; n <= t; n += i) {
//get an incremental vector of size n
std::vector<int> test(n);
std::iota(std::begin(test), std::end(test), 0);
//run the insert test print the time interval
BS_Tree<int> m;
auto ibs_start = clock();
for(auto i : test){
m.insert(i);
}
auto ibs_stop = clock();
std::cout << n << ' ' << (ibs_stop - ibs_start)/double(CLOCKS_PER_SEC)*1000 << "\n";
}
return 0;
}
If someone could help I would greatly appreciate it!
Edit: Could it simply be my stack overflowing due to the destroy function having to store all of the elements before reaching the bottom and actually deleting anything?
If it works for some number of items (40000), but not for a larger, it might be a stackoverflow. Looking at the code also confirms this: destroying is recursive, and in the case of extremely unbalanced tree, it means as many stack frames as many nodes.
The question is how this could be solved without recursion? This is not so obvious, as there are two recursive calls. My solution is to traverse the binary tree, post-order, and delete leaf nodes.
Here is a solution -- an iterative version of the destroy method:
//destroy function used for tree destruction
template <class M>
void BS_Tree<M>::destroy(Node* n) {
if (n) { // iteratively erase the tree
Node* c = n; // current node
while (true) {
if (c->right) {
// it has right child, descend to it
c = c->right;
continue;
}
if (c->left) {
// it has left child, descend to it
c = c->left;
continue;
}
// this node has no (more) children, destroy it
Node* p = c->parent;
if (p) {
// update its parent to no longer point to it
if (p->right == c) p->right = NULL; // we came from left
else if (p->left == c) p->left = NULL; // we came from left
}
// destroy the node
delete c;
// go back to its parent
c = p;
if (c == n) {
// where at back at start node, stop
delete n;
break;
}
}
}
}
Update: I have tested my solution, and made some small changes.

Recursive call and assignment of reference pointers

I am feeling confused by the pointers in c++, where I am trying to implement BST.
Instead of (method 1)having a type of node, I want to use reference pointer (method 2).
How could I rewrite if statement, so it would work in a method where pointers been used?
How node p in (2) could be assigned to another temp node?
Thank you so much.
//1
node* delete(node* p, int k) // deleting k key from p tree
{
if( k < p->key )
p->left = remove(p->left,k);
}
//2
void delete(int key, node*& p) {
// recursive call while key is less and assign a new left child.
if( k < p->key ) {
//??
}
}
node *getNode(int key, node *haystack){
if(!haystack)
return NULL;
if(haystack->val == key)
return haystack;
if(haystack->val < key)
return getNode(key, haystack->left);
return getNode(key, haystack->right);
}
void getNode(int key, node *haystack, node *&result){
if(!haystack){
result = NULL;
return;
}
if(haystack->val == key){
result = haystack;
return;
}
if(haystack->val < key){
return getNode(key, haystack->left, result);
}
return getNode(key, haystack->left, result);
}
They end up being pretty much the same. If you actually want to delete, however, there's quite a bit more work involved, since you need to set the deleted node's pointer to the deleted node to NULL if the deleted node is a leaf, or you need to add the children of the deleted node to the tree (or delete those, too).
I'm assuming you want to pass a reference so you can zero out the pointer?
something like this should work:
void delete_node(int key, node*&p)
{
if (key < p->key) {
delete_node(key, p->left);
delete(p);
p = nullptr;
}
}
But it's a little naughty. It restricts the number of cases in which your function can be called and it adds some potentially surprising behaviour in that it alters its input argument. It also means that your node's left member is being zeroed out un-necessarily when nodes are deleted recursively (since the current node will itself be deleted anyway).

How to return the nth last element in a singly linked list using recursion?

So I have this recursive solution to print the nth element from the end of the list:
void print_nth_from_last_rec(Node* node, int n) {
static int count { 0 };
if (!node) return;
print_nth_from_last_rec(node->next, n);
if (++count == n)
cout << node->data;
}
But I can't figure out how to return that element using recursion. Is it possible?
Attempts:
I can do it if I have a static Node* that will be assigned to when (++count == n):
Node* get_nth_from_last_rec(Node* node, int n) {
static int count { 0 };
static Node* ret{ nullptr };
if (node) {
get_nth_from_last_rec(node->next, n);
if (++count == n)
ret = node;
}
return ret;
}
It is also possible to pass in a reference to the out Node and assign the nth element to it.
But is there a better way? These statics don't look very clean to me.
Node* get_nth_from_last_rec(Node* node, int& n)
{
if (node)
{
Node* result = get_nth_from_last_rec(node->next, n);
if (result)
return result;
else if (! n--)
return node;
}
return nullptr;
}
Here's how I'd do it (I hope it's obvious from context what advance does):
Node* get_nth_from_last(Node* node, int n, Node *ahead = 0) {
if (ahead == 0) {
// might like to check for size < n at the same time
// and return something to indicate error in that case
ahead = advance(node, n);
}
if (ahead->next == 0) return node; // or whatever the end condition is
return get_nth_from_last(node->next, n, ahead->next);
}
If you want to hide that default parameter away from the caller, then use a helper function. It's only needed for efficiency anyway, if you want really slow code then do without it and call advance at every recursive step.
You should pretty much never need static variables just to make your recursion work. You can always add parameters with default values, or else write a helper function with extra parameters and call that to do all the work. Aside from any confusion they might cause the reader, they make the function non-thread-safe, and non-reentrant from signal handlers.
My code does 2 * len - n node advances, and yours only does len (plus n pieces of work coming back out of the recursion). If you want to stick with your performance characteristics but sacrifice tail recursion, then something like this (I'm either out-by-one on this, or on my first answer, depending on the meaning of n...):
Node* get_nth_from_last_helper(Node* node, int &depth) {
if (node == 0) return 0;
Node *n = get_nth_from_last_helper(node->next, depth);
--depth;
return (depth == 0) ? node : n;
}
Node *get_nth_from_last(Node *node, int n) {
return get_nth_from_last_helper(Node *node, n);
}
Personally I would use the nth from front function count down to 0
Node* get_nth_from_first_rec(Node* node, int n) {
if (!node || n == 0) {
return node;
}
return get_nth_from_last_rec(node->next, n - 1);
}
And count the number of elements in the list (recursively if you want)
int get_list_length(Node* node) {
if (!node) {
return 0;
}
return 1 + get_list_length(node->next);
}
So then I could compute the index as an nth from first index
Node* get_nth_from_last_rec(Node* node, int n) {
int count = get_list_length(node);
return get_nth_from_first_rec(node, n - count);
}
Here I believe I have a neat tail recursion way of solving it in Java.
public static LinkedListNode findnthToLastRecursionHelper(LinkedListNode node, LinkedListNode last,int pos){
if(node==null) return null;
if(pos<1)
{
pos=1; //We have reached the nth iteration for last, now time to increment node and last together.
node = node.next;
if(last==null) return node;
}
else if(last==null) return null;
return findnthToLastRecursionHelper(node,last.next,--pos);
}
This is the main tail recursion chunk that cares of moving the last pointer to the nth position, and once position is reached it moves node & last pointer together.
public static LinkedListNode findnthToLastRecursion(LinkedListNode head,int pos){
return findnthToLastRecursionHelper(head,head.next,pos);
}
This is the caller function in order to maintain the aesthetics.

Binary Tree Insertion Pointer Issue

I have two functions in a class that creates a binary tree:
void Btree::insertNode(node* r, node* newNode){
if (r == NULL)
r = newNode;
else if (greater(root, newNode))
insertNode(r->left, newNode);
else
insertNode(r->right, newNode);
}
void Btree::load(){
for (int i = 0; i < mainVec.size(); ++i){
node* n = new node;
n->index = i;
for (int j = 0; j < mainVec[i].size(); ++j)
n->s += mainVec[i][j];
insertNode(root, n);
}
printTree(root);
return;
}
I'd like load to fill up the tree at root (root is a private node pointer node* root), but every time insertNode exits root is still a null pointer. Could someone point out my stupid mistake?
You'll need to make parameter r passed as a reference to be able to change root from inside the function insertNode.
See the below:
void Btree::insertNode(node*& r, node* newNode) {
...
}
You need to pass root by reference.