Dev - C++ - Problemas con el Borrado de datos en Arboles Binarios

 
Vista:
sin imagen de perfil
Val: 20
Ha disminuido 1 puesto en Dev - C++ (en relación al último mes)
Gráfica de Dev - C++

Problemas con el Borrado de datos en Arboles Binarios

Publicado por Nahuel (6 intervenciones) el 10/08/2020 02:35:57
El problema estaría en las funciones finales(EncontrarBorrado y TipoDeBorrado) o eso supongo. Creo que el problema vendría siendo la simplicidad del código de dichas funciones y, en consecuencia, un problema mio para visualizar los posibles casos "especiales" que tiran un error.

Si alguien me echa una mano estaría muy agradecido, pues esta es la primera vez que escribo en un foro, añadiendo el echo de que este es el primer lenguaje de programación que aprendo.

Que tengas un buen día.

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
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
#include<iostream>
#include<stdlib.h>
using namespace std;
 
struct nodo{
	int dato;
	nodo *padre;
	nodo *izq;
	nodo *der;
}*arbol = NULL;
 
void m();
 
//creacion de datos
nodo *crear_nodo(int&,nodo *&);//creamos un nodo vacio
void insertar(nodo *&,int&,nodo *);//insertamos el nodo a la lista
 
//opciones varias
void mostrarArbol(nodo *&,int);//mostramos el arbol
void BuscarNodo(nodo *&, int&,int&);//buscamos un dato dentro del arbol
 
//funciones de borrado de nodos
void EncontrarBorrado(nodo *,int,int&);//encontramos el dato a borrar y lo señalamos con una bandera
void TipoDeBorrado(nodo *);//decidimos como lo borraremos dependiendo de cuantos hijos tenga
 
//recorrido en Profundidad
void PreOrden(nodo *&);//mostramos en preorden
void InOrden(nodo *&);//mostramos en inorden
void PostOrden(nodo *&);//mostramos en postorden
 
int main(){
 
	m();
 
	system("PAUSE");
	return 0;
}
 
//MENU
void m(){
	int n,c,cont = 0,s;
 
	while(s != 8){
		cout<<"----MENU----"<<endl;
		cout<<"Aprieta 1 para agregar elementos al Arbol."<<endl;
		cout<<"Aprieta 2 para mostrar el Arbol."<<endl;
		cout<<"Aprieta 3 para buscar un elemento."<<endl;
		cout<<"Aprieta 4 para Mostrar el Arbol en PreOrden."<<endl;
		cout<<"Aprieta 5 para Mostrar el Arbol en InOrden."<<endl;
		cout<<"Aprieta 6 para Mostrar el Arbol en PostOrden."<<endl;
		cout<<"Aprieta 7 para eliminar un dato del Arbol."<<endl;
		cout<<"Aprieta 8 para salir."<<endl;
		cout<<"Opcion elegida: "; cin>>s;
		system("cls");
 
	switch(s){
		case 1:
 
			cout<<"Dame la cantidad de elementos que deseas ingresar al arbol: "; cin>>c;
 
			for(int i = 1;i<=c;i++){
				cout<<i<<". Dame un numero: "; cin>>n;
				insertar(arbol,n,NULL);
			}
			system("cls");
			break;
 
		case 2:
			cout<<"---------------------------------------"<<endl;
			if(arbol == NULL){
			cout<<"---Arbol Vacio---"<<endl<<endl;
			}
			else{
				mostrarArbol(arbol,cont);
			}
			cout<<"---------------------------------------"<<endl;
			break;
 
		case 3:
			if(arbol == NULL){
				cout<<"---Arbol Vacio---"<<endl<<endl;
			}
			else{
				cout<<"Dame el Dato que deseas Buscar: "; cin>>n;
				system("cls");
 
				if(n == arbol->dato){
					cout<<" El elemento "<<n<<" Es la Raiz del Arbol."<<endl<<endl;
				}
				else{
					BuscarNodo(arbol,n,cont);
 
					if(cont != 1){
 
						system("cls");
						cout<<"---No Existe el Dato "<<n<<" Dentro del Arbol.---"<<endl<<endl;
					}
 
					cont = 0;
				}
 
 
 
			}
			break;
 
		case 4:
			if(arbol == NULL){
				cout<<"---Arbol Vacio---"<<endl<<endl;
			}
			else{
			cout<<"-------"<<endl;
			cout<<" | ";
			PreOrden(arbol);
			cout<<endl<<"-------"<<endl<<endl;
			}
			break;
 
		case 5:
			if(arbol == NULL){
				cout<<"---Arbol Vacio---"<<endl<<endl;
			}
			else{
			cout<<"-------"<<endl;
			cout<<" | ";
			InOrden(arbol);
			cout<<endl<<"-------"<<endl<<endl;
			}
			break;
 
		case 6:
			if(arbol == NULL){
				cout<<"---Arbol Vacio---"<<endl<<endl;
			}
			else{
			cout<<"-------"<<endl;
			cout<<" | ";
			PostOrden(arbol);
			cout<<endl<<"-------"<<endl<<endl;
			}
			break;
 
		case 7:
			if(arbol == NULL){
				cout<<"---Arbol Vacio---"<<endl<<endl;
			}
			else{
				cout<<"Dame el dato que deseas eliminar: "; cin>>n;
				system("cls");
 
				EncontrarBorrado(arbol,n,cont);
				if(cont != 1){
					cout<<"---No Existe el Dato "<<n<<" Dentro del Arbol.---"<<endl<<endl;
				}
				else{
				cout<<"---Elemento "<<n<<" eliminado correctamente---"<<endl<<endl;
				}
				cont = 0;
			}
 
 
			break;
 
		case 8:
			cout<<"---Saliendo del Programa---"<<endl<<endl;
			break;
 
		default:
			cout<<"---Opcion elegida inexistente---"<<endl<<endl;
	}
 
	}
}
 
