Maintaining parent pointers during a recursive AVL Tree insert in C++ - 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.

Related

Floor Value of an element in a Binary Search Tree

So I was reading the book - Data Structures and Algorithms Made Easy by Narasimha Karumanchi and in that the floor Value of a bst snippet is given - Problem 61 in BST Chapter.
The snippet confused me very much and now I just want to know how it is working :
The snippet as Follows :
node* floorValue(node* root, node* prev ,int k)
{
if(!root){
return NULL;
}
if( !(floorValue(root->left , prev ,k))
{
return 0;
}
if(root->data == k)
{
return root;
}
if(root->data > k)
{
return prev;
}
prev = root;
return floorValue(root->right , prev , k);
}
In this the node* prev which is initiated with NULL is storing the previous node and int k is the integer for which we are finding the floor value.
Can someone please help me in understanding its recursion. I am confused because :
1 . The code : if( !(floorValue(root->left , prev ,k)) { return 0; }
will return 0 when the left most of the element of the tree is hit. But that will trigger all the recursive calls return 0.
Why it's returning 0 when we are returning the node* and not any int
Help will be really appreciated. I have solved this question but it was not using this method but a more straight forward one ( according to me ). I want to know what am I doing wrong or what I am missing in this code.
Input:
The First input will be the number of nodes:
The next n lines will be the nodes data. The first input after n will be the root value.
FULL CODE:
#include<bits/stdc++.h>
using namespace std;
struct node
{
int data;
node* left;
node* right;
};
node* insertBST(node* root , int x)
{
if(root==NULL)
{
node* root= new node;
root->data = x;
root->left = root->right = NULL;
return root;
}
else
{
if(x <root->data)
{
root->left = insertBST(root->left , x);
}
else
{
root->right = insertBST(root->right , x);
}
}
}
void inorder(node* root)
{
if(root)
{
inorder(root->left);
cout<<root->data<<" ";
inorder(root->right);
}
}
node* floorValue(node* root, node* prev ,int k)
{
if(!root){
return NULL;
}
if( !(floorValue(root->left , prev ,k))
{
return 0;
}
if(root->data == k)
{
return root;
}
if(root->data > k)
{
return prev;
}
prev = root;
return floorValue(root->right , prev , k);
}
int main()
{
int n;
cin>>n;
node *root = new node;
root = NULL;
for(int i = 0 ;i<n;i++)
{
int k;
cin>>k;
root= insertBST(root , k);
}
inorder(root);
cout<<"\nEnter the Value for which floor has to be searched : ";
int k;
cin>>k;
node* prev = NULL;
cout<<floorValue(root , prev, k);
return 0;
}
The code is exactly the same as given in the book except some variable names.
Thank You and thanks in advance.
The snippet you found is awful, but the answer to your questions is that return 0 is the same as return NULL -- it's not an integer, it's a null pointer. The code is supposed to return null if there is no node in the tree <= the search value.
Here's a much better implementation:
Node* floorNode(Node* tree, int k) {
Node *flr = NULL;
while(tree) {
if (tree -> data <= k) {
flr = tree;
tree = tree->right;
} else {
tree = tree->left;
}
}
return flr;
}
It's classic Binary Search algorithm. I always recommend you to understand the problem you posted. If you clear with algorithm you will know how Binary Search actualy works, as well as how Backtrack works using StackTrace of your system/computer memory.
Let's dive into that. :)
if(!root){
return NULL;
}
the above code snippet, is the case, if you reach here, it is guranteed you searched all the possibilities, but didn't find the 'key' you want. :(
if( !(floorValue(root->left , prev ,k))
{
return NULL;
}
Remember you should return NULL, instead of return 0, since the return value of your function is actually NULL, (though both 0/NULL defines the false case in c/c++, prematurely you can use any of it.
Now you can see, you are diving into the function, with root->left, means left-part of Tree are checking first, similar to Binary Search, where you are searching left side of your input elements.
if(root->data == k)
{
return root;
}
If you reach here, congrats, you finally reached into your destination :D, other words, you found your result in huge (or small, whatever) input elements.
if(root->data > k)
{
return prev;
}
The above snippent is same when your middle elements are greater than your key, so you know you have to go left side of your inputs. (going right will always give you Sadness, you will ended up with nothing).
prev = root;
return floorValue(root->right , prev , k);
The above code are telling you, you went left, but got 0 (you ended up with failure to find the result), so you need to go right side now.
Now most importantly, understand these two following snippets ::
if(root->data > k)
{
return prev;
}
and
prev = root;
return floorValue(root->right , prev , k);
The above two snippets not only dive you into left or right part of your tree (or inputs) but also checking each and every left and right node of your left Tree, and right and left of your right Tree.
When its failed to get the key you want, it's backtrack to your place where you started to go into LEFT (it's kind of DARK series, let's assume left is PAST here, :D right?? ) now you have to go to future, that's RIGHT, to find out the key.
you get the key ? return it from the left(past), or go to right(future) again.
you will definitely reach a conclusion, either SUCCESS or FAILURE.
enjoy.

Binary tree Node pointers

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.

c++ Linked List with priority queue

I trying to code out the Linked List with priority queue and i encountered some problem.
I have about 7 priority from 1 the most to 7 the least important.
here's my current insert method.
void queue::addToQueueList(int newPriority, double newFare, int custID)
{
node* newnode= new node;
newnode->priority= newPriority;
newnode->fare = newFare;
newnode->cusID = custID;
newnode->next= NULL;
if (isempty())
{
front = back = newnode;
}
else
{
node* temp = front;
if(newnode->priority < temp->priority)
{
newnode->next = front;
front = newnode;
}
else
{
while(newnode->priority < temp->priority)
{
if(temp->next == NULL)
{
break;
temp = temp->next;
}
}
if(temp->next == NULL && newnode->priority < temp->priority)
{
back->next = newnode;
back = newnode;
}
else
{
newnode->next = temp->next;
temp->next = newnode;
}
}
}
}
Invoked as:
qList->addToQueueList(2, 488.88, A);
qList->addToQueueList(1, 388.88, B);
qList->addToQueueList(3, 488.88, C);
Expected result should be :
B, A, C
THe result shows :
B, C, A
Your making this considerably harder than it needs to be. Ultimately you need to walk the list, find the insertion point, remember how you arrived at that insertion point, and wire both your fore and aft pointers appropriately. Also a priority queue has no reason to keep a "back" pointer, so I'm not sure why you have one.
There are a number of ways to do this. First, to make the code cleaner to understand, providing a proper parameterized constructor for node is both trivial and helpful:
struct node
{
int priority;
double fare;
int cusID;
node *next;
node(int p, double f, int id, node *nxt = nullptr)
: priority(p), fare(f), cusID(id), next(nxt)
{
}
};
One you have that, you can go down the road you were apparently trying to navigate, using a pointer-value list walking approach. To do that you need to maintain a previous pointer:
void queue::addToQueueList(int newPriority, double newFare, int custID)
{
node* temp = front, *prev = NULL;
while (temp && temp->priority < newPriority)
{
prev = temp; // remember how we got here
temp = temp->next; // advance to next node
}
// create new node, linking to temp
node *newnode = new node(newPriority, newFair, custID, temp);
// link to previous node or assign as new head, whichever is needed
if (prev != nullptr)
prev->next = newnode;
else
head = newnode;
// though there is no need for a back pointer in a priority queue
// you had one none-the-less, so....
if (!temp)
back = newnode;
}
it is worth noting that this algorithm will insert new arrivals with similar priority at the head of that priority section of the list. I.e. the newest arrivals for a given priority are always at the forefront of that priority's position in the queue. If you want the oldest arrivals of a given priority to be "ahead" of their brethren, you simply need to change this:
while (temp && temp->priority < newPriority)
to this:
while (temp && temp->priority <= newPriority) // note < is now <=
Best of luck.
The comparison in your while loop is wrong. When inserting C newnode->priority == 3 and temp(B)->priority == 1. Thus the while loop is never entered.
Also, the temp = temp->next inside the while loop should be outside (after) the if statement. Otherwise this will be an infinite loop.
Assuming you are correcting these: you will always insert the new element after temp. Be aware of this in your fix of your comparisons. You are likely to add comparisons with temp->next->priority as well.
I agree with Joachim in the comments: step through the code with a debugger. Then you can see the values of the variables and which comparisons produce which results.

Segfault when accessing non-null pointer?

The code works fine in a Linux environment, but in Windows it crashes 5-10 seconds after the program starts. The debugger points to n->fired = true; as the problem?
void ParticleSystem::PrivProcessParticles(pNodePtr n, double frameTime)
{
while(n != NULL) {
n->fired = true;
if(!n->immortal)
n->life -= frameTime; //Decrement life
n->particle.ApplyAccel2D(frameTime);
/* Since the oldest particles will always be on
top of the queue, if life is zero, dequeue! */
if(n->life <= 0) {
if(head != NULL && !n->immortal) {
pNodePtr curr;
curr = head;
head = head->next;
delete curr;
}
}
n = n->next;
}
}
Allocation:
void ParticleSystem::AddParticle(double lifeIn, double x, double y, double angle,
double size, double force, bool immortalIn)
{
//Increment particle count
count++;
//Allocate
pNodePtr n = new particleNode;
//Initialize
n->particle.CreateQuad(size);
n->particle.SetTexture(texture);
n->particle.SetPos2D(x, y);
n->particle.SetRot2D(angle);
n->particle.SetTopSpeed(topSpeed);
n->particle.SetVelocity(force);
n->life = lifeIn;
n->immortal=immortalIn;
n->fired = false;
n->next = NULL;
//Place
if (head == NULL)
{
head = n;
tail = n;
n->next = NULL;
} else {
tail->next = n;
tail = n;
}
}
Node:
struct particleNode {
Quad particle;
double life;
bool fired;
bool immortal;
particleNode* next;
};
There's not enough information posted. However, here's one potential source of the problem.
When your PrivProcessParticles function performs its iterations over n, it can decide to delete head element of your list. But is it possible that at the moment when it decides to delete head, n is actually the same as head? If so, deleting head turns n into a dangling pointer, which leads to disastrous consequences at n = n->next.
Add assert(curr != n) before delete curr and see whether that assertion holds or fails.
Anyway, what is the starting value of n passed to PrivProcessParticles by the caller? Can it by any chance happen to be the same as head?
P.S. Also, just out of curiosity, the logic that you use to decide whether to perform the deletion or not seems to suggest that the decision is actually made about node n (you check n->life <= 0 and n->immortal). But then you proceed to delete head, not n... Is that by design?
P.P.S. A nitpick: you are doing excessive n->next = NULL initializations in your AddParticle.

Insertion Sort with a Singly Linked List in C++

I'm trying to write a method for my LinkedList class that will sort a linked list of Person objects by their name. My method compiles fine but when I try to sort a list of people, the output is incorrect. It also never stops running. For example, this code
Person *p1 = new Person("K", "B");
Person *p2 = new Person("A", "A");
Person *p3 = new Person("S", "M");
Person *p4 = new Person("B", "M");
LinkedList ll;
ll.insertFront(*p1);
ll.insertFront(*p2);
ll.insertFront(*p3);
LinkedList newList = ll.insertionSort();
newList.print();
cout << endl;
Gives this output
B, K
A, A
Could anyone help me figure out where I went wrong with my algorithm? Thanks!
This is the method I use to sort names by both first and last:
int Person::compareName(Person p)
{
if (lName.compare(p.lName) > 0)
{
return 1;
}
else if (lName.compare(p.lName) == 0)
{
if (fName.compare(p.fName) > 0)
{
return 1;
}
else return -1;
}
else return -1;
}
Insertion Sort Method:
LinkedList LinkedList::insertionSort()
{
//create the new list
LinkedList newList;
newList.front = front;
Node *n;
Node *current = front;
Node *trail = NULL;
for(n=front->link; n!= NULL; n = n->link)//cycle through old chain
{
Node* newNode = n;
//cycle through new, sorted chain to find insertion point
for(current = newList.front; current != NULL; current = current->link)
{
//needs to go in the front
if(current->per.compareName(n->per) < 0)
{
break;
}
else
{
trail = current;
}
}
//if it needs to be added to the front of the chain
if(current == front)
{
newNode->link = newList.front;
newList.front = newNode;
}
//else goes in middle or at the end
else{
newNode->link = current;
trail->link = newNode;
}
return newList;
}
You have current->link in your inner for loop, and in the else to the inner for loop. I assume that you really have current = current->link in the for loop or it does nothing. If so, you'd be skipping every other element.
You also have a language thing- you aren't creating new nodes, you're altering the nodes on your original list. That measn you're changing the list as you walk it, which will corrupt the list as you sort it. Behavior is undefined and dependent on the order in which you add elements.
Even after you have fixed any linked list handling issues (which I haven't looked at), your compareName() function has a flaw - when comparing Person objects that have the same last name it may return from the function without providing a value (in the cases where Name.compare(p.fName) <= 0).
Getting an indeterminate result from the compare function will break pretty much any sort.
Since this is likely homework, I'll leave correcting the problem as an exercise.