Binary Search Tree Insertion C++ - c++

Maybe asked million times before but I simply cannot understand what's wrong with this. I didn't want to use any code on the internet so I've just tried to program what's on my mind. Either this or my print function is wrong. Is there anything wrong with the code below?
void addNode(int value)
{
Node* newNode=new Node;
newNode->data=value;
if(root==NULL)
root=newNode;
else {
Node* temp=root,*parent;
while(temp!=NULL)
{
parent=temp;
if(temp->data == value)
return;
else if(temp->data < value)
temp=temp->left;
else
temp=temp->right;
}
temp=newNode;
}
}

temp=newNode;
This assigns the pointer to a local variable, which is discarded when the function returns, losing the new node. Instead, you want to assign it to a pointer within the tree; perhaps something like:
if (temp->data < value) { // If the new node should be to the left
if (temp->left) { // If there is a left subtree
temp = temp->left; // Move into the left subtree
} else { // Otherwise
temp->left = newNode; // Insert the new node there
return; // Done.
}
}
and likewise for temp->right if value < temp->data.
Also:
if (temp->data == value)
return;
You have a memory leak there; you should delete newNode before returning.

Related

Logical error in insertion of node in a BST

I have written a node insertion code for a BST. But it dosen't seem to work correctly. Its giving a "Segmentation error". Here is my logic for insertion.
void insert(Node* root, int data){
if(root==NULL){
root= new Node;
root->data = data;
}
else if(data < root->data){
insert(root->left,data);
}
else if(data> root->data){
insert(root->right,data);
}
}
How do i fix it? Thanks
Edit: so i tried out some things and this one does the trick
Node* insert(Node* &root, int data){
if(root==nullptr){
root = create(data);
return root;
}
else if(data < root->data){
insert(root->left,data);
}
else if(data> root->data){
insert(root->right,data);
}
}
Whats the difference between Node* root and Node* &root ?
Well, if node doesn't exists (it's NULL), you're just setting your root pointer to new Node, but you're missing to 'hang it up' to it's parent. And as already mentioned, you can use unique_ptr-s since C++11 to avoid memory leaks (that's when you forget to delete object). It looks like:
struct Node {
int data = -1; // not initialized
std::unique_ptr<Node> l;
std::unique_ptr<Node> r;
}
void insert(Node *root, int data) {
if (root->data == -1) {
root->data = data;
return;
}
if (data < root->data) {
if (!root->l) {
// hanging new left node up
root->l = std::make_unique<Node>(); // std::make_unique comes since C++14
}
insert(root->l.get(), // getting raw ptr
data);
}
else {
if (!root->r) {
// hanging new right node up
root->r = std::make_unique<Node>();
}
insert(root->r.get(), data);
}
}
Also you might be interested in data structure called treap, because your implementation may work very long if you insert, for example, increasing sequence:
Node root;
for (int i = 1; i <= 100'000; i++) {
insert(&root, i);
}
So your binary tree in this case looks like:
1
\
2 <=
\ <= very long path
3 <=
\
...
\
100'000
Treap helps to avoid long paths in your BST.

Runtime error in insertion sort

Im trying to do insertion sort using linked list but this code seems to have runtime error.
void Insert(int data)
{
node* temp=new node();
temp->data=data;
temp->link=NULL;
if(head==NULL)
{
head=temp;
return;
}
node* current=head;
if(current->data>data)
{
temp->link=head;
head=temp;
return;
}
else
{
current=head;
node* trail=head;
while(current->data<=data)
{
trail=current;
current=current->link;
}
trail->link=temp;
temp->link=current;
}
}
Your issue is in the else block of your second if.
You're looping through the list, and everything seems fine...but what happens if you get to the end of the list and current->data is still less than or equal to data?? Uh oh! current = current->link, current will now be NULL, so the next current->data will be trying to dereference a null pointer!
Just add a check for that in your loop condition and everything will be peachy:
while(current && current->data <= data) {
This expression will now short circuit if current is the null pointer, saving you from that issue.
Not sure if this is the only error but:
current=head;
node* trail=head;
while(current->data<=data) // <-- This doesn't check if current->link is NULL
{
trail=current;
current=current->link; /// <-- If current is NULL this would explode
}
trail->link=temp;
temp->link=current;

Deletion in a linked list

Qn) Given only a pointer to a node to be deleted in a singly linked list, how do
you delete it?
I am trying to delete the last element i.e., 1 but the else part goes into an infinite
loop printing garbage values.
Original link.
int main()
{
struct Node* head = NULL;
push(&head, 1);
push(&head, 4);
push(&head, 6);
push(&head, 8);
print(head);
del_p(head->next->next->next);
cout << endl;
print(head);
return 0;
}
void del_p(struct Node* current)
{
struct Node* temp;
if (current->next != NULL)
{
temp = current->next;
current->data = temp->data;
current->next = temp->next;
free(temp);
}
else
{
free(current);
current = NULL;
}
}
The else branch of your function tries to reassign current to NULL. This is problematic because current is a local copy of the pointer passed in. That is, you can't modify the value of the original pointer.
This is why you are receiving garbage, because you're accessing a node whose memory has already been deallocated.
You either need a double pointer, or preferably a reference to the node:
void del_p(struct Node*& current)
If you pass in the node to be deleted and the head node then you can loop until you find the node prior to the node to be deleted. You then need to point the prior node to the node that is pointed to by the node to be deleted and then you can free the node you want to delete.
void delete(struct Node* to_delete, struct Node* head)
{
// check if node to be deleted is the head
if (to_delete == head)
{
head = to_delete->next;
return;
}
// make a local copy of the head just in case as to not alter it
struct Node* tempHead = head;
while(tempHead->next != to_delete)
{
tempHead = tempHead->next;
}
tempHead->next = to_delete->next;
free(to_delete);
}
Just as a disclaimer I haven't tested this code, but conceptually it should work.
The typical algorithm for deleting a node on a linked list would follow the next steps:
Get a temp pointer started in Head.
Move your temp to the node you want to delete (in this case one before the last: temp->next == NULL).
Free the memory for temp2.
Set the pointer of temp->next to NULL.
Return the pointer to head.
Now this is not the only algorithm, there are a lot of ways you can accomplish this. The following code would be my solution to the function del_p (if you would want to delete the last node):
void del_p(struct Node *head)
{
if (head != NULL)
{
struct Node *temp = head;
while (temp->next != NULL) temp = temp->next;
free(temp);
}
}
You can make this code a little more general to make it possible to delete any Node, by passing a pointer to that node (or a value), the code would look as follows:
void del_p(struct Node **head, struct Node *delete_node)
{
if (head != NULL)
{
struct Node *temp = *head;
if (temp == delete_node)
{
*head = (*head)->next;
free(temp);
}
else
{
while (temp->next != NULL && temp->next != delete_node)
temp = temp->next;
if (temp->next != NULL && delete_node != NULL)
{
temp->next = delete_node->next;
free(delete_node);
}
}
}
}
Hope this works for you, this code isn't tested, but tell me if you have troubles!

