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.
Related
I wanted to implement a BST class with a vector and somehow its not working. I just wanted to know the reason why its not working.
The main reason that I can think of that root in the BST always remain NULL.
I wanted to experiment ways to use classes in data structures.
#include<iostream>
#include<vector>
using namespace std;
class Node{
public:
int data;
Node* left ;
Node* right ;
Node(int val){
data = val;
left = NULL;
right = NULL;
}
};
class BST{
public:
Node* root = NULL;
void insert(Node* r,int data){
Node* new_node = new Node(data);
if(r == NULL){
r = new_node;
}
if(data < r->data){
if(r->left == NULL){
r->left = new_node;
}
else{
insert(r->left,data);
}
}else if(data > r->data){
if(r->right == NULL){
r->right = new_node;
}
else{
insert(r->right,data);
}
}else{
return;
}
return;
}
BST(vector<int> bst_array){
for(int i = 0; i<bst_array.size(); i++){
insert(root,bst_array[i]);
}
}
void print_t(Node* r){
if(r == NULL){
cout<<"NULL";
return;
}
else{
print_t(r->left);
cout<<r->data<<" ";
print_t(r->right);
}
}
};
int main(){
vector<int> v = {1,3,5,44,23,78,21};
BST* tr = new BST(v);
tr->print_t(tr->root);
return 0;
}
There seem to be a logical mistake on my end please help me find it.
Thanks in advance.
The reason is that root is never assigned another value after its initialisation to NULL. Passing root as argument to the insert method can never alter root itself, as it is not the address of root that is passed, but its value.
Some other remarks:
insert always starts by creating a new node, at every step of the recursion. This is a waste of node creation. In the end you just need one new node, so only create it when its position in the tree has been identified.
The final else is not needed, as all it does is execute a return, which it would have done anyway without that else block
As insert is a method of BST, it is a pity that it requires a node as argument. You would really like to just do insert(data) and let it take care of it. For that to happen I suggest to move your insert method to the Node class, where the this node takes over the role of the argument. Then the BST class could get a wrapping insert method that forwards the job to the other insert method.
Instead of NULL use nullptr.
To solve the main issue, there are many solutions possible. But after making the above changes, it is quite easy to assign to root in the simplified insert method on the BST class.
Here is how it could work:
class Node{
public:
int data;
Node* left ;
Node* right ;
Node(int val){
data = val;
left = nullptr;
right = nullptr;
}
void insert(int data) {
if (data < this->data) {
if (this->left == nullptr) {
this->left = new Node(data);
} else {
this->left->insert(data);
}
} else if (data > this->data) {
if (this->right == nullptr) {
this->right = new Node(data);
} else {
this->right->insert(data);
}
}
}
};
class BST {
public:
Node* root = nullptr;
void insert(int data) {
if (root == NULL) { // Assign to root
root = new Node(data);
} else { // Defer the task to the Node class
root->insert(data);
}
}
BST(vector<int> bst_array){
for(int i = 0; i<bst_array.size(); i++){
insert(bst_array[i]); // No node argument
}
}
/* ...other methods ...*/
}
Okay so I seem to have gotten a bit lost. I am trying to insert data into a tree and when checking for balance and whether or not to rotate, I default to checking through the root. When I check examples online, I see that we can also rotate along other nodes in the tree as well. How do we figure out which node to use to balance the tree and how do we reach said node? I also saw that instead of having void functions to implement the insert and rotation functions, people use a node pointer return type instead. What is the purpose of that? I know the answers may be super obvious I am just lost.
struct TNode{
int data;
TNode* left;
TNode* right;
};
class Tree{
public:
TNode* root;
public:
Tree()
{root = nullptr;}
int height(TNode* node);
int balanceFactor(TNode* node);
bool isBalance(TNode* node)
{return balanceFactor(node)<-1 && balanceFactor(node)>1?true:false;}
void avlInsert(int key);
void LLRotation(TNode* node);
};
int Tree::height(TNode* node){
int l = 0;
int r = 0;
if(!node->left && !node->right)
return 0;
if(node->left)
l = height(node->left) + 1;
if(node->right)
r = height(node->right) + 1;
return l > r ? l : r;
}
int Tree::balanceFactor(TNode *node){
if(node->left && node->right)
return height(node->left) - height(node->right);
else if(node->left && !node->right)
return height(node);
else
return -1 * height(node);
}
void Tree::LLRotation(TNode *node){
TNode* nl = node->left;
node->left = nl->right;
nl->right = node;
if(root == node)
root = nl;
}
void Tree::avlInsert(int key){
TNode* trav;
TNode* follow;
TNode* node = new TNode;
node->data = key;
node->left = nullptr;
node->right = nullptr;
if (!root)
root = node;
else{
trav = root;
while (trav){
if (key < trav->data){
follow = trav;
trav = trav->left;
}
else{
follow = trav;
trav = trav->right;
}
}
if(key < follow->data)
follow->left = node;
else
follow->right = node;
}
if (balanceFactor(root) == 2 && balanceFactor(root->left) == 1)
LLRotation(root);
}
It really depends on your implementation some people they want to return a node, using a void function does not change the result much. For insert function you need to check only after you insert the node so you can go ahead and insert that node than rotate it. Please note that this function will only work if you have an AVL Tree to start with. Also your code is not correct, below:
if (balanceFactor(root) == 2 && balanceFactor(root->left) == 1)
LLRotation(root);
This is not how you check it for insertion.... That's for deletion buddy, I think you are getting mixed up. Usually for insertion you check if the balanceFactor is between 1 and -1, so if you are getting 2, then it is a left heavy tree, in your case, because it is left-right, which means you should do Right rotation........ Buddy......
int l = 0;
int r = 0;
if(!node->left && !node->right)
return 0;
if(node->left)
l = height(node->left) + 1;
if(node->right)
r = height(node->right) + 1;
return l > r ? l : r;
Height function, extremely inefficient... Instead define height as a variable for node and then modify it after each insertion, deletion.
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.
I've been trying to create an ordered double linked list and then print it out forwards and backwards using recursion. I don't know if I'm adding nodes to the linked list incorrectly or if my problem is in my print functions.
Main
int main() {
ifstream addData;
addData.open("proj1adds.data");
LinkedList<int> List;
Node<int> *head = NULL:
int add;
int i = 0;
while (!addData.eof()){
addData >> add;
List.add(i, add);
i++;
}
}
this is my add function
template < typename T >
void LinkedList < T >::add(int index, T element)
{
if (index == 0){
addFirst(element);
}
else if (index >= size){
addLast(element);
}
else
{
Node < T > * current = head;
for (int i = 1; i < index; i++)
current = current->next;
Node < T > * temp = current->next;
current->next = new Node < T > (element);
(current->next)->prev = current;
(current->next)->next = temp;
size++;
}
}
And these are my print functions
template<typename T>
void LinkedList<T>::printForward(Node<T> *head){
if(head==NULL){
return;
}
cout << head->element << endl;
printForward(head->next);
}
template<typename T>
void LinkedList<T>::printBackward(Node<T> *head){
if(head==NULL){
return;
}
printBackward(head->next);
cout << head->element << endl;
}
I think that I've loaded the data into the nodes, but I'm not sure if its ordered because I cant print it.
In a comment (but not in your question) you say that you're calling printFowards(head) and printBackwards(head) in main(). But in main(), the variable head is a local variable that is set to NULL. So the functions abort, and when you comment out the exit condition [shudder] you dereference a null pointer and get Undefined Behavior.
Maybe the list is being constructed correctly; it doesn't matter because your calls to the printing functions have no connection to the list.
I'm trying to delete the n'th element, which is a random number from 1 to n.
My code does this fine (correct element is deleted and surrounding elemnts are connected) but when it comes to being efficient, it is crashing when I un-comment the line delete (nodeToRemove); and I'm not sure why. Does anyone have any insight?
Assuming my struct looks like :
struct Node {
int data; // The data being stored at the node
Node *next; // Pointer to the next node
};
//------------------------------------------------------------------------------
void deleteNthElement (Node * & head, Node * &temp, int random)
{
temp = head;
Node *nodeToRemove;
if (random == 1)
{
nodeToRemove = temp;
head = head->next;
}
else
{
for (int i = 1; i < random - 1; i++)
temp = temp->next;
nodeToRemove = temp->next;
temp->next = temp->next->next;
}
// delete (nodeToRemove); <----- uncommenting this leads to crash,
}//end deleteNthElement()
//------------------------------------------
int main()
{
Node *head = NULL;
Node *temp;
Node *listarray[n[i]];
int n[] = {1000, 5000, 9000, 105000, 400000, 500000, 505000, 800000, 995000, 1000000};
for (int j = 0; j < n[i]; j++)
listarray[j] = new (Node);
//start timer
begin = clock();
//fill it
for (int j = 0; j < n[i]; j++)
{
listarray[j]->data = (rand() % n[i] + 1);
insertNodeInOrder (head, temp, listarray[j]);
}
//delete it
for (int j = 0; j < n[i]; j++)
deleteNthElement (head, temp, (rand() % (n[i] - j) + 1));
//deallocate
for (int j = 0; j < n[i]; j++)
delete listarray[j];
delete *listarray;
//end timer
}
You're picking the wrong Node, you want:
...
nodeToRemove = temp;
...
At least, you have to check for the end of the list, that is, you need to avoid access to null pointers (i really hope you set next to 0 at the end of the list). If you add the allocation parts, I will extend my answer.
void deleteNthElement (Node * & head, Node * &temp, int random)
{
temp = head;
Node *nodeToRemove;
if (random == 1)
{
nodeToRemove = temp;
if(head != 0)
head = head->next;
} else {
for (int i = 1; i < random - 1; i++)
if(temp != 0)
temp = temp->next;
else throw 1; // no such index; throw something more verbose :)
if(temp == 0)
throw 1; // same situation as above
nodeToRemove = temp->next;
if(nodeToRemove == 0)
throw 1; // same situation as above
temp->next = temp->next->next;
}
if(nodeToRemove == 0)
throw 1; //no such index; ... as the above 3
delete nodeToRemove;
}//end deleteNthElement()
Some clean-up first:
Why pass in two pointers here? do you need the value of temp out? If so why not return it?
Also why the node * & temp? (I can see why it is done for head).
int random should probably be called something like index as it describes the functionality better (as far as the function is concerned, there is nothing random about it).
The same with temp.
I propose:
void delete_element (Node* &head, int index)
{
Node* parent_node = head;
Node* node_to_remove;
//...
We don't need temp if we are removing the head. Also, we generally 0 index things, so we should reflect that too. Thus it becomes:
if (index== 0)
{
node_to_remove= head;
head = head->next;
}
Now we get to the main bit. The loop is just there to step through to the parent node of the node to delete, so we can simplify it a little and add checks to make sure we can't 'fall off' the end of the list.
We then have to make sure there is a node to remove, (so another check). We don't need to check for a node beyond as assigning nullptr isn't a problem (I am assuming that an invalid pointer is set to nullptr here):
{
while(--index && parent_node->next){ //pre-decrement means we stop before the one we want (parent)
parent_node = parent_node->next;}
if (parent_node->next){node_to_remove= parent_node->next;}
else {return;} //no point deleting it if it doesnt exist
parent_node->next = node_to_remove->next;//less indirection is always good. Ok if this is nullptr
}
Incidentally, this fixes a probable off by one error. Which is probably your problem (did it crash every time? only when deleting the last element? next to last?
Now we just need to delete it.
Putting it all together:
void delete_element (Node* &head, int index)
{
Node* parent_node = head;
Node* node_to_remove;
if (index== 0)
{
node_to_remove= head;
head = head->next;
}
else
{
while(--index && parent_node->next){ //pre-decrement means we stop before the one we want (parent)
parent_node = parent_node->next;}
if (parent_node->next){node_to_remove= parent_node->next;}
else {return;} //no point deleting it if it doesnt exist
parent_node->next = node_to_remove->next;//less indirection is always good. Ok if this is nullptr
}
delete node_to_remove;
return;
}
And that should work fine. The checks will prevent us dereferencing null pointers which was (probably) what caused you to crash. Can't tell without full code.