U UUN NNI II V VV E EER RRS SSI II D DDA AA D DD C CCA AA T TT L LL I II C CCA AA D DDE EE S SSA AA N NNT TT A AA M MMA AA R RRI II A AA F FA AC CU UL LT TA AD D D DE E C CI I E EN NC CI I A AS S E E I I N NG GE EN NI I E ER R A A INGENIERADE SISTEMAS LABORATORIO DE ALGORITMOS Y ESTRUCTURA DE DATOS II LISTAS SKIP I OBJETIVOS Explicar el TAD lista skip. Implementar el TAD lista skip. Utilizar el TAD lista skip. para la resolucin de problemas. II TEMAS TAD lista skip Insertar en lista skip Eliminar en lista skip III MARCO TERICO LISTA SKIP (LISTA CON SALTOS) Lista ordenada (y en principio sin claves repetidas) en la que cada nodo puede tener uno o varios enlaces al nodo siguiente y a diversos nodos a distancias variables, bien establecidas de forma aleatoria o siguiendo un patrn establecido de saltos a longitudes fijas. Son estructuras de datos probabilistas. Son una alternativa a los rboles de bsqueda equilibrados (AVL, 2-3, rojinegros,) para almacenar diccionarios de n datos con un coste promedio O(log n) de las operaciones. Son muchos ms fciles de implementar que, por ejemplo, los rboles AVL o los rojinegros. Lista enlazada (ordenada): El coste de una bsqueda en el caso peor es lineal en el nmero de nodos. Aadiendo un puntero a cada nodo par Ahora el nmero de nodos examinados en una bsqueda es, como mucho
1 2 / N . Y aadiendo otro a cada nodo mltiplo de 4 Sesin 1 Mgter. Juan Pablo Apaza Condori 2 Ahora el nmero de nodos examinados en una bsqueda es, como mucho,
2 4 / N Y por fin el caso lmite: cada nodo mltiplo de i 2 apunta al nodo que est i 2 lugares por delante (para todo 0 i ): El nmero total de punteros se ha duplicado (con respecto a la lista enlazada inicial). Ahora el tiempo de una bsqueda est acotado superiormente por
n 2 log , porque la bsqueda consiste en avanzar al siguiente nodo (por el puntero alto) o bajar al nivel siguiente de punteros y seguir avanzando En esencia, se trata de una bsqueda binaria. Problema: la insercin es demasiado difcil. En particular Si llamamos nodo de nivel k al que tiene k punteros, se cumple la siguiente propiedad (ms dbil que la definicin del caso lmite): El puntero i-simo de cualquier nodo de nivel k (k i) apunta al siguiente nodo de nivel i o superior. Adoptamos sta como definicin de lista skip (junto con la decisin aleatoria del nivel de un nuevo nodo). Mgter. Juan Pablo Apaza Condori 3 LISTA SKIP: EJEMPLO LISTA SKIP: BSQUEDA Se empieza en el puntero ms alto de la cabecera. Se contina por ese nivel hasta encontrar un nodo con clave mayor que la buscada (o NIL), entonces se desciende un nivel y se contina de igual forma. Cuando el avance se detiene en el nivel 1, se est frente el nodo con la clave buscada o tal clave no existe en la lista. al gori tmo buscar(l i sta: l i sta_ski p; cl ave_buscada: cl ave) pri nci pi o x: =l i st a. cabecer a; {i nvar i ant e: x. cl ave<cl ave_buscada} par a i : =l i st a. ni vel descendi endo hast a 1 hacer mq x. si g[ i ] . cl ave<cl ave_buscada hacer x: =x. si g[ i ] f mq f par a; {x. cl ave<cl ave_buscadax. si g[ 1] . cl ave} x: =x. si g[ 1] ; si x. cl ave=cl ave_buscada ent devuel ve x. val or si no f r acaso en l a bsqueda f si fi n bool ean buscar(regi ster l i st l , regi ster Ti poCl ave cl ave, Ti poVal or *val orPoi nter) { regi ster i nt k; regi ster pnodo p, q; p =l - >header; k =l - >ni vel ; do { whi l e (q =p- >forward[k], q- >cl ave <cl ave) p =q; k- - ; } whi l e (k>=0); i f (q- >cl ave !=cl ave) return(fal se); *val orPoi nter =q- >val or; / / escri be por ref erenci a el val or asoci ado a l a cl ave return(true); } Mgter. Juan Pablo Apaza Condori 4 EJEMPLO Buscando el 27 PROPUESTOS Busque el 74 Mgter. Juan Pablo Apaza Condori 5 LISTA SKIP: INSERCIN Primero: para insertar un nuevo elemento hay que decidir de qu nivel debe ser. En una lista de las del caso lmite la mitad de los nodos son de nivel 1, una cuarta parte de nivel 2 y, en general, 1/2i nodos son de nivel i. Se elige el nivel de un nuevo nodo de acuerdo con esas probabilidades: se tira una moneda al aire hasta que salga cara, y se elige el nmero total de lanzamientos realizados como nivel del nodo. Distribucin geomtrica de parmetro p =1/2. (En realidad se puede plantear con un parmetro arbitrario, p, y luego seleccionar qu valor de p es ms adecuado) Segundo: hay que saber dnde insertar. Se hace igual que en la bsqueda, guardando traza de los nodos en los que se desciende de nivel. Se determina aleatoriamente el nivel del nuevo nodo y se inserta, enlazando los punteros convenientemente. al gori tmo i nserta(l i sta: l i sta_ski p; c: cl ave; v: val or) var i abl e t r aza: vect or [ 1. . MaxNi vel ] de punt er os pri nci pi o x: =l i st a. cabecer a; para i : =l i sta. ni vel descendi endo hasta 1 hacer mq x. si g[ i ] . cl ave<c hacer x: =x. si g[ i ] f mq; {x. cl ave<cx. si g[ i ] . cl ave} t raza[ i ] : =x fpara; x: =x. si g[ 1] ; si x. cl ave=c ent x. val or : =v si no {i nser ci n} ni vel : =ni vel _al eat ori o; Mgter. Juan Pablo Apaza Condori 6 si ni vel >l i st a. ni vel ent para i : =l i sta. ni vel +1 hasta ni vel hacer t raza[ i ] : =l i st a. cabecer a fpara; l i st a. ni vel : =ni vel f si ; x: =nuevoDat o( ni vel , c, v) ; para i : =1 hasta ni vel hacer x. si g[ i ] : =t r aza[ i ] . si g[ i ] ; t r aza[ i ] . si g[ i ] : =x fpara f si f i n EJEMPLO Insertar el 29 PROPUESTOS Insertar lo siguiente: 30, 5, 18, 25, 50, 34 DESCARTE Es el proceso inverso a la insercin. Se busca el nodo que ser descartado, almacenado en el arreglo auxiliar, las direcciones de los punteros a nodos con claves mayores a las del que ser descartado. Si lo encuentra, copia los punteros hacia delante (los rojos), en los nodos con claves menores al buscado y que fueros marcados en al bsqueda, en las casillas en que salen vnculos azules. Luego de liberar el espacio ocupado por el nodo, es preciso revisar, a partir del la lista de mayor nivel antes de descartar, si qued vaca para ajustar, disminuyendo en uno, el nivel mximo de la lista de saltos. Mgter. Juan Pablo Apaza Condori 7 LISTA SKIP: OBSERVACIONES Se requiere una estimacin a priori del tamao de la lista (igual que en tablas hash) para determinar el nmero de niveles. Si no se dispone de esa estimacin, se puede asumir un nmero grande o usar una tcnica similar al rehashing (reconstruccin). Resultados experimentales muestran que las listas skip son tan eficientes como muchas implementaciones de rboles de bsqueda equilibrados, y son ms fciles de implementar. LISTA SKIP: ELIMINACIN Los pasos para realizar la eliminacin son: 1 Localizar el item con clave K para ser eliminado 2 Sino existe el elemento, retornar no existe la clave K 3 De otra manera eliminar el item K 4 Eliminar tambin todos los tems que se encuentran encima. EJEMPLO Eliminar 18 SOLUCIN PROPUESTOS Eliminar 74, 12, 72, 74 Mgter. Juan Pablo Apaza Condori 8 IV ACTIVIDADES Ejecutar y evaluar la implementacin de listas skip. LISTA SKIP 01: IMPLEMENTACIN EN C/C++ Pruebe el siguiente programa de lista skip: Li st aSk i p.h #i ncl ude "Li staSki p. h" i nt mrandom() { return( (i nt) rand()); } / / se usa el generador al eatori o de l a bi bl i oteca. / / I ni ci o de vari abl es gl obal es. voi d i ni t(voi d) { NI L = newNodeOfLevel (0); NI L- >cl ave = I NT_MAX; / / 0x7fffffff; / / para enteros de 32 bi ts NI L- >val or = 666; / / cual qui er val or. Se i ni ci a pero no se usa. randomBi ts = mrandom(); / / i ni ci a vari abl es del generador. randomsLeft = Bi tsI nRandom/ 2; srand(1); } / / Creador y destructor. l i st newLi st(voi d) { l i st sl ; i nt i ; sl = (l i st)mal l oc(si zeof(struct l i stStructure)); sl ->ni vel = 0; sl ->header = newNodeOfLevel (MaxNumberOfLevel s); sl ->header->cl ave=- I NT_MAX; / / l a dej a en menos i nfi ni to. sl ->header->val or=0; / / No es necesari o i ni ci arl as ya que no se usan l os val ores del header. for(i =0; i <MaxNumberOfLevel s; i ++) sl - >header->forward[i ] =NI L; return(sl ); } voi d freeLi st(l i st sl ) { regi ster pnodo p, q; p = sl - >header; do { q = p->forward[0]; / / pri ntf("%d \ n", p->cl ave); free(p); / / borra l os nodos del ni vel k=0. / / el pri mero que borra es el nodo header. p = q; } whi l e (p!=NI L); free(sl ); / / sol o queda por l i berar el nodo centi nel a. } / / Li stador. Mgter. Juan Pablo Apaza Condori 9 voi d prtLi st(regi ster l i st l ) { regi ster i nt k, cnt, punteros, acum; regi ster pnodo p, q; i nt cl aves[MaxNumberOfLevel s]; k = l - >ni vel ; punteros=0; do { p = l ->header; / / i mpri me nodos de ni vel k i f(k>=0 &&p- >forward[k]!=NI L) pri ntf("k=%d ->", k); cnt=0; whi l e (q = p- >forward[k], q- >cl ave !=I NT_MAX) { p = q; cnt++; punteros++; } i f(cnt==0) pri ntf("Li sta vac a\ n"); el se pri ntf("N=%d \ n", cnt); / / muestra el nmero de nodos en el ni vel k cl aves[k]=cnt; k-- ; } whi l e (k>=0); i f (cnt>0) { for(acum=0, k=l - >ni vel ; k>=0; k-- ) { acum=cl aves[k]; } / / i mpri me nodos en cada ni vel putchar(' \ n' ); } i f(punteros) pri ntf("Punteros por cl ave=%f \ n", (fl oat) punteros/ (fl oat) cnt ); } / / Genera ni vel al eatori o. / / Esta es l a ruti na que al eatori za el al gori tmo. i nt randomLevel (voi d) { regi ster i nt ni vel =0; regi ster i nt b; do { b = randomBi ts&Mascara; / / i nspecci ona l ti mos nbi ts i f (!b) ni vel ++; / / en (1<<nbi ts)- 1 de (1<<nbi ts) casos i ncrementa ni vel randomBi ts>>=nbi ts; randomsLeft-- ; i f (randomsLeft == 0) / / Cuando se acaban, i nvoca al generador { randomBi ts = mrandom(); / / recarga nmero al eatori o randomsLeft = Bi tsI nRandom/ nbi ts; / / rei ni ci a pasadas } }whi l e (!b); Mgter. Juan Pablo Apaza Condori 10 return(ni vel >MaxLevel ? MaxLevel : ni vel ); } / / I nsertar, descartar. #i fdef al l owDupl i cates voi d i nsertar(regi ster l i st l , regi ster Ti poCl ave cl ave, regi ster Ti poVal or val or) #el se bool ean i nsertar(regi ster l i st l , regi ster Ti poCl ave cl ave, regi ster Ti poVal or val or) #endi f { regi ster i nt k; regi ster pnodo p, q; p = l - >header; k = l - >ni vel ; do { whi l e (q = p- >forward[k], q- >cl ave <cl ave) { p = q; / / operador coma. } update[k] =p; / / sal va enl aces haci a al nuevo mul ti nodo k-- ; }whi l e(k>=0); #i fndef al l owDupl i cates i f (q- >cl ave ==cl ave) { q->val or = val or; / / sobreescri be val or. return(fal se); } #endi f k = randomLevel (); / / pri ntf("*%d*\ n", k); i f (k >l ->ni vel ) / / si es mayor sl o aumenta al ni vel si gui ente { k = ++l - >ni vel ; update[k] =l ->header; / / hay que actual i zar el nuevo ni vel } q = newNodeOfLevel (k); q->cl ave =cl ave; q->val or =val or; do { p = update[k]; / / I nserta en todas l as l i stas a parti r de l a k-si ma / / pri ntf(": %d: \ n", k); q->forward[k] =p- >forward[k]; / / pega q con l os proxi mos p->forward[k] =q; / / enl aza q con l os anteri ores k-- ; } whi l e(k>=0); #i fndef al l owDupl i cates return(true); #endi f } bool ean descartar(regi ster l i st l , regi ster Ti poCl ave cl ave) Mgter. Juan Pablo Apaza Condori 11 { regi ster i nt k, m; regi ster pnodo p, q; p = l - >header; k = m=l ->ni vel ; do { whi l e (q = p- >forward[k], q- >cl ave <cl ave) { p = q; } update[k] =p; k-- ; } whi l e(k>=0); i f (q- >cl ave ==cl ave) { for(k=0; k<=m&&(p=update[k])- >forward[k] ==q; k++) p- >forward[k] =q->forward[k]; / / l i ga l as l i stas free(q); i f( l ->header->forward[m] == NI L &&m> 0 ) m- -; / / si l i sta vac a en ni vel m(es i f no whi l e. ) l ->ni vel = m; / / fi j a el ni vel return(true); } el se return(fal se); / / si no encontr l a cl ave } / / Buscar. bool ean buscar(regi ster l i st l , regi ster Ti poCl ave cl ave, Ti poVal or *val orPoi nter) { regi ster i nt k; regi ster pnodo p, q; p = l - >header; k = l - >ni vel ; do { whi l e (q = p- >forward[k], q- >cl ave <cl ave) p = q; k-- ; } whi l e (k>=0); i f (q- >cl ave !=cl ave) return(fal se); *val orPoi nter =q->val or; / / escri be por referenci a el val or asoci ado a l a cl ave return(true); } Mgter. Juan Pablo Apaza Condori 12 Li st aSk i p.c #i ncl ude <stdi o. h> #i ncl ude <stdl i b. h> #i ncl ude <ti me. h> #defi ne fal se 0 #defi ne true 1 typedef char bool ean; #defi ne MaxNumberOfLevel s 16 / / si rve hasta para l og(n)=16 => n=2^16 #defi ne MaxLevel (MaxNumberOfLevel s-1) #defi ne newNodeOfLevel (k) (pnodo)mal l oc(si zeof(nodo)+(k)*si zeof(pnodo )) typedef i nt Ti poCl ave; typedef i nt Ti poVal or; typedef struct nodeStructure { Ti poCl ave cl ave; Ti poVal or val or; / / otro val or al macenado en el nodo. struct nodeStructure *forward[1]; / * arregl o de punteros de l argo vari abl e */ } nodo, *pnodo ; / / La estructura si gui ente agrupa el ni vel de l a l i sta con un puntero al header de l a l i sta de sal tos. typedef struct l i stStructure { i nt ni vel ; / * Ni vel es de l a l i sta */ pnodo header; / * Apunta al nodo de encabezado que conti ene MaxNumberOfLevel s punteros */ } * l i st; / / Vari abl es gl obal es. pnodo NI L; / / apunta a nodo centi nel a #defi ne Bi tsI nRandom15 / / 31 para enteros de 32 #defi ne nbi ts 2 #defi ne Mascara (1<<nbi ts)-1 i nt randomsLeft; / / vari abl es para el generador al eatori o de ni vel es. i nt randomBi ts; pnodo update[MaxNumberOfLevel s]; / / arregl o gl obal para mantener l os enl aces Mgter. Juan Pablo Apaza Condori 13 LISTA SKIP 02: IMPLEMENTACIN EN C/C++ Pruebe el siguiente programa de lista skip: DSL.h #i fndef DSL_H_ #defi ne DSL_H_ #i ncl ude "dsexcepti ons. h" #i ncl ude <i ostream> / / For NULL usi ng namespace std; / / Determi ni sti c ski p l i st cl ass cl ass / / / / CONSTRUCTI ON: wi th I NFI NI TY obj ect that i s / / al so used to si gnal fai l ed fi nds / / / / ******************PUBLI C OPERATI ONS********************* / / voi d i nsert( x ) -- >I nsert x / / voi d remove( x ) -- >Remove x (uni mpl emented) / / Comparabl e fi nd( x ) -- >Return i temthat matches x / / Comparabl e fi ndMi n( ) -->Return smal l est i tem / / Comparabl e fi ndMax( ) -- >Return l argest i tem / / bool ean i sEmpty( ) -- >Return true i f empty; el se fal se / / voi d makeEmpty( ) -- >Remove al l i tems / / voi d pri ntLi st( ) -- >Pri nt i tems i n sorted order / / Node and forward decl arati on because g++does / / not understand nested cl asses. templ ate <cl ass Comparabl e> cl ass DSL; templ ate <cl ass Comparabl e> cl ass Ski pNode { Comparabl e el ement; Ski pNode *ri ght; Ski pNode *down; Ski pNode( const Comparabl e &theEl ement = Comparabl e( ), Ski pNode *rt =NULL, Ski pNode *dt =NULL ) : el ement( theEl ement ), ri ght( rt ), down( dt ) { } fri end cl ass DSL<Comparabl e>; }; templ ate <cl ass Comparabl e> cl ass DSL { publ i c: expl i ci t DSL( const Comparabl e &i nf ); Mgter. Juan Pablo Apaza Condori 14 DSL( const DSL &rhs ); ~DSL( ); const Comparabl e &fi ndMi n( ) const; const Comparabl e &fi ndMax( ) const; const Comparabl e &fi nd( const Comparabl e &x ) const; bool i sEmpty( ) const; voi d pri ntLi st( ) const; voi d makeEmpty( ); voi d i nsert( const Comparabl e &x ); voi d remove( const Comparabl e &x ); const DSL &operator=( const DSL &rhs ); pri vate: const Comparabl e I NFI NI TY; Ski pNode<Comparabl e>*header; / / The l i st Ski pNode<Comparabl e>*bottom; Ski pNode<Comparabl e>*tai l ; const Comparabl e &el ementAt( Ski pNode<Comparabl e> * t ) const; / / Usual recursi ve stuff voi d recl ai mMemory( Ski pNode<Comparabl e>*t ) const; }; #i ncl ude "DSL. cpp" #endi f Mgter. Juan Pablo Apaza Condori 15 DSL.c pp #i ncl ude "DSL. h" / ** * Construct the tree. * i nf i s the l argest Comparabl e * and i s used to si gnal fai l ed fi nds. */ templ ate <cl ass Comparabl e> DSL<Comparabl e>: : DSL( const Comparabl e &i nf ) : I NFI NI TY( i nf ) { bottom= newSki pNode<Comparabl e>( ); bottom->ri ght = bottom->down =bottom; tai l = newSki pNode<Comparabl e>( I NFI NI TY ); tai l ->ri ght =tai l ; header = newSki pNode<Comparabl e>( I NFI NI TY, tai l , bottom); } / ** * Copy constructor. * Left as an exerci se. */ templ ate <cl ass Comparabl e> DSL<Comparabl e>: : DSL( const DSL<Comparabl e> &rhs ) : I NFI NI TY( rhs. I NFI NI TY) { cout <<"Copy constructor i s uni mpl emented" << endl ; } / ** * Destructor. */ templ ate <cl ass Comparabl e> DSL<Comparabl e>: : ~DSL( ) { makeEmpty( ); del ete header; del ete tai l ; del ete bottom; } / ** * I nsert i temx i nto the DSL. */ templ ate <cl ass Comparabl e> voi d DSL<Comparabl e>: : i nsert( const Comparabl e &x ) { Ski pNode<Comparabl e>*current =header; bottom->el ement =x; whi l e( current !=bottom) { whi l e( current- >el ement < x ) current =current->ri ght; Mgter. Juan Pablo Apaza Condori 16 / / I f gap si ze i s 3 or at bottoml evel and / / must i nsert, then promote mi ddl e el ement i f( current- >down->ri ght- >ri ght->el ement < current->el ement ) { current- >ri ght = newSki pNode<Comparabl e>( current->el ement, current->ri ght, current->down->ri ght->ri ght ); current- >el ement = current->down->ri ght->el ement; } el se current =current->down; } / / Rai se hei ght of DSL i f necessary i f( header->ri ght !=tai l ) header =newSki pNode<Comparabl e>( I NFI NI TY, tai l , header ); } / ** * Remove i temx fromthe DSL. Uni mpl emented. */ templ ate <cl ass Comparabl e> voi d DSL<Comparabl e>: : remove( const Comparabl e &x ) { cout <<"Sorry, remove uni mpl emented; " <<x << " sti l l present" << endl ; } / ** * Fi nd the smal l est i temi n the tree. * Return smal l est i temor I NFI NI TY i f empty. */ templ ate <cl ass Comparabl e> const Comparabl e &DSL<Comparabl e>: : fi ndMi n( ) const { i f( i sEmpty( ) ) return I NFI NI TY; Ski pNode<Comparabl e>*current =header; whi l e( current->down !=bottom) current =current->down; return el ementAt( current ); } / ** * Fi nd the l argest i temi n the tree. * Return the l argest i temor I NFI NI TY i f empty. */ templ ate <cl ass Comparabl e> const Comparabl e &DSL<Comparabl e>: : fi ndMax( ) const { i f( i sEmpty( ) ) return I NFI NI TY; Ski pNode<Comparabl e>*current =header; Mgter. Juan Pablo Apaza Condori 17 for( ; ; ) i f( current->ri ght- >ri ght !=tai l ) current = current- >ri ght; el se i f( current->down !=bottom) current = current- >down; el se return el ementAt( current ); } / ** * Fi nd i temx i n the tree. * Return the matchi ng i temor I NFI NI TY i f not found. */ templ ate <cl ass Comparabl e> const Comparabl e &DSL<Comparabl e>: : fi nd( const Comparabl e &x ) const { Ski pNode<Comparabl e>*current =header; bottom->el ement =x; for( ; ; ) i f( x <current->el ement ) { cout<<"| "<<current->el ement; current =current->down; } el se i f( current- >el ement < x ) { cout<<"- -"<<current->el ement; current =current->ri ght; } el se return el ementAt( current ); } / ** * Make the tree l ogi cal l y empty. */ templ ate <cl ass Comparabl e> voi d DSL<Comparabl e>: : makeEmpty( ) { recl ai mMemory( header ); header->ri ght = tai l ; header->down = bottom; } / ** * Test i f the tree i s l ogi cal l y empty. * Return true i f empty, fal se otherwi se. */ templ ate <cl ass Comparabl e> bool DSL<Comparabl e>: : i sEmpty( ) const { return header- >ri ght ==tai l &&header->down == bottom; } Mgter. Juan Pablo Apaza Condori 18 / ** * I nternal method to get el ement fi el d fromnode t. * Return the el ement fi el d or I NFI NI TY i f t i s at the bottom. */ templ ate <cl ass Comparabl e> const Comparabl e &DSL<Comparabl e>: : el ementAt( Ski pNode<Comparabl e> *t ) const { i f( t == bottom) return I NFI NI TY; el se return t->el ement; } / ** * Pri nt the DSL. */ templ ate <cl ass Comparabl e> voi d DSL<Comparabl e>: : pri ntLi st( ) const { Ski pNode<Comparabl e>*current =header; whi l e( current->down !=bottom) { / / cout << current- >el ement <<endl ; current =current->down; } whi l e( current->ri ght != tai l ) { cout <<current->el ement <<endl ; current =current->ri ght; } } / ** * Deep copy. Left as an exerci se */ templ ate <cl ass Comparabl e> const DSL<Comparabl e>& DSL<Comparabl e>: : operator=( const DSL<Comparabl e> &rhs ) { i f( thi s !=&rhs ) cout <<"Sorry, operator= i s uni mpl emented" << endl ; return *thi s; } / ** * recl ai mMemory i s l eft as an exerci se. * Hi nt: del ete fromtop l evel to bottoml evel . */ templ ate <cl ass Comparabl e> voi d DSL<Comparabl e>: : recl ai mMemory( Ski pNode<Comparabl e>*t ) const Mgter. Juan Pablo Apaza Condori 19 { i f( t != bottom) cout <<"recl ai mMemory i s uni mpl emented -- l eaki ng!" << endl ; } Mgter. Juan Pablo Apaza Condori 20 V EJERCICIOS 1 Modifique el programa de Listas Skip para mostrar el siguiente resultado. 2 Modifique el programa de Listas Skip para mostrar el siguiente resultado. 3 Modifique el programa para que genere 4 o ms niveles con valores menores a 100. 4 Agregue al programa de listas skip la opcin de mostrar todos los nodos de un determinado nivel. 5 Agregue al programa de listas skip la opcin de mostrar todos los nodos del nivel ms bajo y del ms alto.