BST Delete Leaf Node

Hi all, i have problem with my code.
When i delete child node there isn't problem, but when i delete leaf node doesn't work, why???

Thanks all :)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
#include <iostream>
#include <cstdlib>
#include <string>
#include <vector>
using namespace std;

class tree_node
{
    private:
        tree_node *left;
		tree_node *right;
		tree_node *root;
		string data;

    public:
        tree_node()
        {
           root = NULL;
        }

        bool isEmpty() const { return root==NULL; }
        void print_inorder();
        void inorder(tree_node*);
        void print_preorder();
        void preorder(tree_node*);
        void print_postorder();
        void postorder(tree_node*);
        void insert(string);
        void remove(string);


};

// Il più piccolo elemento va a sinitra
// L'elemento più grande va a destra
void tree_node::insert(string d)
{
    tree_node* t = new tree_node;
    tree_node* parent;
    t->data = d;
    t->left = NULL;
    t->right = NULL;
    parent = NULL;

    // E' un nuovo nodo?
    if(isEmpty()) root = t;
    else
    {
        //Nota: tutti gli inserimenti avvengono come foglia
        tree_node* curr;
        curr = root;
        // Trova il genitore del nodo
        while(curr)
        {
            parent = curr;
            if(t->data > curr->data) curr = curr->right;
            else curr = curr->left;
        }

        if(t->data < parent->data)
           parent->left = t;
        else
           parent->right = t;
    }
}

void tree_node::remove(string d)
{
    //Localizza l'elemento
    bool found = false;
    if(isEmpty())
    {
        cout<<" Quest'albero è vuoto! "<<endl;
        return;
    }

    tree_node* curr;
    tree_node* parent;
    curr = root;

    while(curr != NULL)
    {
         if(curr->data == d)
         {
            found = true;
            break;
         }
         else
         {
             parent = curr;
             if(d>curr->data) curr = curr->right;
             else curr = curr->left;
         }
    }
    if(!found)
		 {
        cout<<" Campo non trovato! "<<endl;
        return;
    }


		 // 3 casi :
    // 1. Rimoviamo un nodo foglia
    // 2. Rimoviamo un nodo con un singolo figlio
    // 3. Rimoviamo un nodo con due figli

    // Nodo con singolo figlio
    if((curr->left == NULL && curr->right != NULL)|| (curr->left != NULL
&& curr->right == NULL))
    {
       if(curr->left == NULL && curr->right != NULL)
       {
           if(parent->left == curr)
           {
             parent->left = curr->right;
             delete curr;
           }
           else
           {
             parent->right = curr->right;
             delete curr;
           }
       }
       else // figlio sinistro presente mentre il destro no
       {
          if(parent->left == curr)
           {
             parent->left = curr->left;
             delete curr;
           }
           else
           {
             parent->right = curr->left;
             delete curr;
           }
       }
     return;
    }

		 //Cerchiamo un nodo foglia
		 if( curr->left == NULL && curr->right == NULL)
    {
        if(parent->left == curr) parent->left = NULL;
        else parent->right = NULL;
		 		 delete curr;
		 		 return;
    }


    //Nodo con 2 figli
    //Riposiziona il nodo con il più piccolo valore nel sotto-albero destro
    if (curr->left != NULL && curr->right != NULL)
    {
        tree_node* chkr;
        chkr = curr->right;
        if((chkr->left == NULL) && (chkr->right == NULL))
        {
            curr = chkr;
            delete chkr;
            curr->right = NULL;
        }
        else //figlio destro ha figli
        {
            //se il figlio del nodo destro ha figli
            //ci muoviamo verso sinistra per localizzare il più piccolo elemento

            if((curr->right)->left != NULL)
            {
                tree_node* lcurr;
                tree_node* lcurrp;
                lcurrp = curr->right;
                lcurr = (curr->right)->left;
                while(lcurr->left != NULL)
                {
                   lcurrp = lcurr;
                   lcurr = lcurr->left;
                }
		curr->data = lcurr->data;
                delete lcurr;
                lcurrp->left = NULL;
           }
           else
           {
               tree_node* tmp;
               tmp = curr->right;
               curr->data = tmp->data;
	       curr->right = tmp->right;
               delete tmp;
           }

        }
		 return;
    }

}

