C++ deleting minimum element in binary tree - c++

Can anyone explain to me why the delete_min() function does not work? I have been trying to figure this out for hours now.
I have tried different variations of the function, but it seems to either delete the wrong thing, only alter data and not delete it, or delete the wrong thing. Also, the insertion function doesn't always work properly after delete_min() is called, so I'm sure this has something to do with pointers.
Here is the function:
int BinaryTree::delete_min_helper(TreeNode *node){
while(node->left != NULL){
node = node->left;
}
if(node == root){
puts("attempted to delete root");
return 1;
}
delete node;
node = NULL;
return 0;
}
And here is a compilable example:
#ifndef _TREE_H_
#define _TREE_H_
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
struct TreeNode {
int val;
char *str;
TreeNode *left;
TreeNode *right;
};
class BinaryTree {
public:
BinaryTree();
~BinaryTree();
int insert_node(unsigned int val, char *str);
TreeNode *find_min();
int delete_min();
void print();
private:
int insert_node_helper(TreeNode *&node, unsigned int val, char *str);
int delete_min_helper(TreeNode *node);
void print_helper(TreeNode *node);
TreeNode *root;
};
#endif
BinaryTree::BinaryTree(){
this->root = NULL;
}
BinaryTree::~BinaryTree(){
}
int BinaryTree::insert_node(unsigned int val, char *str){
return insert_node_helper(this->root, val, str);
}
int BinaryTree::insert_node_helper(TreeNode *&node, unsigned int val, char *str){
if(node == NULL){
node = new TreeNode;
node->val = val;
node->str = strdup(str);
node->left = NULL;
node->right = NULL;
if(node != NULL){
return 0;
}else{
puts("inserted null node");
return 1;
}
}else if(val <= node->val){
return insert_node_helper(node->left, val, str);
}else if(val > node->val){
return insert_node_helper(node->right, val, str);
}
return 1;
}
void BinaryTree::print(){
print_helper(this->root);
}
void BinaryTree::print_helper(TreeNode *node){
if(node != NULL){
print_helper(node->right);
printf("%d occurrences of \"%s\"\n", node->val, node->str);
print_helper(node->left);
}
}
TreeNode *BinaryTree::find_min(){
TreeNode *temp = this->root;
while(temp->left != NULL){
temp = temp->left;
}
return temp;
}
int BinaryTree::delete_min(){
return delete_min_helper(root);
}
int BinaryTree::delete_min_helper(TreeNode *node){
while(node->left != NULL){
node = node->left;
}
if(node == root){
puts("attempted to delete root");
return 1;
}
delete node;
node = NULL;
return 0;
}
#include <time.h>
int main(){
BinaryTree bt;
srand(time(NULL));
for(int i = 0; i < 10; i++){
bt.insert_node(rand() % 20, "test");
}
bt.print();
printf("min val = %d\n", bt.find_min()->val);
puts("#################################");
bt.delete_min();
bt.print();
printf("min val = %d\n", bt.find_min()->val);
return 0;
}

Two things come to mind right away:
a parent node is still pointing at the node which you deleted
the node you're deleting might have a node->right pointer hanging off of it, which you are lopping off the tree, instead of re-hooking it back into the tree.
There might be more problems, but you need to address these issues at a bare minimum.

Reference from his parent still point to some address in memory.
Try this:
int BinaryTree::delete_min_helper(TreeNode *node){
TreeNode *prev = NULL;
while(node->left != NULL){
prev = node;
node = node->left;
}
if(node == root){
puts("attempted to delete root");
return 1;
}
prev->left = NULL;
delete node;
node = NULL;
return 0;
}

Related

Linked List delete operation not working in visual studio using C