//creacion de datos:
nodo *crear_nodo(int &n,nodo *&padre){
	nodo *nuevo_nodo = new nodo();
	nuevo_nodo->dato = n;
	nuevo_nodo->izq = NULL;
	nuevo_nodo->der = NULL;
	nuevo_nodo->padre = padre;
 
	return nuevo_nodo;
}
void insertar(nodo *&arbol,int &n,nodo *padre){
	if(arbol == NULL){
		nodo *nuevo_nodo = crear_nodo(n,padre);
		arbol = nuevo_nodo;
	}
	else{
		if(n < arbol->dato){
			insertar(arbol->izq,n,arbol);
		}
		else{
			insertar(arbol->der,n,arbol);
		}
	}
}
//opciones varias:
void mostrarArbol(nodo *&arbol, int cont){
 if(arbol==NULL){
  	return;
 }
 else{
  	mostrarArbol(arbol->der,cont+1);
  	for(int i=0; i<cont;i++){
   	cout<<"   ";
  }
  cout<<arbol->dato<<endl;
  mostrarArbol(arbol->izq,cont+1);
 }
}
void BuscarNodo(nodo *&arbol, int &b, int &ban){
 
	if((ban == 1) or (arbol == NULL)){
  	return;
	}
	else if(arbol->dato == b){
		cout<<" El elemento "<<b<<" Ha sido encontrado. <-"<<endl<<endl;
		ban = 1;
	}
 
	else if(b < arbol->dato){
		cout<<"Izquierda -> ";
		BuscarNodo(arbol->izq,b,ban);
	}
	else{
		cout<<"Derecha -> ";
		BuscarNodo(arbol->der,b,ban);
	}
 
}
//recorrido en Profundidad:
void PreOrden(nodo *&arbol){
	if(arbol == NULL){
		return;
	}
	else{
		cout<<arbol->dato<<" | ";
		PreOrden(arbol->izq);
		PreOrden(arbol->der);
	}
}
void InOrden(nodo *&arbol){
	if(arbol == NULL){
		return;
	}
	else{
		InOrden(arbol->izq);
		cout<<arbol->dato<<" | ";
		InOrden(arbol->der);
	}
}
void PostOrden(nodo *&arbol){
	if(arbol == NULL){
		return;
	}
	else{
		PostOrden(arbol->izq);
		PostOrden(arbol->der);
		cout<<arbol->dato<<" | ";
	}
}
//Borrado de datos:
void EncontrarBorrado(nodo *busqueda,int n,int &ban){
	if(busqueda == NULL){
		return;
	}
	else if(n > busqueda->dato){
		EncontrarBorrado(busqueda->der,n,ban);
	}
	else if(n < busqueda->dato){
		EncontrarBorrado(busqueda->izq,n,ban);
	}
	else{
		ban = 1;
		TipoDeBorrado(busqueda);
	}
}
void TipoDeBorrado(nodo *suprimido){
 
	if((suprimido->der == NULL) and (suprimido->izq == NULL)){//si no tiene hijos
 
		if(suprimido->padre != NULL){
 
		if(suprimido->padre->izq->dato == suprimido->dato){
			suprimido->padre->izq = NULL;
		}
		else{
			suprimido->padre->der = NULL;
		}
 
	}
 
	suprimido->padre = NULL;
	suprimido->izq = NULL;
	suprimido->der = NULL;
	delete suprimido;
 
	}
	else if(suprimido->izq != NULL and suprimido->der != NULL){//si tiene dos hijos
 
		nodo *minimo = suprimido->der;
		while(minimo->izq != NULL){
			minimo = minimo->izq;
		}
 
		suprimido->dato = minimo->dato;
		TipoDeBorrado(minimo);
 
	}
	else if(suprimido->der){
 
		suprimido->dato = suprimido->der->dato;
		TipoDeBorrado(suprimido->der);
 
	}
	else if(suprimido->izq){
 
		suprimido->dato = suprimido->izq->dato;
		TipoDeBorrado(suprimido->izq);
 
	}
 
}
Valora esta pregunta
Me gusta: Está pregunta es útil y esta claraNo me gusta: Está pregunta no esta clara o no es útil
0
Responder
Imágen de perfil de Rodrigo
Val: 1.755
Plata
Ha mantenido su posición en Dev - C++ (en relación al último mes)
Gráfica de Dev - C++

Problemas con el Borrado de datos en Arboles Binarios

Publicado por Rodrigo (539 intervenciones) el 10/08/2020 15:41:36
Sugiero que incluyas algo adicional:

Como estas probando tu programa?
Cual es la entrada? La salida esperada? La salida que te da tu programa?
Por que dices "casos especiales que tiran un error."? Que error? Error de compilacion? De ejecucion? aparece algo en la salida? Que cosa exactamente?

Por otro lado, por que no devolver un booleano en vez de modificar un parametro para saber si un elemento esta?

Parece mas leible permitir un codigo como:

1
2
3
if( BuscarNodo( arbol, nodo ) ) {
   // acciones si el nodo esta en arbol
}

que

1
2
3
4
5
6
7
int cont = 0;
 
BuscarNodo( arbol, nodo, &cont );
 
if( cont == 1 ) {
   // acciones si el nodo esta en el arbol
}

Pareciera que EncontrarBorrado() no es mas que otra BuscarNodo(). SI no estas obligado a imprimir como lo esta haciendo BuscarNodo, deberias tener una sola funcion para buscar, no 2.
Por otro lado, por que se llama cont? Parece un mal nombre. Puede eliminar completamente el parametro, retornar un bool, eliminar la necesidad de tener una variable y escribir un codigo mas fluido como consecuencia.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
1
Comentar
sin imagen de perfil
Val: 20
Ha disminuido 1 puesto en Dev - C++ (en relación al último mes)
Gráfica de Dev - C++

Problemas con el Borrado de datos en Arboles Binarios

Publicado por Nahuel (6 intervenciones) el 11/08/2020 02:44:39
Hola! gracias por responder. Antes que nada aplique lo que me dijiste sobre lo de BuscarNodo(no me había dado cuenta del detalle de que podía reutilizar la función) por lo que el código actual quedo talque así:

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
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
#include<iostream>
#include<stdlib.h>
using namespace std;
 
struct nodo{
	int dato;
	nodo *padre;
	nodo *izq;
	nodo *der;
}*arbol = NULL;
 
void m();
 
//creacion de datos
nodo *crear_nodo(int&,nodo *&);//creamos un nodo vacio
void insertar(nodo *&,int&,nodo *);//insertamos el nodo a la lista
 
//opciones varias
void mostrarArbol(nodo *&,int);//mostramos el arbol
bool BuscarNodo(nodo *&, int&,bool&);//buscamos un dato dentro del arbol
 
//funciones de borrado de nodos
void TipoDeBorrado(nodo *);//decidimos como lo borraremos dependiendo de cuantos hijos tenga
 
//recorrido en Profundidad
void PreOrden(nodo *&);//mostramos en preorden
void InOrden(nodo *&);//mostramos en inorden
void PostOrden(nodo *&);//mostramos en postorden
 
int main(){
 
	m();
 
	system("PAUSE");
	return 0;
}
 
//MENU
void m(){
	int n,c,s;
	bool tipe;
 
	while(s != 8){
		cout<<"----MENU----"<<endl;
		cout<<"Aprieta 1 para agregar elementos al Arbol."<<endl;
		cout<<"Aprieta 2 para mostrar el Arbol."<<endl;
		cout<<"Aprieta 3 para buscar un elemento."<<endl;
		cout<<"Aprieta 4 para Mostrar el Arbol en PreOrden."<<endl;
		cout<<"Aprieta 5 para Mostrar el Arbol en InOrden."<<endl;
		cout<<"Aprieta 6 para Mostrar el Arbol en PostOrden."<<endl;
		cout<<"Aprieta 7 para eliminar un dato del Arbol."<<endl;
		cout<<"Aprieta 8 para salir."<<endl;
		cout<<"Opcion elegida: "; cin>>s;
		system("cls");
 
	switch(s){
		case 1:
 
			cout<<"Dame la cantidad de elementos que deseas ingresar al arbol: "; cin>>c;
 
			for(int i = 1;i<=c;i++){
				cout<<i<<". Dame un numero: "; cin>>n;
				insertar(arbol,n,NULL);
			}
			system("cls");
			break;
 
		case 2:
			cout<<"---------------------------------------"<<endl;
			if(arbol == NULL){
			cout<<"---Arbol Vacio---"<<endl<<endl;
			}
			else{
				c = 0;
				mostrarArbol(arbol,c);
			}
			cout<<"---------------------------------------"<<endl;
			break;
 
		case 3:
			if(arbol == NULL){
				cout<<"---Arbol Vacio---"<<endl<<endl;
			}
			else{
				tipe = false;
				cout<<"Dame el Dato que deseas Buscar: "; cin>>n;
				system("cls");
 
				if(n == arbol->dato){
					cout<<"---El elemento "<<n<<" Es la Raiz del Arbol---"<<endl<<endl;
				}
				else{
					if(BuscarNodo(arbol,n,tipe) == false){
						system("cls");
						cout<<"---Elemento no encontrado---"<<endl<<endl;
					}
				}
 
 
 
			}
			break;
 
		case 4:
			if(arbol == NULL){
				cout<<"---Arbol Vacio---"<<endl<<endl;
			}
			else{
			cout<<"-------"<<endl;
			cout<<" | ";
			PreOrden(arbol);
			cout<<endl<<"-------"<<endl<<endl;
			}
			break;
 
		case 5:
			if(arbol == NULL){
				cout<<"---Arbol Vacio---"<<endl<<endl;
			}
			else{
			cout<<"-------"<<endl;
			cout<<" | ";
			InOrden(arbol);
			cout<<endl<<"-------"<<endl<<endl;
			}
			break;
 
		case 6:
			if(arbol == NULL){
				cout<<"---Arbol Vacio---"<<endl<<endl;
			}
			else{
			cout<<"-------"<<endl;
			cout<<" | ";
			PostOrden(arbol);
			cout<<endl<<"-------"<<endl<<endl;
			}
			break;
 
		case 7:
			if(arbol == NULL){
				cout<<"---Arbol Vacio---"<<endl<<endl;
			}
			else{
				tipe = true;
				cout<<"Dame el dato que deseas eliminar: "; cin>>n;
				system("cls");
 
				if(BuscarNodo(arbol,n,tipe) == false){
					system("cls");
					cout<<"---Elemento no encontrado---"<<endl<<endl;
				}
				else{
					cout<<"---Elemento "<<n<<" Borrado correctamente---"<<endl<<endl;
				}
 
			}
 
 
			break;
 
		case 8:
			cout<<"---Saliendo del Programa---"<<endl<<endl;
			break;
 
		default:
			cout<<"---Opcion elegida inexistente---"<<endl<<endl;
	}
 
	}
}
 