void tree_node::print_inorder()
{
  inorder(root);
}

void tree_node::inorder(tree_node* p)
{
    if(p != NULL)
    {
        if(p->left) inorder(p->left);
        cout<<" "<<p->data<<" ";
        if(p->right) inorder(p->right);
    }
    else return;
}

void tree_node::print_preorder()
{
    preorder(root);
}

void tree_node::preorder(tree_node* p)
{
    if(p != NULL)
    {
        cout<<" "<<p->data<<" ";
        if(p->left) preorder(p->left);
        if(p->right) preorder(p->right);
    }
    else return;
}

void tree_node::print_postorder()
{
    postorder(root);
}

void tree_node::postorder(tree_node* p)
{
    if(p != NULL)
    {
        if(p->left) postorder(p->left);
        if(p->right) postorder(p->right);
        cout<<" "<<p->data<<" ";
    }
    else return;
}

int main()
{
    tree_node b;
    int ch;
	string tmp,tmp1;
    while(1)
    {
       cout<<endl<<endl;
       cout<<" Operazioni su Alberi Binari Di Ricerca "<<endl;
       cout<<" ----------------------------- "<<endl;
       cout<<" 1. Inserimento "<<endl;
       cout<<" 2. In-Order  "<<endl;
       cout<<" 3. Pre-Order  "<<endl;
       cout<<" 4. Post-Order  "<<endl;
       cout<<" 5. Rimozione "<<endl;
       cout<<" 6. Exit "<<endl;
       cout<<" Inserisci la tua scelta : ";
       cin>>ch;
       switch(ch)
       {
           case 1 : cout<<" Inserisci la stringa : ";
                    cin>>tmp;
                    b.insert(tmp);
                    break;
           case 2 : cout<<endl;
                    cout<<" In-Order  "<<endl;
                    cout<<" -------------------"<<endl;
                    b.print_inorder();
                    break;
           case 3 : cout<<endl;
                    cout<<" Pre-Order  "<<endl;
                    cout<<" -------------------"<<endl;
                    b.print_preorder();
                    break;
           case 4 : cout<<endl;
                    cout<<" Post-Order  "<<endl;
                    cout<<" --------------------"<<endl;
                    b.print_postorder();
                    break;
           case 5 : cout<<" Scegli la stringa da cancellare : ";
                    cin>>tmp1;
                    b.remove(tmp1);
                    break;
           case 6 :
                    return 0;

       }
    }
}
Last edited on
It looks to me like the code to remove a leaf is at lines 141-146 and that code looks okay to me.

However, it does appear that the code will fail if you remove the root node.

The constructor at line 16 sets root, but not left or right. Although your code always sets them, it's bad form to allow for the possibility of having them uninitialized. It would be handy to have a constructor that takes a string:
1
2
3
tree_node::tree_node(const string &s) :
    data(s), root(NULL), left(NULL), right(NULL)
    {;}

It's a little harder to understand, but the code can be greatly simplified if you use a pointer to the pointer to the current node. For example, the insert method can look like this (using the new constructor too):
1
2
3
4
5
6
7
8
9
10
11
12
13
void tree_node::insert(string d)
{
    tree_node* t = new tree_node(d)
    tree_node **ptr;
    tree_node *curr;

    for (ptr = &root; *ptr;) {
        curr = *ptr;
        if(t->data > curr->data) ptr = &curr->right;
        else ptr = &curr->left;
    }
    *ptr = t;
}

Note that ptr points to one of 3 possibilities: the root pointer, a left pointer or a right pointer. The assignment at line 12 thus changes the right pointer in all 3 cases.
Topic archived. No new replies allowed.