rboles Introduccin Conjunto finito de nodos que cumple
Árboles • • Introducción Conjunto finito de nodos que cumple 1 - Existe un nodo especial llamado raíz (root) 2 - El resto de nodos están en n (n>= 0) particiones de conjuntos disjuntos T 1, T 2, ……Tn donde cada uno de estos conjuntos es un árbol. T 1, T 2, ……Tn son los subárboles del nodo raíz. • La definición es recursiva • Disjuntos => no puede haber conexiones entre subárboles 12/13/2021 1
Árboles • • Nodo : información + ramas de conexión a otros nodos El número de subárboles es el grado del nodo Las hojas o nodos terminales tienen grado = 0 Los nodos raíz de los subárboles de un nodo X son sus hijos – X es el nodo padre – Los nodos hijos son entre si hermanos (siblings) 12/13/2021 2
Árboles • El grado de un árbol es el grado máximo de sus nodos • Los ancestros de un nodo son todos los nodos que hay en el camino desde el nodo raíz hasta el nodo en cuestión • El nivel de un nodo se define como sigue: – El nivel del nodo raíz es 1 – Si un nodo está en el nivel L, sus hijos están en el nivel L+1 • La altura o profundidad de un árbol es el máximo nivel 12/13/2021 3
root (raiz) Árboles Niveles A branch (rama) B E internal node (nodo interno) F G 2 D C H I 1 J 3 leaf (hoja) K L M 4 Lista ----- (A(B(E(K, L), F), C(G), D(H(M), I, J))) 12/13/2021 4
Árboles A C D G I J H B M F E K 12/13/2021 L 5
Árboles • Es deseable tener una representación específica para árboles • El tamaño de los nodos puede ser variable o fijo • Se suele utilizar tamaño fijo según el grado del árbol Info Hijo 1 Hijo 2 ………. Hijo. N-1 Hijo. N Si T es un árbol de grado k con n nodos de tamaño fijo, => n * ( k - 1 ) + 1 de los n * k campos hijo son 0, n>=1 12/13/2021 6
Árboles • Prueba: • El número de campos hijos distintos de cero en un árbol de n nodos es n - 1 ( cada nodo es referenciado por una conexión excepto el nodo raíz) • El número total de campos hijo en un árbol de grado k con n nodos será n * k • (n * k) - (n - 1) = n * ( k - 1) + 1 12/13/2021 7
Árboles • Representación: Hijo Izquierdo - Hermano Derecho A INFO IZQ. DER. B E K 12/13/2021 F L D C G H I J M 8
Árboles Binarios • Cada nodo puede tener hasta dos ramas K K • Se admite el concepto de árbol binario vacío – Cuando el número de nodos es cero L • Definición: – Conjunto finito de nodos que; o bien está vacío o consiste de un root y dos árboles binarios disjuntos llamados subárbol izquierdo y subárbol derecho 12/13/2021 L 9
Árboles Binarios Propiedades: (1) El número máximo de nodos en el nivel i es (2) El número máximo de nodos en un árbol de profundidad k es (1) Demostración por inducción: si i == 1 => Sea i >=1, suponemos que en el nivel i-1 el número de nodos es Como el grado máximo de cada nodo es 2, el máximo número de nodos en el nivel i es dos veces el máximo número de nodos en el nivel i-1, 12/13/2021 10
Árboles Binarios (2) El máximo número de nodos en un árbol binario de profundidad k será: Por inducción: si i = 1 => suponemos validez para i = n y probaremos para i = n + 1 12/13/2021 11
Árboles Binarios Relación entre el número de nodos de grado 2 y el número de hojas: N 0 = N 2 + 1 N 0: número de hojas, N 2 número de nodos de grado 2 Sea N: número total de nodos y N 1 los de grado 1 N = N 0 + N 1 + N 2 (i) El número de ramas B será igual al número de nodos menos uno (root) => N = B + 1 = N 1 + 2 * N 2 + 1 (ii) (i)-(ii) => 0 = N 0 - N 2 - 1 => N 0 = N 2 + 1; 12/13/2021 12
Árboles Binarios Definición: un árbol binario de profundidad k y N nodos se dice completo si tiene nodos y los nodos están numerados desde 1 a N según la figura La altura H de un árbol 1 binario completo de n nodos es: 3 2 H 4 8 12/13/2021 5 9 10 6 11 12 7 13 14 15 13
Árboles Binarios • Primera aproximación a la clase árbol binario • Conjunto mínimo de operaciones típicas template<class Key. Type> class Binary. Tree { //conjunto finito de nodos: root, left Binary. Tree y rigth Binary. Tree public: Binary. Tree(); //constructor por defecto: árbol vacío bool Is. Empty(); //verdadero si el árbol esta vacío Binary. Tree( Binary. Tree bt 1, Element<Key. Type> item, Binary. Tree bt 2 ); //Crea un árbol con root = ítem y subárboles bt 1 y bt 2 Binary. Tree LChild(); //si no esta vacío retorna el subárbol izquierdo de *this Element<Key. Type> Data(); //retorna el root de *this Binary. Tree RChild(); //si no esta vacío retorna el subárbol derecho de *this }; 12/13/2021 14
Árboles Binarios • Representación mediante vectores de árboles completos: – La posición cero del vector señala el árbol vacío – Para cualquier nodo i; 1 =< i =< n – padre( i ) estará en si i , i = 1 => root – hijoizq( i ) estará en 2 * i si 2 * i =< n – hijoder( i ) estará en 2 * i +1 si 2 * i +1=< n • Si los árboles no son completos se desperdicia espacio 12/13/2021 15
Árboles Binarios • Representación mediante enlaces: – La representación secuencial no es eficiente en las inserciones y borrado de nodos intermedios class Tree; (templates) Data class Tree. Node { friend class Tree; Left. Child Right. Child Tree. Node *Left. Child; Left. Child Data Right. Child char Data; Tree. Node *Right. Child; }; 12/13/2021 16
Árboles Binarios • Representación mediante enlaces: class Tree { public: // operaciones private: Tree. Node *root; }; 12/13/2021 17
Árboles Binarios Representaciones A C B D 0 H 0 12/13/2021 0 E 0 0 I 0 0 F 0 0 G 0 0 1 2 3 4 5 6 7 8 9 --A B C D E F G H I 18
Árboles Binarios • • • Recorridos - Iteradores L: movimiento a la izquierda V: “visitar” el nodo R: movimiento a la derecha Hay seis combinaciones posibles de recorrido – LVR, LRV, VLR, VRL, RVL, RLV – Si optamos por realizar primero el movimiento a izquierda, tenemos las tres primeras posibilidades – LVR inorden, LRV postorden, VLR preorden 12/13/2021 19
Árboles Binarios • Recorridos - Iteradores • Los recorridos se corresponden con las formas infija, postfija y prefija. * Inorden A/B*C*D+E Preorden +**/ABCDE A + E * D C / B Postorden AB/C*D*E+ 12/13/2021 20
Árboles Binarios • Inorden – Descender por la izquierda hasta donde se pueda, visitar el nodo, moverse un nodo a la derecha y continuar. Si no se puede ir a la derecha, volver un nodo hacia atrás. 12/13/2021 21
Árboles Binarios void Tree: : inorder() { inorder( root ); } void Tree: : inorder(Tree. Node *Current. Node) { if(Current. Node){ inorder(Current. Node->Left. Child); cout << Current. Node->Data; inorder(Current. Node->Right. Child); } } 12/13/2021 22
Árboles Binarios • Preorden – Visitar un nodo, descender por la izquierda, así hasta donde se pueda. Cuando no se pueda continuar, moverse a la derecha y comenzar nuevamente o volver hacia atrás hasta que se pueda mover a la derecha y continuar. 12/13/2021 23
Árboles Binarios void Tree: : preorder() { preorder( root); } void Tree: : preorder(Tree. Node *Current. Node) { if(Current. Node){ cout << Current. Node->Data; preorder(Current. Node->Left. Child); preorder(Current. Node->Right. Child); } } 12/13/2021 24
Árboles Binarios • Postorden – Descender por la izquierda, así hasta donde se pueda. Cuando no se pueda continuar, moverse a la derecha hasta que se pueda, visitar el nodo, volver hacia atrás y comenzar nuevamente. 12/13/2021 25
Árboles Binarios void Tree: : postorder() { postorder( root); } void Tree: : postorder(Tree. Node *Current. Node) { if(Current. Node){ postorder(Current. Node->Left. Child); postorder(Current. Node->Right. Child); cout << Current. Node->Data; } } 12/13/2021 26
Árboles void Tree: : No. Rec. Inorder() { stack<Tree. Node *> s; Tree. Node *Current. Node = root; while(true){ while(Current. Node) { s. push(Current. Node); Current. Node = Current. Node->Left. Child; } if(!s. empty()){ Current. Node = s. top(); s. pop(); cout << Current. Node->Data<<endl; Current. Node=Current. Node->Right. Child; }else break; } } 12/13/2021 Binarios 27
void Tree: : Levelorder() { Árboles Binarios queue<Tree. Node *> q; Tree. Node *Current. Node = root; q. push(Current. Node); while(!q. empty()) { Current. Node = q. top(); q. pop(); //q. front() cout << Current. Node->Data<<endl; if(Current. Node->Left. Child) q. push(Current. Node->Left. Child); if(Current. Node->Right. Child) q. push(Current. Node->Right. Child); } } 12/13/2021 28
Árboles Binarios class Inorder. Iterator { public: char * Next(); Inorder. Iterator(Tree tree): t(tree) {Current. Node = t. root; } private: Tree t; stack<Tree. Node *> s; Tree. Node *Current. Node; }; 12/13/2021 29
char *Inorder. Iterator: : Next() { Árboles Binarios while(Current. Node) { s. push(Current. Node); Current. Node = Current. Node->Left. Child; } if(!s. empty()){ Current. Node = s. top(); s. pop(); char& temp = Current. Node->Data; Current. Node=Current. Node->Right. Child; return &temp; }else return 0; } 12/13/2021 30
• Copia Árboles Binarios Tree: : Tree(const Tree& s) { root = copy(s. root); } Tree. Node* Tree: : copy(Tree. Node* orignode) { if(orignode){ Tree. Node *temp = new Tree. Node; temp->Data = orignode->Data; temp->Left. Child = copy(orignode->Left. Child); temp->Right. Child = copy(orignode->Right. Child); return temp; }else return 0; } 12/13/2021 31
Árboles Binarios • Igualdad bool operator==(const Tree& s, const Tree& t){ return equal(s. root, t. root); } bool equal(Tree. Node *a, Tree. Node *b){ if(!a && !b) return 1; if(a && b && (a->Data == b->Data) && equal(a->Left. Child, b->Left. Child) && equal(a->Right. Child , b->Right. Child) ) return 1; return 0; }12/13/2021 32
Árboles Binarios • Árbol de búsqueda: – Cuando los nodos respetan la relación de orden: • El hijo izquierdo de cualquier nodo es menor que su padre y • El hijo derecho es mayor que su padre • Se dice que un árbol binario es balanceado cuando la diferencia de altura de todo par de subárboles es menor o igual que 1 12/13/2021 33
Árboles Binarios • La búsqueda es de complejidad O( ) • La inserción se realiza buscando el valor a insertar y cuando se llega a una hoja (sin haber hallado el valor) se inserta a la izquierda o derecha de ésta. • El borrado depende del grado del nodo a eliminar. 12/13/2021 34
Árboles Binarios de Búsqueda 20 15 12 25 a 40 5 22 10 60 30 70 65 2 b 80 c • Cada nodo tendrá tres campos: Left. Child, Right. Child y data. • data es una clase con al menos un campo key. • La clase árbol binario de búsqueda la llamaremos BST 12/13/2021 35
Árboles de Búsqueda template<class Type> Bst. Node<Type>* BST<Type>: : Search(const Element<Type>& x) { return Search(root, x); } template<class Type> Bst. Node<Type>* BST<Type>: : Search(Bst. Node<Type> *b, const Element<Type>& x) { if(!b) return 0; if(x. key == b->data. key) return b; if(x. key < b->data. key) return Search(b->Left. Child, x); return Search(b->Right. Child, x); } 12/13/2021 36
Árboles de Búsqueda template<class Type> Bst. Node<Type>* BST<Type>: : Iter. Search( const Element<Type>& x) { for(Bst. Node<Type> *t = root; t) { if(x. key == t->data. key) return t; if(x. key < t->data. key) t = t->Left. Child; else t = t->Right. Child; } return 0; } 12/13/2021 37
January February Inserción de los meses según su orden natural March April June August May September July December October November 12/13/2021 38
Árboles de Búsqueda template<class Type> bool BST<Type>: : Insert( const Element<Type>& x) { Inserción Bst. Node<Type> *p= root; Bst. Node<Type> *q=0; while(p){ q=p; if(x. key == p->data. key) return false; if(x. key < p->data. key) p = p->Left. Child; else p = p->Right. Child; } p = new Bst. Node<Type>; p->Left. Child = p->Right. Child = 0; p->data = x; if(!root) root = p; else if(x. key < q->data. key) q->Left. Child = p; else q->Right. Child = p; return true; } 12/13/2021 39
Árboles de Búsqueda Borrado January February April March June August December May September October November 12/13/2021 Eliminado July: grado 0 Se pone a 0 el enlace correspondiente del nodo padre 40
January Árboles de Búsqueda Borrado Eliminados February y May: April March grado 1 August June September December October November 12/13/2021 Se reemplaza el nodo eliminado por su subárbol 41
January April Árboles de Búsqueda Borrado Eliminado March: grado 2 September November August June December October Se debe reemplazar el nodo a eliminar por el nodo mayor de su subárbol izquierdo (predecesor inorden) o por el nodo menor de su subárbol derecho (sucesor inorden). A continuación se elimina el nodo utilizado en el reemplazo que siempre será de grado < 2. 12/13/2021 42
Árboles de Búsqueda Borrado template<class Type> Bst. Node<Type>* BST<Type>: : Iter. Search. Delete(const Element< Type > & x, Bst. Node<Type>*& q) //retorna la dirección del nodo y la dirección del padre (p) { // si no esta retorna 0 Bst. Node<Type> *p= root; while(p){ if(x. key == p->data. key) return p; q=p; if(x. key < p->data. key) p = p->Left. Child; else p = p->Right. Child; } return p; } 12/13/2021 43
Árboles de Búsqueda Borrado template<class Type> bool BST<Type>: : Delete( const Element< Type > & x ) { Bst. Node<Type> *parent=0; Bst. Node<Type>* pos = Iter. Search. Delete(x, parent); if(pos) { remove(pos, parent); delete pos; return true; } else return false; } template<class Type> void BST<Type>: : remove(Bst. Node<Type>* pos, Bst. Node<Type>* parent ) { if(!pos->Left. Child ) // no tiene subárbol izquierdo if(!pos->Right. Child) remove_leaf(pos, parent); // es de grado 0 else remove_right(pos, parent); // grado 1, tiene subárbol derecho else if(!pos->Right. Child) remove_left(pos, parent); // grado 1, tiene subárbol izq. else remove_both(pos, parent); // grado 2 } 12/13/2021 44
Árboles de Búsqueda Borrado template<class Type> void BST<Type>: : remove_leaf(Bst. Node<Type>* pos, Bst. Node<Type>* p) { //el nodo a eliminar tiene grado 0 (hoja) if(pos == root) root = 0; else if (p->Left. Child == pos) p->Left. Child = 0; else p->Right. Child = 0; } 12/13/2021 45
Árboles de Búsqueda Borrado template<class Type> void BST<Type>: : remove_right(Bst. Node<Type>* pos, Bst. Node<Type>* p) {//el nodo a eliminar tiene grado 1(subárbol derecho) Bst. Node<Type>* lr = pos->Right. Child; if(pos == root) root = lr; else if (p->Left. Child == pos) p->Left. Child = lr; else p->Right. Child = lr; } template<class Type> void BST<Type>: : remove_left(Bst. Node<Type>* pos, Bst. Node<Type>* p) {//el nodo a eliminar tiene grado 1 (subárbol izquierdo) Bst. Node<Type>* ll = pos->Left. Child; if(pos == root) root = ll; else if (p->Left. Child == pos) p->Left. Child = ll; else p->Right. Child = ll; } 12/13/2021 46
Árboles de Búsqueda Borrado template<class Type> void BST<Type>: : remove_both(Bst. Node<Type>* pos, Bst. Node<Type>* pa) {//el nodo a eliminar tiene grado 2 Bst. Node<Type>* lr = pos->Right. Child; Bst. Node<Type>* plr = pos->Right. Child; if(!lr->Left. Child)plr = 0; for( ; lr->Left. Child; lr = lr->Left. Child); if(plr) for( ; plr->Left. Child != lr; plr = plr->Left. Child); if(pa){ if (pa->Left. Child == pos) pa->Left. Child = lr; else pa->Right. Child = lr; }else root = lr; //deleting root Bst. Node<key, T>* r = lr->Right. Child; lr->Left. Child = pos->Left. Child; if(pos ->Right. Child != lr) lr->Right. Child = pos-> Right. Child ; if(plr) plr->Left. Child = r; } 12/13/2021 47
Árboles de Búsqueda • Altura: si no se tiene cuidado, la altura de un árbol de búsqueda de n nodos puede llegar a ser n (lista) – Se pierde toda la eficiencia de búsqueda • O(n) – Si las inserciones son aleatorias => O( ) • Los árboles con O( ) se denominan árboles de búsqueda balanceados – Los de mayor utilidad son los AVL, 2 -3 -4, red/black y B-trees 12/13/2021 48
Árboles Enhebrados • En un árbol binario hay más punteros null que punteros a nodos • En un árbol binario de n nodos hay 2 n punteros, de los cuales n+1 son null • Se puede utilizar estos punteros para conseguir ciertas ventajas • Para diferenciarlos de los punteros no null le llamaremos hebras • Existen varias formas de enhebrado. Veremos el inorden 12/13/2021 49
Árboles Enhebrados • La hebras se construyen de la siguiente forma: – Un 0 en un enlace derecho de un nodo p se reemplaza por un puntero al nodo que se visitaría después de p en un recorrido en inorden (sucesor inorden) – Un 0 en un enlace izquierdo de un nodo p se reemplaza por un puntero al nodo que se visitaría antes de p en un recorrido en inorden (predecesor inorden) • Utilizaremos un nodo de cabecera. Será predecesor del primer nodo y el sucesor del último nodo 12/13/2021 50
Árboles Enhebrados root head ----- A C B E D t H tt I t F G Puntero a Nodo Hebra True Left. Child ------ Right. Child False árbol vacío 12/13/2021 51
class Threaded. Node { friend class Threaded. Tree; friend class Threaded. Inorder. Iterator; public: Threaded. Node(char c=‘ ’) : Data(c), Left. Thread(false), Left. Child(0), Right. Thread(false){} private: bool Left. Thread; Threaded. Node *Left. Child; char Data; Threaded. Node *Right. Child; bool Right. Thread; }; 12/13/2021 Árboles Enhebrados class Threaded. Tree { friend class Threaded. Inorder. Iterator; public: Threaded. Tree(){head = new Threaded. Node; } bool empty(); private: Threaded. Node *head; }; bool Threaded. Tree: : empty(){ if(!head || head->Left. Child == head && head->Right. Child ==head) return true; 52
Árboles Enhebrados class Threaded. Inorder. Iterator { public: char * Next(); void Inorder(); Threaded. Inorder. Iterator (Threaded. Tree tree): t(tree) {Current. Node = t. head; } private: Threaded. Tree t; Threaded. Node *Current. Node; }; 12/13/2021 53
Árboles Enhebrados char* Threaded. Inorder. Iterator: : Next() { Threaded. Node *temp = Current. Node->Right. Child; if(! Current. Node->Right. Thread) while(!temp->Left. Thread ) temp = temp->Left. Child; Current. Node = temp; if( Current. Node == t. head) return 0; else return &Current. Node->Data; } void Threaded. Inorder. Iterator: : Inorder() { for( char *ch = Next(); ch = Next() ) cout << *ch << endl; } 12/13/2021 54
Árboles Enhebrados • Para encontrar el sucesor, si su enlace derecho es una hebra, es inmediato, si no lo es, bastará recorrer, a partir de la posición que señala dicho enlace, todos los nodos a su izquierda hasta encontrar la primera hebra • Para encontrar el predecesor, si su enlace izquierdo es una hebra, es inmediato, si no lo es, bastará recorrer, a partir de la posición que señala dicho enlace, todos los nodos a su derecha hasta encontrar la primera hebra 12/13/2021 55
Árboles Enhebrados Threaded. Node *Threaded. Tree: : Inorder. Succ(Threaded. Node *r) { Threaded. Node *temp = r->Right. Child; if(r->Right. Thread) return temp; while(!temp->Left. Thread ) temp = temp->Left. Child; return temp; } Threaded. Node *Threaded. Tree: : Inorder. Pred(Threaded. Node *r) { Threaded. Node *temp = r->Left. Child; if(r->Left. Thread) return temp; while(!temp->Right. Thread ) temp = temp->Right. Child; return temp; } 12/13/2021 56
Árboles Enhebrados void Threaded. Tree: : Inorder(Threaded. Node *head) { Threaded. Node *temp = head; while(true){ temp = Inorder. Succ(temp); if(temp == head) return; else cout << temp->Data << endl; } } 12/13/2021 57
Árboles Enhebrados • La inserción es simple cuando se realiza en la posición que ocupa una hebra • Cuando no se inserta sobre una hebra, se debe encontrar el predecesor ó el sucesor inorden del nodo a partir del que se insertará – El predecesor si la inserción es por la izquierda • se asigna una hebra con la dirección del nuevo nodo, al enlace derecho del predecesor – El sucesor si la inserción es por la derecha • se asigna una hebra con la dirección del nuevo nodo, al enlace izquierdo del sucesor 12/13/2021 58
Árboles Enhebrados void Threaded. Tree: : Insert. Left(Threaded. Node *x, char c) { Threaded. Node *p = new Threaded. Node(c); p->Left. Child = x->Left. Child; x->Left. Child = p; p->Left. Thread = x->Left. Thread; x->Left. Thread = false; p->Right. Child = x; p->Right. Thread = true; if(!p->Left. Thread) { Threaded. Node *aux = Inorder. Pred(p); aux->Right. Child = p; aux->Right. Thread = true; } // Falta contemplar la inserción en un árbol vacío } 12/13/2021 59
Árboles Enhebrados void Threaded. Tree: : Insert. Right(Threaded. Node *x, char c) { Threaded. Node *p = new Threaded. Node(c); p->Right. Child = x->Right. Child; p->Right. Thread = x->Right. Thread; p->Left. Child = x; p->Left. Thread = true; x->Right. Child = p; x->Right. Thread = false; if(!p->Right. Thread) { Threaded. Node * aux = Inorder. Succ(p); aux->Left. Child = p; //Este enlace ya era una hebra }if(p->Right. Child == head) head->Left. Child = p; }// Falta contemplar la inserción en un árbol vacío 12/13/2021 60
Árboles Enhebrados void Threaded. Tree: : Insert. Left. Head(char c) { Threaded. Node *p = new Threaded. Node(c); head->Right. Child = head->Left. Child = p; p->Right. Thread = p->Left. Thread = true; } void Threaded. Tree: : Insert. Right. Head(char c) { Threaded. Node *p = new Threaded. Node(c); head->Right. Child = head->Left. Child = p; p->Right. Thread = p->Left. Thread = true; } 12/13/2021 61
head A A D B C x E G F D B C p x E H G F Inserción a la izquierda de x: el subárbol izquierdo de x está vacío 12/13/2021 62
head x A D B C p E G F A D I B E C G F Inserción a la izquierda de x: el subárbol izquierdo de x es no vacío 12/13/2021 63
Árboles Enhebrados • Ventajas – Las hebras evitan el uso de recursividad o pilas – Recorrido inorden más rápido – Determinación del sucesor y el predecesor inorden muy simple y eficiente. – Mediante otro tipo de enhebrado se pueden conseguir los mismos resultados para otros recorridos • Inconvenientes – No se pueden compartir subárboles – Espacio extra para identificar las hebras – Inserciones y supresiones menos eficientes 12/13/2021 64
HEAP • Árbol binario balanceado y parcialmente ordenado 20 • Todo nodo debe ser mayor 10 que sus hijos • El root será el mayor nodo 15 12 10 8 • Al ser balanceados se puede utilizar la representación secuencial Se puede construir un HEAP a partir de una secuencia de objetos, simplemente reorganizando. La STL provee la el patrón de función make_heap 12/13/2021 65
HEAP Inserción 15 12 9 8 5 2 4 3 8 11 Se realiza al final de la secuencia (balance) y luego mediante intercambios se 11 coloca en la posición correcta (push_heap) 9 5 4 3 5 2 2 12 9 11 12/13/2021 15 15 12 8 4 3 66
HEAP Borrado 2 11 12 11 8 9 12 4 8 9 3 3 5 2 5 4 12 Se retira el root, se lo reemplaza por el mayor de sus hijos y se repite el proceso (pop_heap deja el nodo al final de la secuencia) 9 2 12/13/2021 4 11 8 3 5 67
- Slides: 67