//creacion de datos:
nodo *crear_nodo(int &n,nodo *&padre){
	nodo *nuevo_nodo = new nodo();
	nuevo_nodo->dato = n;
	nuevo_nodo->izq = NULL;
	nuevo_nodo->der = NULL;
	nuevo_nodo->padre = padre;
 
	return nuevo_nodo;
}
void insertar(nodo *&arbol,int &n,nodo *padre){
	if(arbol == NULL){
		nodo *nuevo_nodo = crear_nodo(n,padre);
		arbol = nuevo_nodo;
	}
	else{
		if(n < arbol->dato){
			insertar(arbol->izq,n,arbol);
		}
		else{
			insertar(arbol->der,n,arbol);
		}
	}
}
//opciones varias:
void mostrarArbol(nodo *&arbol, int cont){
 if(arbol==NULL){
  	return;
 }
 else{
  	mostrarArbol(arbol->der,cont+1);
  	for(int i=0; i<cont;i++){
   	cout<<"   ";
  }
  cout<<arbol->dato<<endl;
  mostrarArbol(arbol->izq,cont+1);
 }
}
bool BuscarNodo(nodo *&arbol, int &b,bool &tipe){
 
	if(arbol == NULL){
  	return false;
	}
	else if(arbol->dato == b){
		cout<<" El elemento "<<b<<" Ha sido encontrado. <-"<<endl<<endl;
 
		if(tipe == true){
			system("cls");
			TipoDeBorrado(arbol);
		}
 
		return true;
	}
 
	else if(b < arbol->dato){
		cout<<"Izquierda -> ";
		BuscarNodo(arbol->izq,b,tipe);
	}
	else{
		cout<<"Derecha -> ";
		BuscarNodo(arbol->der,b,tipe);
	}
 
}
//recorrido en Profundidad:
void PreOrden(nodo *&arbol){
	if(arbol == NULL){
		return;
	}
	else{
		cout<<arbol->dato<<" | ";
		PreOrden(arbol->izq);
		PreOrden(arbol->der);
	}
}
void InOrden(nodo *&arbol){
	if(arbol == NULL){
		return;
	}
	else{
		InOrden(arbol->izq);
		cout<<arbol->dato<<" | ";
		InOrden(arbol->der);
	}
}
void PostOrden(nodo *&arbol){
	if(arbol == NULL){
		return;
	}
	else{
		PostOrden(arbol->izq);
		PostOrden(arbol->der);
		cout<<arbol->dato<<" | ";
	}
}
//Borrado de datos:
void TipoDeBorrado(nodo *suprimido){
 
	if((suprimido->der == NULL) and (suprimido->izq == NULL)){//si no tiene hijos
 
		if(suprimido->padre != NULL){
 
		if(suprimido->padre->izq->dato == suprimido->dato){
			suprimido->padre->izq = NULL;
		}
		else{
			suprimido->padre->der = NULL;
		}
 
	}
 
	suprimido->padre = NULL;
	suprimido->izq = NULL;
	suprimido->der = NULL;
	delete suprimido;
 
	}
	else if(suprimido->izq != NULL and suprimido->der != NULL){//si tiene dos hijos
 
		nodo *minimo = suprimido->der;
		while(minimo->izq != NULL){
			minimo = minimo->izq;
		}
 
		suprimido->dato = minimo->dato;
		TipoDeBorrado(minimo);
 
	}
	else if(suprimido->der){//si tiene solo el hijo derecho
 
		suprimido->dato = suprimido->der->dato;
		TipoDeBorrado(suprimido->der);
 
	}
	else if(suprimido->izq){//si tiene solo el hijo izquierdo
 
		suprimido->dato = suprimido->izq->dato;
		TipoDeBorrado(suprimido->izq);
 
	}
 
}

En cuanto a tus preguntas, ahora las respondo:
- La entrada esperada seria en primera instancia el árbol con la cantidad y elementos digitados por el usuario. En segunda instancia(ya centrándonos en el borrado de datos) el elemento que el usuario desee eliminar. En esta parte no habría un error, pues el programa parece ser capaz de operar con estos elementos sin ningún problema en ciertos casos(ahora me explayo).
-La salida esperada se mostraría principalmente en el momento de decirle al usuario si el elemento se borro o no, ademas de cuando se usa la opción 2(Mostrar el Árbol). De nuevo, en esta zona no habría aparente error, pues el programa me da la salida esterada SOLO en ciertos casos.

Entonces, el problema o error seria el siguiente: El programa ejecuta con normalidad(por lo que el error no es uno de sintaxis) y ejecuta las funciones de menú de manera esperada. Sin embargo, al momento de borrar un elemento pueden pasar dos cosas: O el elemento se borra de manera esperada o sale un cartel de windows diciendo "arboles.exe dejo de funcionar".

Desde mi perspectiva, lo que debe suceder es que en algún momento los punteros se deben desequilibrar o/y el código tiene ciertos casos especiales donde el las instrucciones generales no sirven, haciendo saltar el error. Pero como dije, solo pasa en algunos casos:
-cuando el elemento a borrar tiene solo un hijo derecho(independientemente de cuanta descendencia tenga el hijo derecho)
- Al momento de enseñar un árbol que se quedo sin nodos luego de eliminarlos a todos(esto es algo que me di cuenta recién cuando testeaba)
-Cuando se borra un nodo con dos hijos donde un hijo es repetido del padre

-En cuanto a como estoy probando mi programa, a puro sudor y paciencia jaja, viendo cada caso posible.

Espero que esto te sirva para comprender un poco mejor el programa, gracias de antemano.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar
Imágen de perfil de Rodrigo
Val: 1.755
Plata
Ha mantenido su posición en Dev - C++ (en relación al último mes)
Gráfica de Dev - C++

Problemas con el Borrado de datos en Arboles Binarios

Publicado por Rodrigo (539 intervenciones) el 11/08/2020 14:57:08
Puedes poner un ejemplo explicito, no teoria, de cuando tu programa no funciona?
O copiar y pegar una sesion de entradas y salidas de tu programa para reproducir el error?
Ojala el minimo numero de pasos que lo reproduce.

Ahora algunos comentarios y sugerencias respecto a tu codigo. Todo lo de mas abajo no va a arreglar necesariamente tu problema, pero puede facilitar comprender mas tu codigo.