when I tried to implement a linked list in visual studio 2019 using c it produces heap error.
It was due to the free function.
However, the code works fine on online compilers which use the GCC compiler. https://www.jdoodle.com/c-online-compiler/
I can't able to figure it out..........................
here is the code:
#include <stdio.h>
#include <stdlib.h>
struct Node
{
int data;
struct Node* next;
};
struct Node* head = NULL;
void append(int data)
{
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node*));
(*newNode).data = data;
(*newNode).next = NULL;
if (head == NULL)
{
head = newNode;
return;
}
struct Node* temp = head;
while (temp->next != NULL)
{
temp = temp->next;
}
temp->next = newNode;
}
void insertAt(int position, int data)
{
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node*));
newNode->data = data;
newNode->next = NULL;
if (position == 1)
{
newNode->next = head;
head = newNode;
return;
}
struct Node* temp = head;
for (int i = 1; i < position - 1; i++)
{
temp = temp->next;
}
newNode->next = temp->next;
temp->next = newNode;
}
void deleteAt(int position)
{
struct Node* temp = NULL;
if (position == 1)
{
temp = head;
head = temp->next;
free(temp);
return;
}
struct Node* tempHead = head;
for (int i = 1; i < position - 1; i++)
{
tempHead = tempHead->next;
}
temp = tempHead->next;
tempHead->next = temp->next;
free(temp);
}
void print()
{
struct Node* temp = head;
while (temp != NULL)
{
printf("%d\n", temp->data);
temp = temp->next;
}
}
void main()
{
append(3);
append(4);
append(5);
append(6);
insertAt(3, 20);
insertAt(4, 50);
insertAt(2, 70);
deleteAt(4);
deleteAt(3);
print();
}
The sizes you're passing to malloc are wrong. You should pass sizeof(struct Node).
If you're compiling this as C++ you shouldn't be using malloc at all.
As #1201ProgramAlarm answered, the allocation size is wrong. sizeof(struct Node*) is the size of a pointer, not the size of the struct.
Instead of trying to match the type, use the size of the referenced data. Easy to code right, review and maintian.
Cast not needed in C.
// struct Node* newNode = (struct Node*)malloc(sizeof(struct Node*));
// instead...
// ptr = malloc(sizeof *ptr * N);
struct Node* newNode = malloc(sizeof *newNode);
Just try this code once down there .This code is written by me according to my understanding and still if u have any issue with the code you can further ask me .You can try this code out or just cross check it with your's.
Code:
Linked List:
#include <stdio.h>
#include <stdlib.h>
struct Node
{
int data;
struct Node *next;
}*first=NULL;
void create(int A[],int n)
{
int i;
struct Node *t,*last;
first=(struct Node *)malloc(sizeof(struct Node));
first->data=A[0];
first->next=NULL;
last=first;
for(i=1;i<n;i++)
{
t=(struct Node*)malloc(sizeof(struct Node));
t->data=A[i];
t->next=NULL;
last->next=t;
last=t;
}
}
void Display(struct Node *p)
{
while(p!=NULL)
{
printf("%d ",p->data);
p=p->next;
}
}
void RDisplay(struct Node *p)
{
if(p!=NULL)
{
RDisplay(p->next);
printf("%d ",p->data);
}
}
int Delete(struct Node *p,int index)
{
struct Node *q=NULL;
int x=-1,i;
if(index < 1 || index > count(p))
return -1;
if(index==1)
{
q=first;
x=first->data;
first=first->next;
free(q);
return x;
}
else
{
for(i=0;i<index-1;i++)
{
q=p;
p=p->next;
}
q->next=p->next;
x=p->data;
free(p);
return x;
}
}
int main()
{
int A[]={10,20,30,40,50};
create(A,5);
printf(“%d\n",Delete(first),2);
Display(first);
return 0;
}
In main function you can pass the function created int the program and also pass the argument according to you.

Slow Inserts Linked List multi-threading needed?

In the code bellow, I'm searching for ways to optimize the speed of insertions when dealing with Millions of inserts at the time. the code runs fine but is very slow when performing large amounts of inserts. I already tried some ideas but is always slow. I guess the solution is to use Multi-threading to perform the inserts, and use a global variable "truct Node* nodeObj".
I have very few/no experience with Multi-threading and Synchronization in C, C++, If you could give me an example based on the code bellow I would be very appreciated.
Any additional Ideas are welcome.
The rules are:
1- In the end (after insert all numbers) the linked list must be ordered, meaning that each Node->data starts at lowest number up to the Largest number.
2 - The caller is using a for loop, this for loop cannot be started inside the Insert function.
3 - Any of the code, caller or insert function can be optimized as long as the insert function does not automatically add inserts by it self, that's the caller s job.
#include<stdio.h>
#include<stdlib.h>
#include<conio.h>
struct Node {
int data;
struct Node* nextAddr;
};
struct Node* Insert(Node* p, int data);
void Print(struct Node* p);
void RevPrint(struct Node* p);
int main() {
struct Node* nodeObj = NULL;
printf("---------------------------------\n"
"Insert()\n---------------------------------\n");
for (int i = 1; i < 1000000; i++) {
nodeObj = Insert(nodeObj, i);
printf(" %d", i);
}
printf("\n---------------------------------\n"
"Print()\n---------------------------------\n");
Print(nodeObj);
printf("---------------------------------\n"
"RevPrint()\n---------------------------------");
RevPrint(nodeObj);
printf("\nPress any key to continue...");
_getch();
}
struct Node* Insert(Node* _pToNode, int _nbr)
{
Node *newValue = (struct Node*)malloc(sizeof(struct Node));
newValue->data = _nbr;
newValue->nextAddr = NULL;
if (_pToNode == NULL) _pToNode = newValue;
else {
Node* pLocal = _pToNode;
while (pLocal->nextAddr != NULL) {
pLocal = pLocal->nextAddr;
}
pLocal->nextAddr = newValue;
}
return _pToNode;
}
void Print(struct Node* p) {
if (p == NULL) {
printf("\n");
return;
}
printf(" %d", p->data);
Print(p->nextAddr);
}
void RevPrint(struct Node* p) {
if (p == NULL) {
printf("\n");
return;
}
RevPrint(p->nextAddr);
printf(" %d", p->data);
}
Thank you.
Linked lists are unwelcome on modern machines. The L1 and L2 caches love vectors and arrays. They utterly despise linked lists. Use a std::vector, not a linked list, (and certainly not a hand-rolled linked list). Try to .reserve() enough memory in the vector to accommodate all the new stuff. Just push everything onto the back of the vector, and then sort the vector using parallel execution. C++17 can do that painlessly. std::stable_sort parallels quite nicely.
Caveat: This works only for tail insertion/append:
int
main()
{
struct Node* nodeObj = NULL;
struct Node* nodeTail = NULL;
// your other stuff ...
for (int i = 1; i < 1000000; i++) {
nodeObj = Insert(nodeObj, &nodeTail, i);
printf(" %d", i);
}
// your other stuff ...
}
struct Node* Insert(Node* _pToNode, Node **tail,int _nbr)
{
Node *newValue = (struct Node*)malloc(sizeof(struct Node));
newValue->data = _nbr;
newValue->nextAddr = NULL;
if (_pToNode == NULL) {
_pToNode = newValue;
}
else {
(*tail)->nextAddr = newValue;
}
*tail = newValue;
return _pToNode;
}
You could clean this up with a "list" struct that has both the head and tail in it (vs. the separate args)
UPDATE:
Very cool/smart, but unfortunately is still slow...
malloc et. al. can be slow for a large number of small allocations. One way to speed things up is to use a subpool of allocations [as WeatherVane suggested].
As I mentioned, adding a "list" struct can make things tidier and I used it in two places. Once you commit to that, you can add other things besides head/tail, such as count. Also, it makes it easier to convert from a singly-linked list to a doubly-linked in the future, if you so choose.
Side note: With a doubly-linked list, insertions are [slightly] more complex, but insertions in the middle of the list are much faster because you don't have to traverse the list to find the previous pointer (e.g. the node would have a prev pointer in it). Also, RevPrintList would become as simple as PrintList.
Note that [on my system], the reverse print ran out of stack space [and segfaulted], so I recoded the print functions to not be recursive.
Here's a cleaned up version that should do the insertions faster because of the reduced number of individual malloc calls.
Side note: I didn't add the requisite checks for malloc, etc. returning null.
#include <stdio.h>
#include <stdlib.h>
//#include <conio.h>
typedef struct Node_ {
int data;
struct Node_* next;
} Node;
typedef struct List_ {
int count;
Node* head;
Node* tail;
} List;
Node* NewNode(void);
Node* Insert(List* p, int data);
void Print(Node* p);
void PrintList(List *list);
void RevPrint(Node* p);
void RevPrintList(List *list);
List freelist;
int
main()
{
List nodelist = { 0, NULL, NULL };
printf("---------------------------------\n"
"Insert()\n---------------------------------\n");
for (int i = 1; i < 1000000; i++) {
Insert(&nodelist, i);
#if 0
printf(" %d", i);
#endif
}
printf("\n---------------------------------\n"
"Print()\n---------------------------------\n");
#if 0
Print(nodelist.head);
#else
PrintList(&nodelist);
#endif
printf("---------------------------------\n"
"RevPrint()\n---------------------------------");
#if 0
RevPrint(nodelist.head);
#else
RevPrintList(&nodelist);
#endif
printf("\nPress any key to continue...");
#if 0
_getch();
#else
getchar();
#endif
}
Node*
NewNode(void)
{
Node *node;
// NOTE: adjust the count setup (e.g. 1000) to what ever value you want
if (freelist.count <= 0) {
freelist.count = 1000;
freelist.head = calloc(freelist.count,sizeof(Node));
}
node = freelist.head++;
freelist.count -= 1;
return node;
}
Node*
Insert(List* list,int _nbr)
{
Node *node = NewNode();
node->data = _nbr;
node->next = NULL;
if (list->head == NULL) {
list->head = node;
}
else {
list->tail->next = node;
}
list->tail = node;
list->count += 1;
return node;
}
void
Print(Node* p)
{
if (p == NULL) {
printf("\n");
return;
}
printf(" %d", p->data);
Print(p->next);
}
void
PrintList(List* list)
{
Node *node;
for (node = list->head; node != NULL; node = node->next)
printf(" %d", node->data);
printf("\n");
}
void
RevPrint(Node* p)
{
if (p == NULL) {
printf("\n");
return;
}
RevPrint(p->next);
printf(" %d", p->data);
}
void
RevPrintList(List *list)
{
Node **rlist = malloc(sizeof(Node**) * list->count);
Node *node;
int ridx;
ridx = list->count - 1;
for (node = list->head; node != NULL; node = node->next, --ridx)
rlist[ridx] = node;
for (ridx = 0; ridx < list->count; ++ridx) {
node = rlist[ridx];
printf(" %d",node->data);
}
printf("\n");
free(rlist);
}
UPDATE #2:
you could make freeList a list of lists (using a different "node" struct which would have a pointer to list instead of a number), so that memory could be released when the program is done.
Here is a modified version that does that:
#include <stdio.h>
#include <stdlib.h>
//#include <conio.h>
typedef struct Node_ {
int data;
struct Node_* next;
} Node;
typedef struct List_ {
int count;
Node* head;
Node* tail;
} List;
typedef struct Freelist_ {
int count;
Node* head;
Node* tail;
Node* avail;
} FreeList;
Node* NewNode(void);
Node* Insert(List* p, int data);
void Print(Node* p);
void PrintList(List *list);
void RevPrint(Node* p);
void RevPrintList(List *list);
void FreeAll(void);
FreeList freelist = { 0 };
int
main()
{
List nodelist = { 0, NULL, NULL };
printf("---------------------------------\n"
"Insert()\n---------------------------------\n");
for (int i = 1; i < 1000000; i++) {
Insert(&nodelist, i);
// this printf will radically slow things down
#if 0
printf(" %d", i);
#endif
}
printf("\n---------------------------------\n"
"Print()\n---------------------------------\n");
#if 0
Print(nodelist.head);
#else
PrintList(&nodelist);
#endif
printf("---------------------------------\n"
"RevPrint()\n---------------------------------");
#if 0
RevPrint(nodelist.head);
#else
RevPrintList(&nodelist);
#endif
// release all nodes back to the malloc free pool
FreeAll();
printf("\nPress any key to continue...");
#if 0
_getch();
#else
getchar();
#endif
}
Node*
NewNode(void)
{
Node *node;
// NOTE: adjust the count setup (e.g. 1000) to what ever value you want
if (freelist.count <= 0) {
freelist.count = 1000;
node = calloc(freelist.count,sizeof(Node));
// maintain linked list of nodes that are at the _start_ of a
// malloc area/arena
if (freelist.head == NULL)
freelist.head = node;
else
freelist.tail->next = node;
freelist.tail = node;
// burn the first node as a placeholder
freelist.avail = node + 1;
freelist.count -= 1;
}
node = freelist.avail++;
freelist.count -= 1;
return node;
}
void
FreeAll(void)
{
Node* node;
Node* next;
for (node = freelist.head; node != NULL; node = next) {
next = node->next;
free(node);
}
}
Node*
Insert(List* list,int _nbr)
{
Node *node = NewNode();
node->data = _nbr;
node->next = NULL;
if (list->head == NULL) {
list->head = node;
}
else {
list->tail->next = node;
}
list->tail = node;
list->count += 1;
return node;
}
void
Print(Node* p)
{
if (p == NULL) {
printf("\n");
return;
}
printf(" %d", p->data);
Print(p->next);
}
void
PrintList(List* list)
{
Node *node;
for (node = list->head; node != NULL; node = node->next)
printf(" %d", node->data);
printf("\n");
}
void
RevPrint(Node* p)
{
if (p == NULL) {
printf("\n");
return;
}
RevPrint(p->next);
printf(" %d", p->data);
}
void
RevPrintList(List *list)
{
Node **rlist = malloc(sizeof(Node**) * (list->count + 1));
Node *node;
int ridx;
ridx = list->count - 1;
for (node = list->head; node != NULL; node = node->next, --ridx)
rlist[ridx] = node;
for (ridx = 0; ridx < list->count; ++ridx) {
node = rlist[ridx];
printf(" %d",node->data);
}
printf("\n");
free(rlist);
}
UPDATE #3:
Here's a version that adds reuse of nodes by adding a reuse member to FreeList and a FreeOne function that can be called when a node is deleted.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//#include <conio.h>
typedef struct Node_ {
int data;
struct Node_ *next;
} Node;
typedef struct List_ {
int count;
Node *head;
Node *tail;
} List;
typedef struct Freelist_ {
int count;
Node *head;
Node *tail;
Node *avail;
Node *reuse;
} FreeList;
Node *NewNode(void);
Node *Insert(List *p,int data);
void Print(Node *p);
void PrintList(List *list);
void RevPrint(Node *p);
void RevPrintList(List *list);
void FreeOne(Node *p);
void FreeAll(void);
FreeList freelist = { 0 };
int
main()
{
List nodelist = { 0, NULL, NULL };
printf("---------------------------------\n" "Insert()\n---------------------------------\n");
for (int i = 1; i < 1000000; i++) {
Insert(&nodelist,i);
// this printf will radically slow things down
#if 0
printf(" %d",i);
#endif
}
printf("\n---------------------------------\n" "Print()\n---------------------------------\n");
#if 0
Print(nodelist.head);
#else
PrintList(&nodelist);
#endif
printf("---------------------------------\n" "RevPrint()\n---------------------------------");
#if 0
RevPrint(nodelist.head);
#else
RevPrintList(&nodelist);
#endif
// release all nodes back to the malloc free pool
FreeAll();
printf("\nPress any key to continue...");
#if 0
_getch();
#else
getchar();
#endif
}
Node *
NewNode(void)
{
FreeList *list;
Node *node;
list = &freelist;
do {
// try to reuse a node that has been released by FreeOne
node = list->reuse;
if (node != NULL) {
list->reuse = node->next;
node->next = NULL;
break;
}
// NOTE: adjust the count setup (e.g. 1000) to what ever value you want
if (list->count <= 0) {
list->count = 1000;
node = calloc(list->count,sizeof(Node));
// maintain linked list of nodes that are at the _start_ of a
// malloc area/arena
if (list->head == NULL)
list->head = node;
else
list->tail->next = node;
list->tail = node;
// burn the first node as a placeholder
list->avail = node + 1;
list->count -= 1;
}
// grab one from the current allocation array
node = list->avail++;
list->count -= 1;
} while (0);
return node;
}
void
FreeOne(Node *node)
{
FreeList *list;
list = &freelist;
// push this node onto the front of the reuse list (i.e. it's fast)
node->next = list->reuse;
list->reuse = node;
}
void
FreeAll(void)
{
Node *node;
Node *next;
for (node = freelist.head; node != NULL; node = next) {
next = node->next;
free(node);
}
memset(&freelist,0,sizeof(FreeList));
}
Node *
Insert(List *list,int _nbr)
{
Node *node = NewNode();
node->data = _nbr;
node->next = NULL;
if (list->head == NULL) {
list->head = node;
}
else {
list->tail->next = node;
}
list->tail = node;
list->count += 1;
return node;
}
void
Print(Node *p)
{
if (p == NULL) {
printf("\n");
return;
}
printf(" %d",p->data);
Print(p->next);
}
void
PrintList(List *list)
{
Node *node;
for (node = list->head; node != NULL; node = node->next)
printf(" %d",node->data);
printf("\n");
}
void
RevPrint(Node *p)
{
if (p == NULL) {
printf("\n");
return;
}
RevPrint(p->next);
printf(" %d",p->data);
}
void
RevPrintList(List *list)
{
Node **rlist = malloc(sizeof(Node **) * (list->count + 1));
Node *node;
int ridx;
ridx = list->count - 1;
for (node = list->head; node != NULL; node = node->next, --ridx)
rlist[ridx] = node;
for (ridx = 0; ridx < list->count; ++ridx) {
node = rlist[ridx];
printf(" %d",node->data);
}
printf("\n");
free(rlist);
}
I assume that the order of the elements that you mention is ordered by comparison. I.e. A < B => A is before B in the container.
If that assumption holds the best you can hope for is a log(N) insertion of each element. So if you want to insert an element among those millions of elements you should expect to do about 20+ comparisons. If the millions you want to insert have an order you can do better.
Now, a pointer based structure is never the answer to a fast data structure.
std::vector should be your go to.
To read this fast-insertion structure with a for statement you'd need a very peculiar iterator or you need to rearrange the inserted stuff in to another vector.
In conclusion, you want to insert stuff into a simple binary heap.
Multithreading would not make this faster unless you can devise a merge like scheme to your inserts.

C++ program implementing tree stops working when a node is inserted and I can't understand why

here is my code. after reading T the program reads the first input data and stops working. message "Unhandled exception at 0x00844D30 in tree.exe: 0xC0000005: Access violation reading location 0x00000000." is shown. I included iostream and stddef.h libraries.
class Node{
public:
int data;
Node *left, *right;
Node(int d){
data = d;
left = right = NULL;
}
};
class Solution{
public:
Node* insert(Node* root, int data){
if (root = NULL){
return new Node(data);
}
else{
Node* cur;
if (data <= root->data){
cur = insert(root->left, data);
root->left = cur;
}
else{
cur = insert(root->right, data);
root->right = cur;
}
return root;
}
}
};
int main(){
Solution myTree;
Node* root = NULL;
int T, data;
cin >> T;
while (T-->0){
cin >> data;
root = myTree.insert(root, data);
}
return 0;
}
This if will always go into the else part. Because you assign NULL to the variable root and then check the value. It should be root == NULL
if (root = NULL){
return new Node(data);
}
else{
Node* cur;
if (data <= root->data){
cur = insert(root->left, data);
root->left = cur;
}
else{
cur = insert(root->right, data);
root->right = cur;
}
return root;
}
The condition should be
if (root==NULL)
#include <iostream>
#include <stddef.h>
using namespace std;
class Node{
public:
int data;
Node *left, *right;
Node(int d){
data = d;
left = right = NULL;
}
};
class Solution{
public:
Node* insert(Node* root, int data){
if(root == NULL){
return new Node(data);
}
else{
Node* cur;
if (data <= root->data){
cur = insert(root->left, data);
root->left = cur;
}
else{
cur = insert(root->right, data);
root->right = cur;
}
cur->left=cur->right=NULL;
return root;
}
}
};
int main(){
Solution myTree;
Node* root = NULL;
int T, data;
cin>>T;
while (T-->0){
cin>>data;
root = myTree.insert(root, data);
}
return 0;
}

I'm having trouble with cpp code to insert elements in a binary tree

I've tried this way to insert elements in a binary tree in code blocks. The program got compiled but got a run time error and the program stopped running. Could some one please help me out in this issue.
Thanks in advance.
#include <iostream>
#include <cstdlib>
using namespace std;
class bst;
class node
{
public:
int data;
node *lc;
node *rc;
};
class bst
{
public:
node *root;
bst()
{
root = NULL;
}
void search(int, node **, node **);
void insert(int);
void display(node *, int);
};
void bst::search(int item, node **par, node **loc)
{
node *current;
node *ptr;
if(root == NULL)
{
*par = NULL;
*loc = NULL;
return;
}
if(item == root->data)
{
*par = NULL;
*loc = root;
return;
}
if(item < root->data)
current = root->lc;
else
current = root->rc;
ptr = root;
while(current != NULL)
{
if(item == current->data)
{
*par = ptr;
*loc = current;
return;
}
ptr = current;
if(item < current->data)
current = current->lc;
else
current = current->rc;
}
*par = current;
*loc = NULL;
}
void bst::insert(int item)
{
node *parent;
node *location;
node *temp;
search(item, &parent, &location);
temp = new node;
temp->data = item;
temp->lc = NULL;
temp->rc = NULL;
if(item < parent->data)
parent->lc = temp;
else
parent->rc = temp;
}
void bst::display(node *ptr, int level)
{
if(ptr != NULL)
{
display(ptr->rc, level+1);
cout<<"\n";
for(int i=0;i<level;i++)
cout<<" ";
cout<<ptr->data;
display(ptr->lc, level+1);
}
}
int main()
{
int ch, num;
bst b;
while(1)
{
cout<<"1. INSERT ; 2. DISPLAY ; 3. EXIT "<<endl;
cout<<"Enter your choice"<<endl;
cin>>ch;
switch(ch)
{
case 1: cout<<"Enter the number to insert"<<endl;
cin>>num;
b.insert(num);
break;
case 2: b.display(b.root, 1);
break;
case 3: exit(0);
}
}
return 0;
}
In this line search(item, &parent, &location); you are calling the function search with arguments of types int, node** and node**. It in fact expects int, node* and node*. You should change the function declaration to search(int, node**, node**).

C++ delete min element in binary tree

I have the following function for deleting the min element:
int BinaryTree::delete_min_helper(TreeNode *node){
while(node->left != NULL){
node = node->left;
}
if(node == root){
return 1;
}
delete node;
node = NULL;
return 0;
}
I always pass a pointer to the root node to this function. I've tried this and a few variations of it, but it always seems to delete the the wrong thing or not delete anything at all. Any ideas why?
Here is a compilable example:
#ifndef _TREE_H_
#define _TREE_H_
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
struct TreeNode {
int val;
char *str;
TreeNode *left;
TreeNode *right;
};
class BinaryTree {
public:
BinaryTree();
~BinaryTree();
int insert_node(unsigned int val, char *str);
TreeNode *find_min();
int delete_min();
void print();
private:
int insert_node_helper(TreeNode *&node, unsigned int val, char *str);
int delete_min_helper(TreeNode *node);
void print_helper(TreeNode *node);
TreeNode *root;
};
#endif
BinaryTree::BinaryTree(){
this->root = NULL;
}
BinaryTree::~BinaryTree(){
}
int BinaryTree::insert_node(unsigned int val, char *str){
return insert_node_helper(this->root, val, str);
}
int BinaryTree::insert_node_helper(TreeNode *&node, unsigned int val, char *str){
if(node == NULL){
node = new TreeNode;
node->val = val;
node->str = strdup(str);
node->left = NULL;
node->right = NULL;
if(node != NULL){
return 0;
}else{
puts("inserted null node");
return 1;
}
}else if(val <= node->val){
return insert_node_helper(node->left, val, str);
}else if(val > node->val){
return insert_node_helper(node->right, val, str);
}
return 1;
}
void BinaryTree::print(){
print_helper(this->root);
}
void BinaryTree::print_helper(TreeNode *node){
if(node != NULL){
print_helper(node->right);
printf("%d occurrences of \"%s\"\n", node->val, node->str);
print_helper(node->left);
}
}
TreeNode *BinaryTree::find_min(){
TreeNode *temp = this->root;
while(temp->left != NULL){
temp = temp->left;
}
return temp;
}
int BinaryTree::delete_min(){
return delete_min_helper(root);
}
int BinaryTree::delete_min_helper(TreeNode *node){
while(node->left != NULL){
node = node->left;
}
if(node == root){
puts("attempted to delete root");
return 1;
}
delete node;
node = NULL;
return 0;
}
#include <time.h>
int main(){
BinaryTree bt;
srand(time(NULL));
for(int i = 0; i < 10; i++){
bt.insert_node(rand() % 20, "test");
}
bt.print();
printf("min val = %d\n", bt.find_min()->val);
puts("#################################");
bt.delete_min();
bt.print();
printf("min val = %d\n", bt.find_min()->val);
return 0;
}
You are taking a reference to a pointer as argument (TreeNode *&node), and then modify it. So if you pass the root of your tree to this method, you will eventually set the root to NULL.
Additionally this actually deletes absolutely nothing, because you call delete after setting the pointer to NULL, and delete called on a null-pointer does nothing.
Update after edit of original post:
I assume root is a member of BinaryTree. It would be easier to help you if you posted a Short, Self Contained, Compilable Example.
You're still taking root as a reference. Thus node == root will always be true, and you'll never reach your delete statement. So actually you're not deleting anything, but you're changing your root to be the left-most child node.
Try changing your method signature to
int BinaryTree::delete_min_helper(TreeNode *node){
that is, without the ampersand (&).
After edit:
Ok, now I've run your program, and found your second problem. In the line
node = NULL;
You're changing the value of a local pointer, not of the left-pointer in the parent node. This means than when you traverse the tree the next time, you will access a pointer to the memory you just deleted. That triggers undefined behaviour. To get around this you should set the left-pointer of your parent node to 0 when you delete your leaf-node.