Delete a value in a sorted Linked list

Hey I created a function that inserts inputed values into a sorted linked list, and now I'm trying to create another function to delete an entered value in a linked list. Currently I am getting an infinite loop of rick james and it is incredibly frustrating.
typedef int ListItemType; // global value in my header file
ListItemType item; // assigned in head file under ListNode struct
bool List::remove(const ListItemType& removedItem) {
ListNode *curr = head;
ListNode *prev = NULL;
//empty list
if(head == NULL){
cout<< "No items in the list";
}else{
//traverse the list
while(curr != NULL){
if(curr->item == removedItem){
break; //data has been found break loop
}else{
//increment loop
prev = curr;
curr = curr->next;
}
}//end while
//data has not been found
if(curr == NULL){
cout << "RICK JAMES";
}else{
//data has been found delete data
// case 1: delete at head node
if(head == curr){
head = head->next;
}else{
// case 2: delete after head
prev->next = curr->next;
}
delete curr;
size--;
return true;
}
}
return false;
}
the function logic looks ok to me...
If you're getting "RICK JAMES" all the time, it means it can not find the node to delete - may be something's wrong with the way you compare node's value with the function parameter...
function accepts
ListItemType& removedItem
which seems a little bit weird for int datatype, but I'm not sure how's the "item" field defined in ListNode... I would suggest to double check this. Good luck!

Finding a seg fault in recursive code for inorder successor

Hey guys I'm just practicing recursive code on a binary search tree. I'm getting a seg fault but I'm not sure where the problem is (probably something stupid staring me right in the face). I have other functions that are working fine like counting the number of nodes or counting the height of the tree. This function in particular is giving me trouble. I'm coding in c++.
//wrapper function
int table::in_order_successor()
{
node * temp;
temp = root;
in_order_successor(root, temp);
}
//Find the in-order successor
int table::in_order_successor(node * root, node * temp)
{
if(root == NULL) return 0;
if(root->right != NULL)
if(root->data == temp->data)
in_order_successor(root, temp->right);
in_order_successor(root, temp->left);
return temp->data;
}
The idea I had was to get the function to go right once from the root and then continue left as far as possible. To get it to go right once I want to only go right if my root->data is equal to my temp->data (the data is just a randomly generated int).
For Seg fault, you should check whether temp is null, as you code might pass temp->right and temp->left to it, which might be null.
if(temp == NULL) return 0; // add this check
But there is another problem in your code: you never reuse the return value. Then it will just iterate. Suppose you would like to return the data stored in the leaf node after your traversal, then the code could look like this:
//Find the in-order successor
int table::in_order_successor(node * root, node * temp) {
if(root == NULL) return 0;
if(temp == NULL) return 0; // add this check
if(root->right != NULL) {
// check by pointer instead of the data unless each
// node->data is unique. Otherwise unwanted moving
// right will occur.
if(root == temp) {
if (temp->right != null) {
// use `return` here instead of plain function call to get
// the update of the rest of the recursion.
return in_order_successor(root, temp->right);
}
}
}
if (temp->left != null) {
// if have left child, return what you will find in the next step
return in_order_successor(root, temp->left); // use return here
} else {
// reach the left-most leaf after first steping right at root node.
return temp->data;
}
}
Also
if(temp->left != NULL)
in_order_successor(root, temp->left);
and
if(!temp-> left)
return temp->data;