Las funciones deberian hacer 1 y solo 1 cosa.
La funcion BuscarNodo solo deberia buscar, no deberia invocar la funcion de borrado,
ni siquiera deberia imprimir. Su unica mision: saber si un elemento esta en el arbol y devolver si lo encontro o no.
Quien llama a la funcion entonces, se obliga a realizar acciones con el resultado de BuscarNodo. No es BuscarNodo quien lo hace.

El problema que tienes es que para borrar, necesitas el nodo a borrar, por lo que podrias cambiar el tipo de retorno de BuscarNodo: que ya no devuelva boolean, sino que devuelva un nodo*, que sera el elemento encontrado o null si no es encontrado.

En ese caso la invocacion a BuscarNodo quedaria, para el caso del borrado:

1
2
3
4
nodo* a_borrar = BuscarNodo( arbol, n );
if( a_borrar != null ) {
    BorrarNodo( arbol, a_borrar );  // TipoDeBorrado renombrado a BorrarNodo
}

Con esta modificacion, eliminas el 3er parametro de la funcion BuscarNodo, que ya era un candidato a ser sospechoso de codigo extran~o.
Tambien eliminas la variable tipe del main, no es necesaria mas.

No le pongas nombres como m() a las funciones. Especialmente si estas pidiendo ayuda en un foro.
Ponle nombres descriptivos a tus funciones y variables. Cortos y claros.
m() podria ser menu(), TipoDeBorrado deberia ser BorrarNodo y creo que deberia recibir 2 parametros, para considerar el caso que quieras borrar la raiz (y borrarla).

La variable c es superflua. Usa 0 directamente en el parametro de la funcion.

Las variables locales no parten en 0, parten con cualquier valor que haya en la memoria en el momento de la ejecucion del programa.
La variable s la defines y 2 lineas mas abajo tienes un while que se ejecuta si s != 8, se podria ser 8 (por casualidad) y no ejecutarse nunca,
-> asignale un valor inicial. Aprovecha y cambiale el nombre.

Respecto a tu problema, considera que si tu estructura tiene un puntero al padre y estas eliminando un nodo en la mitad, todos los hijos necesitan tener un nuevo padre.

Pareciera que podrias eliminar parte de la invocacion recursiva en el caso de nodos que solo tienen 1 hijo. En ese caso, basta ajustar el padre t el unico hijo.

Algo adicional: Cuando una funcion ejecuta return todo el resto del codigo ya no se va a ejecutar.
Puedes usar esto para reducir un poco los niveles de indentacion y facilitar la lectura tambien.

Dicho de otro modo:

1
2
3
4
5
6
7
8
if(condicion) {
   ... instrucciones
   ...
   return valor;  // o return solo, si se trata de una funcion void
} else {
   ... otras instrucciones
   ...
}

Se convierte en:

1
2
3
4
5
6
7
if(condicion) {
   ... instrucciones
   ...
   return valor;  // o return solo, si se trata de una funcion void
}
 
otras instrucciones
...

Hay varias funciones que presentas que pueden modificarse asi.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
1
Comentar
sin imagen de perfil
Val: 20
Ha disminuido 1 puesto en Dev - C++ (en relación al último mes)
Gráfica de Dev - C++

Problemas con el Borrado de datos en Arboles Binarios

Publicado por Nahuel (6 intervenciones) el 15/08/2020 07:12:54
Hola! ya logre resolver los errores del programa, y gracias a tu ayuda pude pulirlo como para hacerlo cuanto menos un poco mas presentable, De verdad muchas gracias.
Te puedo hacer una pregunta? Cuanto tiempo de experiencia tenes programando en c++?

Bueno, en cualquier caso, este es el código completo del programa:
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
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
#include<iostream>
#include<stdlib.h>
using namespace std;
 
struct nodo{
	int dato;
	nodo *der;
	nodo *izq;
	nodo *padre;
}*arbol = NULL;
 
//Funciones primariasiere hacer
void Opciones(int&);//mediante un condicional seleccionamos lo
void menu();//el usuario nos dice que qu que vamos a hacer a base de lo que quiere el usuario
 
//creacion de datos
nodo *crear_nodo(int&,nodo *&);//creamos un nodo vacio
void insertar(nodo *&,int&,nodo *);//insertamos el nodo a la lista
 
//opciones varias
void mostrarArbol(nodo *&,int);//mostramos el arbol
nodo* BuscarNodo(nodo *&, int&);//buscamos y copiamos la ruta hacia un dato dentro del arbol
nodo* minimo(nodo*&);//buscamos el menor elemento dentro del arbol
nodo* mayor(nodo*&);//buscamos el mayor elemento dentro del arbol
bool TipoDeHijo(nodo *&);//dice si un nodo es una raiz, un hijo derecho o un hijo izquierdo
 
//funciones de borrado de nodos
void BorrarNodo(nodo *&,nodo *&);//dependiendo de que tipo de nodo sea, lo borraremos de una forma u otra
void Borrado_SinHijos(nodo *&,nodo *&);//Procedimiento a realizar cuando el nodo no tiene hijos
void Borrado_DosHijos(nodo *&,nodo *&);//procedimiento a realizar cuando el nodo tiene dos hijos
void Borrado_UnHijo(nodo *&,nodo *&,nodo *&);//procedimiento a realizar cuando el nodo solo tiene un solo hijo
void Suprimir(nodo *&);//Procedimiento de eliminacion de un nodo
 
//recorrido en Profundidad
void PreOrden(nodo *&);//mostramos en preorden
void InOrden(nodo *&);//mostramos en inorden
void PostOrden(nodo *&);//mostramos en postorden
 
int main(){
 
	menu();
 
	system("PAUSE");
	return 0;
}
 
//MENU
void menu(){
	int opcion = 0;
 
	while(opcion != 11){
		cout<<"----MENU----"<<endl;
		cout<<"Aprieta 1 para agregar elementos al Arbol."<<endl;
		cout<<"Aprieta 2 para mostrar el Arbol."<<endl;
		cout<<"Aprieta 3 para buscar un elemento."<<endl;
		cout<<"Aprieta 4 para Mostrar el Arbol en PreOrden."<<endl;
		cout<<"Aprieta 5 para Mostrar el Arbol en InOrden."<<endl;
		cout<<"Aprieta 6 para Mostrar el Arbol en PostOrden."<<endl;
		cout<<"Aprieta 7 para saber el menor dato existente dentro del arbol."<<endl;
		cout<<"Aprieta 8 para saber el mayor dato existente dentro del arbol."<<endl;
		cout<<"Aprieta 9 para saber que tipo de hijo es un dato dentro del arbol."<<endl;
		cout<<"Aprieta 10 para eliminar un dato del Arbol."<<endl;
		cout<<"Aprieta 11 para salir."<<endl;
		cout<<"Opcion elegida: "; cin>>opcion;
		system("cls");
 
		Opciones(opcion);
	}
}
 
void Opciones(int &opcion){
	int n;//donde se guarda los datos que usaremos en las diferentes ordenes dadas por el usuario
	int contador;
 
	switch(opcion){
		case 1:
 
			cout<<"Dame la cantidad de elementos que deseas ingresar al arbol: "; cin>>contador;
 
			for(int i = 1;i<=contador;i++){
				cout<<i<<". Dame un numero: "; cin>>n;
				insertar(arbol,n,NULL);
			}
			system("cls");
			break;
 
		case 2:
			cout<<"---------------------------------------"<<endl;
			if(arbol == NULL){
			cout<<"---Arbol Vacio---"<<endl;
			}
			else{
				mostrarArbol(arbol,0);
			}
			cout<<"---------------------------------------"<<endl;
			break;
 
		case 3:
			if(arbol == NULL){
				cout<<"---Arbol Vacio---"<<endl<<endl;
			}
			else{
				cout<<"Dame el Dato que deseas Buscar: "; cin>>n;
				system("cls");
 
				if(n == arbol->dato){
					cout<<"---El elemento "<<n<<" Es la Raiz del Arbol---"<<endl<<endl;
				}
				else{
					if(BuscarNodo(arbol,n) == NULL){
						system("cls");
						cout<<"---Elemento no encontrado---"<<endl<<endl;
					}
					else{
						cout<<" Elemento "<<n<<" encontado <-"<<endl<<endl;
					}
				}
 
 
 
			}
			break;
 
		case 4:
			if(arbol == NULL){
				cout<<"---Arbol Vacio---"<<endl<<endl;
			}
			else{
			cout<<"-------"<<endl;
			cout<<" | ";
			PreOrden(arbol);
			cout<<endl<<"-------"<<endl<<endl;
			}
			break;
 
		case 5:
			if(arbol == NULL){
				cout<<"---Arbol Vacio---"<<endl<<endl;
			}
			else{
			cout<<"-------"<<endl;
			cout<<" | ";
			InOrden(arbol);
			cout<<endl<<"-------"<<endl<<endl;
			}
			break;
 
		case 6:
			if(arbol == NULL){
				cout<<"---Arbol Vacio---"<<endl<<endl;
			}
			else{
			cout<<"-------"<<endl;
			cout<<" | ";
			PostOrden(arbol);
			cout<<endl<<"-------"<<endl<<endl;
			}
			break;
 
		case 7:
			if(arbol == NULL){
				cout<<"---Arbol Vacio---"<<endl<<endl;
			}
			else{
				nodo *Menor = minimo(arbol);
				cout<<"---El menor elemento dentro del arbol es el "<<Menor->dato<<"---"<<endl<<endl;
			}
			break;
 
		case 8:
			if(arbol == NULL){
				cout<<"---Arbol Vacio---"<<endl<<endl;
			}
			else{
				nodo *Mayor = mayor(arbol);
				cout<<"---El mayor elemento dentro del arbol es el "<<Mayor->dato<<"---"<<endl<<endl;
			}
			break;
 
		case 9:
			if(arbol == NULL){//si el arbol esta vacio
				cout<<"---Arbol Vacio---"<<endl<<endl;
			}
			else{
				cout<<"Dame el dato: "; cin>>n;//si no esta vacio, le pedimos el dato a buscar
				system("cls");
				//nos fijamos si el dato existe dentro del arbol
					if(BuscarNodo(arbol,n) == NULL){//si no existe
						system("cls");
						cout<<"---Elemento no encontrado---"<<endl<<endl;
					}
					else{//si existe
 
						if(n == arbol->dato){//si es la raiz del arbol
							cout<<"---El elemento "<<n<<" Es la Raiz del Arbol---"<<endl<<endl;
						}
						else{//si no es la raiz del arbol
 
							nodo *a_buscar = BuscarNodo(arbol,n);
							system("cls");
 
							if(TipoDeHijo(a_buscar)){//si retorna true es hijo derecho
								cout<<"---El nodo "<<a_buscar->dato<<" es un hijo Derecho---"<<endl<<endl;
							}
							else{//si retorna false es hijo izquierdo
								cout<<"---El nodo "<<a_buscar->dato<<" es un hijo Izquierdo---"<<endl<<endl;
							}
 
						}
 
					}
				}
				break;
 
		case 10:
			if(arbol == NULL){
				cout<<"---Arbol Vacio---"<<endl<<endl;
			}
			else{
				cout<<"Dame el dato que deseas eliminar: "; cin>>n;
				system("cls");
 
					if(BuscarNodo(arbol,n) == NULL){
						system("cls");
						cout<<"---Elemento no encontrado---"<<endl<<endl;
					}
					else{
						nodo *a_borrar = BuscarNodo(arbol,n);
						system("cls");
						BorrarNodo(a_borrar,arbol);
						cout<<"---Elemento "<<n<<" Borrado correctamente---"<<endl<<endl;
					}
				}
 
 
			break;
 
		case 11:
			cout<<"---Saliendo del Programa---"<<endl<<endl;
			break;
 
		default:
			cout<<"---Opcion elegida inexistente---"<<endl<<endl;
	}
 
}
 
//creacion de datos:
nodo *crear_nodo(int &n,nodo *&padre){
	nodo *nuevo_nodo = new nodo();
	nuevo_nodo->dato = n;
	nuevo_nodo->izq = NULL;
	nuevo_nodo->der = NULL;
	nuevo_nodo->padre = padre;
 
	return nuevo_nodo;
}
void insertar(nodo *&arbol,int &n,nodo *padre){
	if(arbol == NULL){
		nodo *nuevo_nodo = crear_nodo(n,padre);
		arbol = nuevo_nodo;
	}
	else{
		if(n < arbol->dato){
			insertar(arbol->izq,n,arbol);
		}
		else{
			insertar(arbol->der,n,arbol);
		}
	}
}
//opciones varias:
void mostrarArbol(nodo *&arbol, int cont){
 if(arbol==NULL){
  	return;
 }
 else{
  	mostrarArbol(arbol->der,cont+1);
  	for(int i=0; i<cont;i++){
   	cout<<"   ";
  }
  cout<<arbol->dato<<endl;
  mostrarArbol(arbol->izq,cont+1);
 }
}
nodo* BuscarNodo(nodo *&arbol, int &buscado){
 
	if(arbol == NULL or arbol->dato == buscado){
		return arbol;
	}
	else if(buscado < arbol->dato){
		cout<<"Izquierda ->";
		BuscarNodo(arbol->izq,buscado);
	}
	else{
		cout<<"Derecha -> ";
		BuscarNodo(arbol->der,buscado);
	}
 
}
nodo *minimo(nodo *&arbol){
	while(arbol->izq != NULL){
		arbol = arbol->izq;
	}
	return arbol;
}
nodo *mayor(nodo *&arbol){
	while(arbol->der != NULL){
		arbol = arbol->der;
	}
	return arbol;
}
bool TipoDeHijo(nodo *&hijo){
	if(hijo->padre->der == hijo){
		return true;
	}
	return false;
 
}
//recorrido en Profundidad:
void PreOrden(nodo *&arbol){
	if(arbol == NULL){
		return;
	}
	cout<<arbol->dato<<" | ";
	PreOrden(arbol->izq);
	PreOrden(arbol->der);
}
void InOrden(nodo *&arbol){
	if(arbol == NULL){
		return;
	}
	InOrden(arbol->izq);
	cout<<arbol->dato<<" | ";
	InOrden(arbol->der);
}
void PostOrden(nodo *&arbol){
	if(arbol == NULL){
		return;
	}
	PostOrden(arbol->izq);
	PostOrden(arbol->der);
	cout<<arbol->dato<<" | ";
}
//Borrado de datos:
void BorrarNodo(nodo *&suprimido,nodo *&raiz){
 
	if(suprimido->der == NULL and suprimido->izq == NULL){//si tiene ningun hijo
		Borrado_SinHijos(suprimido,raiz);
	}
 
	else if(suprimido->der != NULL and suprimido->izq != NULL){//si tiene dos hijos
		Borrado_DosHijos(suprimido,raiz);
	}
 
	else if(suprimido->der != NULL){//si tiene solo el hijo derecho
		Borrado_UnHijo(suprimido,suprimido->der,raiz);
	}
 
	else if(suprimido->izq != NULL){//si tiene solo el hijo izquierdo
		Borrado_UnHijo(suprimido,suprimido->izq,raiz);
	}
 
}
void Borrado_SinHijos(nodo *&suprimido,nodo *&raiz){
 
	if(suprimido->padre != NULL){//si el nodo a borrar tiene padre
 
		if(TipoDeHijo(suprimido)){//si es un hijo derecho
			suprimido->padre->der = NULL;
		}
		else{//si en cambio es un hijo izquierdo
			suprimido->padre->izq = NULL;
		}
 
	}
	else if(raiz == suprimido){//si el nodo a borrar es la raiz
		raiz = NULL;//anulamos a raiz en el caso de que sea el nodo a borrar
	}
 
	Suprimir(suprimido);
 
}
void Borrado_DosHijos(nodo *&suprimido,nodo *&raiz){
 
	nodo *min = minimo(suprimido->der);//buscamos el valor mas cercano al dato a borrar
	suprimido->dato = min->dato;//copiamos el valor encontrado por la funcion minimo hacia el dato que deseamos borrar
	BorrarNodo(min,raiz);//borramos minimo
 
}
void Borrado_UnHijo(nodo *&suprimido,nodo *&hijo,nodo *&raiz){
 
	if(suprimido->padre != NULL){//si el nodo a borrar tiene padre
 
		hijo->padre = suprimido->padre;//al nodo hijo le asignamos como nuevo padre a su "abuelo"
 
		if(TipoDeHijo(suprimido)){//si es hijo derecho
			suprimido->padre->der = hijo;//al nodo padre le asignamos como nuevo hijo a su "nieto"
		}
		else{//si es hijo izquierdo
			suprimido->padre->izq = hijo;//al nodo padre le asignamos como nuevo hijo a su "nieto"
		}
 
	}
	else if(raiz == suprimido){//si el nodo a borrar es la raiz
		raiz = hijo;//intercambiamos lugares entre raiz/suprimido con hijo
		raiz->padre = NULL;//le ponemos null apadre para convertirlo un una raiz completa(recordemos que estas no tienen padre)
	}
 
	Suprimir(suprimido);
 
}
void Suprimir(nodo *&suprimido){
 
	suprimido->der = NULL;
	suprimido->izq = NULL;
	suprimido->padre = NULL;
	delete suprimido;
	suprimido = NULL;
 
}

De nuevo, gracias. Que tengan un buen día.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar
Imágen de perfil de Rodrigo
Val: 1.755
Plata
Ha mantenido su posición en Dev - C++ (en relación al último mes)
Gráfica de Dev - C++

Problemas con el Borrado de datos en Arboles Binarios

Publicado por Rodrigo (539 intervenciones) el 15/08/2020 13:38:20
Felicitaciones y gracias por volver a publicar el codigo "final".

Revisandolo, pareciera que hay errores y cosas por mejorar.
Estoy un poco desconcertado, no entiendo como funciona tu programa con los errores que veo, por lo que supongo que debe haber cosas que hacen que funcione y que no veo con claridad, o bien no lo probaste exhaustivamente y no has descubierto los errores aun.

Aqui va lo que descubri, y las sugerencias de mejoras:

La funcion BuscarNodo:

- Hay un return en la linea 290, por lo que el else de la linea 292 es superfluo, puedes eliminarlo.
- NO hay un return en la linea 293, lo que es un error, pues la funcion tiene que devolver el valor que se obtiene en la llamada recursiva, al poner ese return ademas de corregir este problema, se puede eliminar el else de la linea 295 y las llaves del bloque final.

- Siempre que invocas BuscarNodo en el menu, lo haces 2 veces, por ejemplo en las lineas 188 y 199.
Esto no es necesario y puedes simplificar el codigo llamando BuscarNodo y guardando el valor retornado en la primera invocacion

1
2
3
4
5
6
7
8
9
nodo *a_buscar = BuscarNodo(arbol,n);
if( a_buscar == NULL ) {
  // no existe
}
if( a_buscar == arbol ) {
  // es igual a la raiz
} else {
 ...
}

Las lineas 223 y 228 vuelven a usar 2 veces BuscarNodo. Usa la misma sugerencia

El nombre de la funcion TipoDeHijo se puede mejorar, pues no devuelve ni escribe el tipo de hijo, esa funcion devuelve true si el nodo que se le pasa como parametro es hijo derecho del nodo padre, o false si es hijo izquierdo. derecho true, izquierdo false. Sugiero cambiarlo a EsHijoDerecho() o similar. El comentario de la linea 25 es inexacto pues la funcion no dice si el nodo es raiz.

Veo que algunas funciones pasan a n por referencia. Si no modificas el valor de n, no tiene ninguna ventaja. Tiene sentido con estructuras grandes que se pasan por valor, que implican una copia y que al usar la referencia se ahorran la copia, pero para un int que no esta siendo modificado no hay ventaja alguna. Puedes eliminar ese paso por referencia en las lineas 249, 258, 286, 321, 329, 337.

Tengo la impresion que la funcion minimo y mayor tienen un problema al poner el parametro como referencia, pues van a modificar el puntero que se le pase (tipicamente la raiz) y lo modificaran para que apunte al minimo (o mayor, respectivamente). Quieres modificar el nodo que apubta a la raiz, o quieres tener un puntero al minimo? Yo creo que es esto ultimo. Si es asi, no uses paso por referencia.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar
sin imagen de perfil
Val: 20
Ha disminuido 1 puesto en Dev - C++ (en relación al último mes)
Gráfica de Dev - C++

Problemas con el Borrado de datos en Arboles Binarios

Publicado por Nahuel (6 intervenciones) el 16/08/2020 01:49:05
Hola! aplique todo los consejos que me diste arriba salvo uno que no llegue a comprender del todo: El segundo "error" de la función BuscarNodo(el que en la Linea 293 No hay un return). Intente hacer lo que me dijiste, pero al momento de ejecutar la opción de buscar un nodo daba una salida errónea. En cualquier caso, tal cual tengo la función ahora no me da problema alguno y cumple con su propósito(estuve probando bastante tiempo esta parte).

¿Podrías darme un ejemplo practico de a lo que te refieres?:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
nodo* BuscarNodo(nodo *&arbol, int buscado){
 
	if(arbol == NULL or arbol->dato == buscado){
		return arbol;
	}
	if(buscado < arbol->dato){
		cout<<"Izquierda ->";
		BuscarNodo(arbol->izq,buscado);
	}
	else{
		cout<<"Derecha -> ";
		BuscarNodo(arbol->der,buscado);
	}
 
}

Por otro lado, creo que me exedi con el tema de pasar parámetros por referencia jeje. Y en cuanto a lo de las funciones minimo y maximo ve a saber tu que milagro evitaba que saltara error tal cual estaban.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar
Imágen de perfil de Rodrigo
Val: 1.755
Plata
Ha mantenido su posición en Dev - C++ (en relación al último mes)
Gráfica de Dev - C++

Problemas con el Borrado de datos en Arboles Binarios

Publicado por Rodrigo (539 intervenciones) el 16/08/2020 04:38:42
Yo no compilo ni pruebo tu programa para darte estos tips, pero tu si, por lo que seria util saber como estas probando que el programa que tienes es correcto.

En vez de mostrar tus datos, y como lo pruebas, te sugiero crear funciones que prueben tu programa, por ejemplo una funcion test1() que empiece con un arbol, le agregue algunos valores (que no pides por teclado, especificalos tu mismo explicitamente en la funcion de test) y luego pregunte, usando BuscarNodo, por todos ellos, todos ellos deberian estar. Otra funcion, test2(), que empiece con otro arbol, que le agregue 1 valor, luego lo elimine, y luego lo busque, ese valor no deberia estar, test3() con 2 valores, que elimine uno de ellos y busque al eliminado y al borrado, uno deberia estar y el otro no, test4() con 3 etc.

Crea variantes del mismo test. Inserta 3 valores y eliminalos en el orden que fueron insertados, En otro test, eliminalos al reves de como fueron insertados, y otro test con otro orden. Siempre despues de borrar preguntas por los elementos que en teoria estan (aun deberian estar, y por los borrados (que ya no deberian estar)

Crea una funcion que se llame testsO que llame a todos los otros tests creados

1
2
3
4
5
6
7
8
9
10
11
12
13
void test1() {
   cout <<  "TEST1";
   // 1. crear arbol
   // 2. agregar valores
   // 3. Buscar cada uno de los valores agregados, todos deberian estar
}
...
 
void tests() {
  test1();
  test2();
  ...
}

Agrega una opcion a tu menu para ejecutar tus tests.

Una vez que estos tests pasen (o fallen), puedes volver y describir mejor las condiciones por las que tu programa no funciona, o bien contar con alegria que todos los tests pasan.

Una vez que todo funcione, borras estos tests, o los mueves a otro lado.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
1
Comentar
sin imagen de perfil
Val: 20
Ha disminuido 1 puesto en Dev - C++ (en relación al último mes)
Gráfica de Dev - C++

Problemas con el Borrado de datos en Arboles Binarios

Publicado por Nahuel (6 intervenciones) el 17/08/2020 00:28:58
Estuve probando el programa manualmente(yo metía los diferentes datos, yo los borraba, etc). Puede ser interesante lo de probar el programa de forma automática. Dentro de un par de días te digo si encontré algún problema o por el contrario, el programa dio la entrada y salida esperada. De verdad muchas gracias por la ayuda hasta el momento.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar
sin imagen de perfil
Val: 20
Ha disminuido 1 puesto en Dev - C++ (en relación al último mes)
Gráfica de Dev - C++

Problemas con el Borrado de datos en Arboles Binarios

Publicado por Nahuel (6 intervenciones) el 22/08/2020 02:17:16
Hola! Creo que ya realice los suficientes test como para comprobar que mi programa no diera error alguno, así que puedo decir con certeza que el programa funciona correctamente. Has sido una gran ayuda, por lo que te lo agradezco.

En cualquier caso, este seria el código final(esta vez es en serio ahr):
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
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
#include<iostream>
#include<stdlib.h>
using namespace std;
 
struct nodo{
	int dato;
	nodo *der;
	nodo *izq;
	nodo *padre;
}*arbol = NULL;
 
//Funciones primariasiere hacer
void Opciones(int&);//mediante un condicional seleccionamos lo
void menu();//el usuario nos dice que qu que vamos a hacer a base de lo que quiere el usuario
 
//creacion de datos
nodo *crear_nodo(int,nodo *&);//creamos un nodo vacio
void insertar(nodo *&,int,nodo *);//insertamos el nodo a la lista
 
//opciones varias
void mostrarArbol(nodo *&,int);//mostramos el arbol
nodo* BuscarNodo(nodo *&, int);//buscamos y copiamos la ruta hacia un dato dentro del arbol
nodo* minimo(nodo*);//buscamos el menor elemento dentro del arbol
nodo* mayor(nodo*);//buscamos el mayor elemento dentro del arbol
bool EsHijoDerecho(nodo *&);//manda true si es un hijo derecho, false en caso de ser izquierdo
 
//funciones de borrado de nodos
void BorrarNodo(nodo *&,nodo *&);//dependiendo de que tipo de nodo sea, lo borraremos de una forma u otra
void Borrado_SinHijos(nodo *&,nodo *&);//Procedimiento a realizar cuando el nodo no tiene hijos
void Borrado_DosHijos(nodo *&,nodo *&);//procedimiento a realizar cuando el nodo tiene dos hijos
void Borrado_UnHijo(nodo *&,nodo *&,nodo *&);//procedimiento a realizar cuando el nodo solo tiene un solo hijo
void Suprimir(nodo *&);//Procedimiento de eliminacion de un nodo
 
//recorrido en Profundidad
void PreOrden(nodo *&);//mostramos en preorden
void InOrden(nodo *&);//mostramos en inorden
void PostOrden(nodo *&);//mostramos en postorden
 
int main(){
 
	menu();
 
	system("PAUSE");
	return 0;
}
 
//MENU
void menu(){
	int opcion = 0;
 
	while(opcion != 11){
		cout<<"----MENU----"<<endl;
		cout<<"Aprieta 1 para agregar elementos al Arbol."<<endl;
		cout<<"Aprieta 2 para mostrar el Arbol."<<endl;
		cout<<"Aprieta 3 para buscar un elemento."<<endl;
		cout<<"Aprieta 4 para Mostrar el Arbol en PreOrden."<<endl;
		cout<<"Aprieta 5 para Mostrar el Arbol en InOrden."<<endl;
		cout<<"Aprieta 6 para Mostrar el Arbol en PostOrden."<<endl;
		cout<<"Aprieta 7 para saber el menor dato existente dentro del arbol."<<endl;
		cout<<"Aprieta 8 para saber el mayor dato existente dentro del arbol."<<endl;
		cout<<"Aprieta 9 para saber que tipo de hijo es un dato dentro del arbol."<<endl;
		cout<<"Aprieta 10 para eliminar un dato del Arbol."<<endl;
		cout<<"Aprieta 11 para salir."<<endl;
		cout<<"Opcion elegida: "; cin>>opcion;
		system("cls");
 
		Opciones(opcion);
	}
}
 
void Opciones(int &opcion){
	int n;//donde se guarda los datos que usaremos en las diferentes ordenes dadas por el usuario
	int contador;
 
	switch(opcion){
		case 1:
 
			cout<<"Dame la cantidad de elementos que deseas ingresar al arbol: "; cin>>contador;
 
			for(int i = 1;i<=contador;i++){
				cout<<i<<". Dame un numero: "; cin>>n;
				insertar(arbol,n,NULL);
			}
			system("cls");
			break;
 
		case 2:
			cout<<"---------------------------------------"<<endl;
			if(arbol == NULL){
			cout<<"---Arbol Vacio---"<<endl;
			}
			else{
				mostrarArbol(arbol,0);
			}
			cout<<"---------------------------------------"<<endl;
			break;
 
		case 3:
			if(arbol == NULL){
				cout<<"---Arbol Vacio---"<<endl<<endl;
			}
			else{
				cout<<"Dame el Dato que deseas Buscar: "; cin>>n;
				system("cls");
				nodo *a_buscar = BuscarNodo(arbol,n);
 
				if(a_buscar == NULL){
					system("cls");
					cout<<"---Elemento no encontrado---"<<endl<<endl;
				}
				else if(a_buscar == arbol){
					cout<<"---El elemento "<<n<<" Es la Raiz del Arbol---"<<endl<<endl;
				}
				else{
					cout<<" Elemento "<<n<<" encontrado <-"<<endl<<endl;
				}
			}
			break;
 
		case 4:
			if(arbol == NULL){
				cout<<"---Arbol Vacio---"<<endl<<endl;
			}
			else{
			cout<<"-------"<<endl;
			cout<<" | ";
			PreOrden(arbol);
			cout<<endl<<"-------"<<endl<<endl;
			}
			break;
 
		case 5:
			if(arbol == NULL){
				cout<<"---Arbol Vacio---"<<endl<<endl;
			}
			else{
			cout<<"-------"<<endl;
			cout<<" | ";
			InOrden(arbol);
			cout<<endl<<"-------"<<endl<<endl;
			}
			break;
 
		case 6:
			if(arbol == NULL){
				cout<<"---Arbol Vacio---"<<endl<<endl;
			}
			else{
			cout<<"-------"<<endl;
			cout<<" | ";
			PostOrden(arbol);
			cout<<endl<<"-------"<<endl<<endl;
			}
			break;
 
		case 7:
			if(arbol == NULL){
				cout<<"---Arbol Vacio---"<<endl<<endl;
			}
			else{
				nodo *Menor = minimo(arbol);
				cout<<"---El menor elemento dentro del arbol es el "<<Menor->dato<<"---"<<endl<<endl;
			}
			break;
 
		case 8:
			if(arbol == NULL){
				cout<<"---Arbol Vacio---"<<endl<<endl;
			}
			else{
				nodo *Mayor = mayor(arbol);
				cout<<"---El mayor elemento dentro del arbol es el "<<Mayor->dato<<"---"<<endl<<endl;
			}
			break;
 
		case 9:
			if(arbol == NULL){//si el arbol esta vacio
				cout<<"---Arbol Vacio---"<<endl<<endl;
			}
			else{
				cout<<"Dame el dato: "; cin>>n;
				nodo *a_buscar = BuscarNodo(arbol,n);
				system("cls");
 
				if(a_buscar == NULL){//si esta vacio significa que el dato no existe dentro del arbol
				cout<<"---Elemento no encontrado---"<<endl<<endl;
				}
				else{
					if(a_buscar == arbol){//si el nodo a buscar es raiz no tendra padre.
						cout<<"---El elemento "<<n<<" Es la Raiz del Arbol---"<<endl<<endl;
					}
					else{//si no es raiz tiene padre
 
						if(EsHijoDerecho(a_buscar)){//si retorna true es hijo derecho
							cout<<"---El nodo "<<a_buscar->dato<<" es un hijo Derecho---"<<endl<<endl;
						}
						else{//si retorna false es hijo izquierdo
							cout<<"---El nodo "<<a_buscar->dato<<" es un hijo Izquierdo---"<<endl<<endl;
 
						}
					}
				}
			}
			break;
 
		case 10:
			if(arbol == NULL){
				cout<<"---Arbol Vacio---"<<endl<<endl;
			}
			else{
				cout<<"Dame el dato que deseas eliminar: "; cin>>n;
				nodo *a_borrar = BuscarNodo(arbol,n);
				system("cls");
				if(a_borrar == NULL){
					cout<<"---Elemento no encontrado---"<<endl<<endl;
				}
				else{
					BorrarNodo(a_borrar,arbol);
					cout<<"---Elemento "<<n<<" Borrado correctamente---"<<endl<<endl;
				}
 
			}
			break;
 
		case 11:
			cout<<"---Saliendo del Programa---"<<endl<<endl;
			break;
 
		default:
			cout<<"---Opcion elegida inexistente---"<<endl<<endl;
	}
 
}
 
//creacion de datos:
nodo *crear_nodo(int n,nodo *&padre){
	nodo *nuevo_nodo = new nodo();
	nuevo_nodo->dato = n;
	nuevo_nodo->izq = NULL;
	nuevo_nodo->der = NULL;
	nuevo_nodo->padre = padre;
 
	return nuevo_nodo;
}
void insertar(nodo *&arbol,int n,nodo *padre){
	if(arbol == NULL){
		nodo *nuevo_nodo = crear_nodo(n,padre);
		arbol = nuevo_nodo;
	}
	else{
		if(n < arbol->dato){
			insertar(arbol->izq,n,arbol);
		}
		else{
			insertar(arbol->der,n,arbol);
		}
	}
}
//opciones varias:
void mostrarArbol(nodo *&arbol, int cont){
 if(arbol==NULL){
  	return;
 }
 else{
  	mostrarArbol(arbol->der,cont+1);
  	for(int i=0; i<cont;i++){
   	cout<<"   ";
  }
  cout<<arbol->dato<<endl;
  mostrarArbol(arbol->izq,cont+1);
 }
}
nodo* BuscarNodo(nodo *&arbol, int buscado){
 
	if(arbol == NULL or arbol->dato == buscado){
		return arbol;
	}
	if(buscado < arbol->dato){
		cout<<"Izquierda ->";
		BuscarNodo(arbol->izq,buscado);
	}
	else{
		cout<<"Derecha -> ";
		BuscarNodo(arbol->der,buscado);
	}
 
}
nodo *minimo(nodo *arbol){
	while(arbol->izq != NULL){
		arbol = arbol->izq;
	}
	return arbol;
}
nodo *mayor(nodo *arbol){
	while(arbol->der != NULL){
		arbol = arbol->der;
	}
	return arbol;
}
bool EsHijoDerecho(nodo *&hijo){
	if(hijo->padre->der == hijo){
		return true;
	}
	return false;
 
}
//recorrido en Profundidad:
void PreOrden(nodo *&arbol){
	if(arbol == NULL){
		return;
	}
	cout<<arbol->dato<<" | ";
	PreOrden(arbol->izq);
	PreOrden(arbol->der);
}
void InOrden(nodo *&arbol){
	if(arbol == NULL){
		return;
	}
	InOrden(arbol->izq);
	cout<<arbol->dato<<" | ";
	InOrden(arbol->der);
}
void PostOrden(nodo *&arbol){
	if(arbol == NULL){
		return;
	}
	PostOrden(arbol->izq);
	PostOrden(arbol->der);
	cout<<arbol->dato<<" | ";
}
//Borrado de datos:
void BorrarNodo(nodo *&suprimido,nodo *&raiz){
 
	if(suprimido->der == NULL and suprimido->izq == NULL){//si tiene ningun hijo
		Borrado_SinHijos(suprimido,raiz);
	}
 
	else if(suprimido->der != NULL and suprimido->izq != NULL){//si tiene dos hijos
		Borrado_DosHijos(suprimido,raiz);
	}
 
	else if(suprimido->der != NULL){//si tiene solo el hijo derecho
		Borrado_UnHijo(suprimido,suprimido->der,raiz);
	}
 
	else if(suprimido->izq != NULL){//si tiene solo el hijo izquierdo
		Borrado_UnHijo(suprimido,suprimido->izq,raiz);
	}
 
}
void Borrado_SinHijos(nodo *&suprimido,nodo *&raiz){
 
	if(suprimido->padre != NULL){//si el nodo a borrar tiene padre
 
		if(EsHijoDerecho(suprimido)){//si es un hijo derecho
			suprimido->padre->der = NULL;
		}
		else{//si en cambio es un hijo izquierdo
			suprimido->padre->izq = NULL;
		}
 
	}
	else if(raiz == suprimido){//si el nodo a borrar es la raiz
		raiz = NULL;//anulamos a raiz en el caso de que sea el nodo a borrar
	}
 
	Suprimir(suprimido);
 
}
void Borrado_DosHijos(nodo *&suprimido,nodo *&raiz){
 
	nodo *min = minimo(suprimido->der);//buscamos el valor mas cercano al dato a borrar
	suprimido->dato = min->dato;//copiamos el valor encontrado por la funcion minimo hacia el dato que deseamos borrar
	BorrarNodo(min,raiz);//borramos minimo
 
}
void Borrado_UnHijo(nodo *&suprimido,nodo *&hijo,nodo *&raiz){
 
	if(suprimido->padre != NULL){//si el nodo a borrar tiene padre
 
		hijo->padre = suprimido->padre;//al nodo hijo le asignamos como nuevo padre a su "abuelo"
 
		if(EsHijoDerecho(suprimido)){//si es hijo derecho
			suprimido->padre->der = hijo;//al nodo padre le asignamos como nuevo hijo a su "nieto"
		}
		else{//si es hijo izquierdo
			suprimido->padre->izq = hijo;//al nodo padre le asignamos como nuevo hijo a su "nieto"
		}
 
	}
	else if(raiz == suprimido){//si el nodo a borrar es la raiz
		raiz = hijo;//intercambiamos lugares entre raiz/suprimido con hijo
		raiz->padre = NULL;//le ponemos null apadre para convertirlo un una raiz completa(recordemos que estas no tienen padre)
	}
 
	Suprimir(suprimido);
 
}
void Suprimir(nodo *&suprimido){
 
	suprimido->der = NULL;
	suprimido->izq = NULL;
	suprimido->padre = NULL;
	delete suprimido;
	suprimido = NULL;
 
}
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar