INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO GUÍA DE ESTUDIO MODULAR ESTRUCTURA DE DATOS II TERCER NIVEL TECNOLOGÍA EN: INFORMÁTICA MENCIÓN: ANÁLISIS DE SISTEMAS AUTOR: RUDI FRANCISCO PUA Corrección: Comisión de Redacción Aprobado: Vicerrectorado Académico Edición: Instituto Superior Tecnológico “David Ausubel” Periodo Octubre 2015 – abril 2016 QUITO - ECUADOR [email protected] Página 1 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO PARA USTED APRECIADO ESTUDIANTE LA DIRECCCIÓN ACADÉMICA A LA DISTANCIA LE ENVÍA EL MAS CORDIAL SALUDO Y ESPERA QUE EN ESTE MODULO CUMPLA TODAS LAS ESPECTATIVAS PUESTAS EN NOSOTROS. NO OLVIDE QUE EL ESTUDIAR Y TRABAJAR ENGRANDECE AL SER HUMANO Y DE USTED DEPENDE EL ENGRANDECERSE. El Instituto Tecnológico Superior “David Ausubel”, da la bienvenida a este su módulo de ESTRUCTURA DE DATOS II y espera que el desarrollo del mismo aporte para su vida profesional. [email protected] Página 2 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO NOTA: EN ESTE TEXTO GUIA SE ENCUENTRA DESARROLLADOS LOS TEMAS QUE CORRESPONDEN A ESTE MÓDULO, Y LAS TAREAS QUE USTED DEBE DESARROLLAR; CON LA AYUDA DEL TUTOR USTED LLEGARÁ A DOMINAR EL CONOCIMIENTO. 1. EL ESTUDIANTE TIENE LAS OPORTUNIDADES QUE SEAN NECESARIAS PARA ACLARAR LOS TEMAS QUE NO COMPRENDA MEDIANTE LA EXPLICACIÓN DEL TUTOR YA SEA DE MANERA PRESENCIAL O MEDIANTE EL CORREO ELECTRONICO. 2. LAS TAREAS SERAN ENVIADAS POR EL TUTOR, DE ACUERDO A LAS FECHAS DEL CALENDARIO Y DE ACUERDO AL DESARROLLO DEL MÓDULO. 3. ES OBLIGACION DEL ESTUDIANTE ASISTIR A CADA UNA DE LAS TUTORÍAS PRESENCIALES PROGRAMADAS EN EL CALENDARIO DE ACTIVIDADES. 4. TODO TRABAJO DEL ESTUDIANTE SERÁ EVALUADO CUANTITATIVAMENTE. 5. AL FINAL EL TUTOR EVALUARA EL MÓDULO EN SU TOTALIDAD. 6. DE REQUERIR CUALQUIER INFORMACION DIRIGIRSE AL CORREO DE LA DIRECCION ACADEMICA Y SERA ATENDIDO INMEDIATAMENTE EN SU CONSULTA. [email protected] GRACIAS. [email protected] Página 3 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO 1. PERFIL DE INFORMÁTICA MENCIÓN ANÁLISIS DE SISTEMAS a) OBJETIVO DE FORMACIÓN INTEGRAL DEL PROFESIONAL Demostrar en el desempeño profesional de la informática un comportamiento ético que se evidencie en el interés por la investigación e innovación tecnológica, con responsabilidad social, espíritu empresarial y compromiso con el desarrollo sostenido y sustentable del país. b) PERFIL DEL TECNÓLOGO EN INFORMÁTICA Es un profesional capaz de usar herramientas y técnicas para recolectar datos, analizar, diseñar, desarrollar e implementar nuevos sistemas que permitan automatizar los procedimientos de las empresas con fundamentos científicos, tecnológicos, humanísticos y de gestión, demostrando sólidos valores ético-morales. c) COMPETENCIAS PRINCIPALES POR DESARROLLAR Conducir el ciclo de vida de un sistema de información que permita automatizar el manejo de los datos mediante un sistema de computadora, utilizando para ello las diferentes herramientas informáticas existentes en el medio actual. Fundamentar cambios en la estructura organizacional, procedimientos, políticas y funciones de una entidad que permitan optimizar el flujo de datos e información, aumentando con ello la productividad y competitividad y disminuyendo los costos operativos. Administrar las acciones para realizar un correcto análisis, diseño, desarrollo y documentación de los sistemas informáticos de un centro de cómputo, que cubran las expectativas de la institución y del medio en que se desenvuelve. Evaluar y seleccionar hardware y software, fundamentado en cuadros comparativos técnicos que permitan satisfacer los requerimientos de las empresas y organizaciones en general. Analizar de manera independiente e imparcial las bondades o defectos de un sistema de información, mediante la valoración de todos los procesos que intervienen, tomando en cuenta las necesidades y el presupuesto económico. Apoyar la toma de decisiones de la gerencia utilizando métodos matemáticos, estadísticos, modelos de transporte y de investigación de operaciones. SISTEMATIZACIÓN DE LAS COMPETENCIAS POR NIVELES [email protected] Página 4 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO d) NIVEL COMPETENCIA PRINCIPAL Instalar, operar y administrar programas utilitarios conociendo todos los principios de la informática. Programar en lenguajes de tercera generación aplicando técnicas especializadas y con pleno conocimiento de sistemas matemáticos y contables Conocer las acciones requeridas hacia la automatización de las empresas mediante el análisis, diseño, desarrollo, documentación e implementación de los sistemas. Diseñar y administrar Bases de datos, dominando la programación en herramientas de cuarta generación y la programación orientada a objetos. Participar en el diseño de sistemas informáticos interactuando con plataformas de internet y con pleno conocimiento de la administración de las redes y sus sistemas operativos. Administrar las actividades de un departamento de cómputo con la aplicación de herramientas informáticas y gerenciales incluyendo la creación de su propia microempresa. e) ESCENARIOS DE ACTUACIÓN El Tecnólogo en Informática podrá desempeñarse en todo tipo de empresa pública o Privada donde se requiera tratar de una manera especial a los datos y la información que Se generan dentro de la entidad, sea por procesos o por transacciones: ·Instituciones Bancarias Entidades Financieras Empresas Comerciales Empresas del estado Entes de servicio a la comunidad Instituciones de capacitación a nivel profesional, universitario o intermedio Empresas de Asesoría Informática f) OCUPACIONES PROFESIONALES El Tecnólogo en Informática podrá desempeñarse como: Gerente de Sistemas [email protected] Página 5 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO Programador de computadoras Director de grupos de trabajo Administrador de Centros de Cómputo Asistente de gerencia Administrador de Bases de Datos Instructor de personal en el área informática Asesor organizacional de las empresas Asesor en el área informática DESCRIPCIÓN DE LA ASIGNATURA La materia esta orientada en cinco capítulos, los cuales están coordinados para que el estudiante comprenda y relacione cada uno de sus contenidos en pro de una mejor compresión y desarrollo; utilizando las diferentes opciones de programación que nos ofrece el lenguaje de programación C++ y aplicando conceptos de árboles, grafos, matriz dispersa con el fin de enriquecer su creatividad a la hora de aplicar la programación OBJETIVOS DE LA MATERIA GENERAL: Dotar al estudiante de los conocimientos necesarios para realizar programas y consoliden un conocimiento básico en la programación, usando un medio de resolución de problemas mediante técnicas de programación utilizando la herramienta de programación denominada C++. ESPECIFICOS: Lograr que el estudiante adquiera, consolide y demuestre: conocimientos profundos de la metodología de elaboración de programas; particularmente mediante la utilización árboles; desarrollando conocimientos generales y habilidades de conceptualización, compresión de análisis utilizan do Lograr que el estudiante adquiera, consolide y demuestre: conocimientos profundos en el análisis de estructuras; particularmente mediante la utilización de árboles orientados. [email protected] Página 6 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO CONTENIDOS CAPITULO I 1. ARBOLES BINARIOS 1.1 DEFINICIÓN 1.2 LOS ARBOLES TIENEN 3 RECORRIDOS DIFERENTES : 1.2.1 PRE-ORDEN 1.2.2 IN-ORDEN 1.2.3 BUSQUEDA 1.3 ARBOLES EN MONTON 1.3.1 INSERCIÓN 1.3.2 BUSQUEDA 1.3.3 ELIMINACIÓN 1.3.4 RECORRIDO(ORDENADO) 1.4 METODOS DE BUSQUEDAS 1.4.1 BUSQUEDA SECUENCIAL 1.4.2 BUSQUEDA BINARIA 1.4.3 BUSQUEDA POR HASH CAPITULO II 2. MÉTODOS PARA RESOLVER EL PROBLEMA DE LAS COLISIONES 2.1.1 SONDEO LINEAL 2.1.2 DOBLE HASHING 2.2 ORDENAMIENTOS INTERNOS 2.2.1 BURBUJA 2.2.2 SHELLSORT 2.2.3 RADIXSORT 2.2.4 QUICKSORT 2.3 ORDENAMIENTOS EXTERNOS 2.3.1 MEZCLA DIRECTA 2.3.2 MEZCLA NATURAL CAPITULO III 3. GRAFOS 2.1 OPERACIONES SOBRE GRAFOS 2.1.1 ALGORITMOS CREACIÓN 2.1.2 ALGORITMOS INSERCIÓN 2.1.3 ALGORITMOS BUSQUEDA 2.1.4 ALGORITMOS DE BORRADO 2.1.5 CAMINO MÍNIMO 2.2 MATRICES DISPERSAS [email protected] Página 7 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO DESARROLLO DEL CONTENIDO CAPITULO I 1. ARBOLES BINARIOS 1.1 DEFINICIÓN: Un Árbol Binario es un conjunto de finito de Elementos, de nombre Nodos de forma que: El Árbol Binario es Vació si no tiene ningún elemento en el. El Árbol Binario contiene un Nodo Raíz y los dos que parten de él, llamados Nodo Izquierdo y Nodo Derecho. 1.2 LOS ÁRBOLES TIENEN 3 RECORRIDOS DIFERENTES LOS CUALES SON: 1.2.1 Pre-Orden 1.2.1 In-Orden 1.2.3 Búsqueda 1.2.1 PRE-ORDEN Definición: El Recorrido “Pre-Orden” lo recorre de la siguiente manera, viaje a través del Árbol Binario desplegando el Contenido en la Raíz, después viaje a través del Nodo Izquierdo y después a través del Nodo Derecho. Detalle: Temp toma el Valor de la Raíz y compara si el Árbol tiene algún Elemento, de otra manera Desplegara “Árbol Vació…” y terminara el método. Si el Árbol tiene elementos dentro de él, lo recorrerá y viajara a través de los Arreglos Izq. y Der para determinar que valor meter en la Pila y en Temp para de esta manera imprimir el siguiente Elemento correspondiente. Algoritmo: Pre Ord (Árbol, Der, izq., Pila, Raíz) Temp → Raiz Top → [email protected] Página 8 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO Pila [Top] → Nulo Si Raíz = Nulo Imprimir “Árbol Vació…” y Salir Repetir mientras Temp ≠ Nulo Imprimir Árbol [Temp] Si Der [Temp] ≠ Nulo Top → Top + 1 Pila [Top] → Der [Temp] Si izq. [Temp] ≠ Nulo Temp → izq.[Temp] Si no: Temp → Pila [Top]; Top → Top - 1 Fin del ciclo Salir DIAGRAMA: [email protected] Página 9 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO CORRIDA: 1.2.2 IN-ORDEN Definición: El Recorrido “In-Orden” lo recorre de la siguiente manera, viaje a través del Árbol Binario desplegando el Contenido en el Nodo Izquierdo después la Raíz y finalmente viaja a través del Nodo Derecho. Detalle: Temp toma el Valor de la Raíz y compara si el Árbol tiene algún Elemento, de otra manera Desplegara “Árbol Vació…” y terminara el método. Si el Árbol tiene elementos dentro de él, lo recorrerá y viajara a través de los Arreglos izq. y Der para determinar que valor meter en la Pila y en Temp para de esta manera imprimir el siguiente Elemento correspondiente. Algoritmo: Pre Ord (Árbol, Der, izq., Pila, Raíz) Temp → Raiz Top → Pila [Top] → Nulo Si Raíz = Nulo Imprimir “Árbol Vacio…” y Salir Etiqueta: Mientras Temp ≠ Nulo [email protected] Página 10 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO Top → Top + 1 Pila [Top] → Temp Temp → izq. [Temp] Fin del ciclo Temp → Pila [Top] Top → Top - 1 Mientras Temp ≠ Nulo Imprimir Árbol [Temp] Si Der [Temp] ≠ Nulo Temp → Der [Temp] Ir a Etiqueta Temp → Pila [Top] Top → Top - 1 Fin del ciclo Salir DIAGRAMA: [email protected] Página 11 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO CORRIDA: 1.2.3 BÚSQUEDA Definición: La Búsqueda es Similar a todas los Métodos anteriores de Búsqueda, simplemente efectúa un recorrido comparando el Elemento que deseas encontrar contra cada uno de los Elementos en los Arreglos. Detalle: El Algoritmo de Búsqueda compara el Elemento a buscar con cada uno de los datos de nuestro Árbol, compara si el Elemento con el Nodo Raíz, si no se encuentra en la Raíz… compara Elemento contra la Raíz para empezar a viajar por el Árbol respectivamente, usa un método similar al anterior hasta encontrar el Elemento. De otra forma la búsqueda es fallida. Algoritmo: Búsqueda (Árbol, Der, izq., Pila, Raíz, Elemí) Si Raíz = Nulo Imprimir “Árbol Vacío” Pos → Nulo Par → Nulo Regresar Pos y Par Salir Si Elemí = Árbol [Raíz] Imprimir “Elemento Encontrado” Pos → Raíz [email protected] Página 12 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO Par → Nulo Regresar Pos y Par Salir Si Elemí < Árbol [Raíz] Temp → izq. [Raíz] Temp2 → Raíz Si no: Temp → Der [Raíz] Temp2 → Raíz Mientras Temp ≠ Nulo Si Elemí = Árbol [Temp] Imprimir “Elemento Encontrado…” Pos → Temp Par → Temp2 Regresar Pos y Par Salir Si Elemí < Árbol [Temp] Temp2 → Temp Temp → izq. [Temp] Si no: Temp2 → Temp Temp → Der [Temp] Fin del ciclo Imprimir “Elemento no Encontrado…” Pos → Nulo Par → Temp2 Regresar Pos y Par Salir [email protected] Página 13 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO DIAGRAMA: CORRIDA: 1.3 PROGRAMA ARBOLES BINARIOS #incluye <conio.h> #include <iostream.h> class Arbol { private: int Top,Pila[10]; int Info[10],Izq[10],Der[10],Raiz,Disp; public: [email protected] Página 14 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO Arbol() { int in[10]={0,0,0,0,0,0,0,0,0,0}; For (int i=0; i<10; i++) { Info [I] =0; Is [I] =i+1; Der [I] =-999; Pila [I] =0; } Top=0; Dips=0; Raiz=-999; Is [9] =-999; } Void Preorder (void) { In Temp=Raiz; Top=0; Pila [0] =-999; If (Raiz==-999) { Court<<"Arbor Macio..."<<end; Return; } While (Temp! =-999) { Court<<Info [Temp] <<end; If (Der [Temp]! =-999) [email protected] Página 15 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO { Top++; Pila [Top] =Der [Temp]; } If (Is [Temp]! =-999) { Temp=Is [Temp]; } Else { Temp=Pila [Top]; Top--; } } } Void in Ord (void) { In Temp=Raiz, Top=0; Pila [0] =-999; If (Raiz==-999) { Court<<"Arbor Macio..."<<end; Return; } Back: While (Temp! =-999) { Top++; [email protected] Página 16 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO Pila [Top] =Temp; Temp=Is [Temp]; } Temp=Pila [Top]; Top--; While (Temp! =-999) { Court<<Info [Temp] <<end; If (Der [Temp]! =-999) { Temp=Der [Temp]; Got Back; } Temp=Pila [Top]; Top--; } } Void Post Ord (void) { In Temp=Raiz; Top=0; Pila [0] =-999; If (Raiz==-999) { Court<<"Arbor Macio..."<<end; Return; } Back1: While (Temp! =-999) [email protected] Página 17 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO { Top++; Pila [Top] =Temp; If (Der [Temp]! =-999) { Top++; Pila [Top] =-Der [Temp]; } Temp=Is [Temp]; } Temp=Pila [Top]; Top--; While (Temp>=0) { cout<<Info[Temp]<<endl; if(Info[Temp]==Info[Raiz]) return; Temp=Pila[Top]; Top--; } if(Temp<0) { Temp=-Temp; goto Back1; } } void Busqueda(int PosPad[2],int Elem) { int Temp,Temp2; [email protected] Página 18 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO if(Raiz==-999) { PosPad[0]=-999; PosPad[1]=-999; cout<<"Arbol Vacio..."<<endl; return; } if(Elem==Info[Raiz]) { PosPad[0]=Raiz; PosPad[1]=-999; cout<<"Elemento Encontrado..."<<endl; return; } if(Elem<Info[Raiz]) { Temp=Izq[Raiz]; Temp2=Raiz; } else { Temp=Der[Raiz]; Temp2=Raiz; } while(Temp!=-999) { if(Elem==Info[Temp]) { cout<<"Elemento Encontrado..."<<endl; [email protected] Página 19 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO PosPad[0]=Temp; PosPad[1]=Temp2; return; } if(Elem<Info[Temp]) { Temp2=Temp; Temp=Izq[Temp]; } else { Temp2=Temp; Temp=Der[Temp]; } } PosPad[0]=-999; PosPad[1]=Temp2; cout<<"Elemento no Encontrado..."<<endl; } void InsOrd(int Elem) { int PosPad[2],Temp; if(Disp!=-999) { Busqueda(PosPad,Elem); clrscr(); if(PosPad[0]!=-999) { cout<<"Elemento Existente... Imposible Insertar..."<<endl; [email protected] Página 20 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO return; } Temp=Disp; Disp=Izq[Disp]; Info[Temp]=Elem; PosPad[0]=Temp; Izq[Temp]=-999; Der[Temp]=-999; if(PosPad[1]==-999) Raiz=Temp; else if(Elem<Info[PosPad[1]]) Izq[PosPad[1]]=Temp; else Der[PosPad[1]]=Temp; cout<<"Elemento Insertado..."<<endl; return; } cout<<"Arbol Lleno... Imposible Insertar..."<<endl; } void Eliminar(int Elem) { int PosPad[2]; Busqueda(PosPad,Elem); clrscr(); if(PosPad[0]==-999) { cout<<"El Elemento no se Encuentra en el Arbol... Imposible Eliminar..."<<endl; return; } [email protected] Página 21 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO if(Der[PosPad[0]]!=-999&&Izq[PosPad[0]]!=-999) CasoB(PosPad); else CasoA(PosPad); Izq[PosPad[0]]=Disp; Disp=PosPad[0]; } void CasoA(int PosPad[2]) { int Temp; if(Izq[PosPad[0]]==-999&&Der[PosPad[0]]==-999) Temp=-999; else if(Izq[PosPad[0]]!=-999) Temp=Izq[PosPad[0]]; else Temp=Der[PosPad[0]]; if(PosPad[1]!=-999) { if(PosPad[0]==Izq[PosPad[1]]) Izq[PosPad[1]]=Temp; else Der[PosPad[1]]=Temp; } else Raiz=Temp; } void CasoB(int PosPad[2]) { int PosPad2[2],Temp=Der[PosPad[0]],Temp2=PosPad[0]; [email protected] Página 22 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO while(Izq[Temp]!=-999) { Temp2=Temp; Temp=Izq[Temp]; } PosPad2[0]=Temp; PosPad2[1]=Temp2; CasoA(PosPad2); if(PosPad[1]!=-999) { if(PosPad[0]==Izq[PosPad[1]]) Izq[PosPad[1]]=PosPad2[0]; else Der[PosPad[1]]=PosPad2[0]; } else Raiz=PosPad2[0]; Izq[PosPad2[0]]=Izq[PosPad[0]]; Der[PosPad2[0]]=Der[PosPad[0]]; } }tec; main() { int PosPad[2],res,op=0; while(op!=7) { clrscr(); cout<<"\n1) Pre-Orden\n2) In-Orden\n3) Post-Orden\n4) Busqueda\n5) Insercion\n6) Eliminar\n7) Salir"<<endl; [email protected] Página 23 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO gotoxy(1,1); cout<<"Que deseas hacer?: "; cin>>op; gotoxy(1,10); switch (op) { case 1: tec.PreOrd(); break; case 2: tec.InOrd(); break; case 3: tec.PostOrd(); break; case 4: cout<<"Que Numero deseas buscar?"<<endl; cin>>res; tec.Busqueda(PosPad,res); break; case 5: cout<<"Que Numero quieres Insertar?"<<endl; cin>>res; tec.InsOrd(res); break; case 6: cout<<"Que Numero quieres Eliminar?"<<endl; cin>>res; tec.Eliminar(res); [email protected] Página 24 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO break; case 7: cout<<"Salida..."; break; default: cout<<"Opcion Erronea"<<endl; break; } getch(); } } 1.3 ARBOLES EN MONTON Definición: El Árbol en Montón consiste en el ordenamiento de un conjunto de Elemento en un solo arreglo. Trabajaremos sobre la siguientes Operaciones en este Tema: 1.3.1 1.3.2 1.3.3 1.3.4 Inserción Búsqueda Eliminación Recorrido (Ordenado) 1.3.1 Inserción Definición: El Concepto de Inserción ya es familiar para nosotros y sabemos que para realizar el mismo no resulta complejo el procedimiento. Pero en los Árboles en Montón es uno de los Métodos más largos para efectuarlo. Detalle: Básicamente lo que hace estos Algoritmos es la Inserción Ordenada. Primero comparan si es posible insertar algún Elemento al Arreglo, si es posible hacerlo Ingresa el Elemento a la Ultima posición. Después básicamente acomoda el Arreglo con el Método de la Burbuja llamando a otra serie de Métodos. [email protected] Página 25 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO Algoritmos: Insertar(Arbol, N, Elemento) Si N<25 Arbol[N] -> a N -> N + 1 OrdMon(Arbol, N) Salir //Fin de la condición// Imprimir "Árbol Lleno..." Salir OrdMon(Arbol, Total) ConstMon(Arbol, Total) Mientras Total > 1 Total -> Total - 1 Burbuja(0, Total) RecMon(Total, 0) //Fin del ciclo// Salir ConstMon(Arbol, Total) v -> (Total/2) - 1 Mientras v ≥ 0 RecMon(Arbol, Total, v) v -> v - 1 //Fin del ciclo// Salir ---RecMon(Arbol, Total, v) w -> 2*v+1 Mientras w < Total [email protected] Página 26 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO Si (w+1) < Total Si Arbol[w+1] > Arbol[w] w++ //Fin de la condición// Fin de la condición Si Arbol[v] ≥ Arbol[w] Salir //Fin de la condición// Burbuja(Arbol, v, w) v -> w w -> 2*v+1 //Fin del ciclo// Salir ---Burbuja(Arbol, v, w) t -> Arbol[v] Arbol[v] -> Arbol[w] Arbol[w] -> t Salir Diagrama: [email protected] Página 27 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO CORRIDA: 1.3.2 Búsqueda Definición: El Concepto de Búsqueda es sencillo, simplemente es un método de búsqueda lineal. Existen 3 posible resultados: 1. Que el Árbol este Vació y no se puede realizar la búsqueda. 2. Que el Elemento sea encuentre en el Árbol 3. Que el Elemento no este dentro del Árbol Detalle: Se manda al Método Búsqueda el Dato que se desea buscar, se acomoda el Árbol en Orden en caso que no estuviera Ordenado y después compara con cada uno de los datos. Algoritmos: **Busqueda(Arbol, N, Elemento)** Si N ≠ 0 OrdMon(Arbol, N) i -> Mientras i < N;i++) Si Arbol[i] = Elemento Imprimir "Elemento Encontrado..." Salir //Fin de la condición// i -> i + 1 [email protected] Página 28 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO //Fin del ciclo// Imprimir "El Elemento no esta en el Árbol..." Salir //Fin de la condición// Imprimir "Árbol Vació..." Salir DIAGRAMA: CORRIDA: 1.3.3 Eliminación Definición: El Concepto de Eliminación consiste en la búsqueda de un Elemento y sacarlo del Arreglo. Existen 3 casos Diferentes; 1. Que el Árbol este Vació y no se puede realizar la eliminación [email protected] Página 29 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO 2. Que el Elemento sea encuentre en el Árbol y sea eliminado 3. Que el Elemento no este dentro del Árbol por lo tanto no se elimina Detalle: Vemos si el Árbol tiene Elementos insertados en el, de otra forma será imposible realizar la Eliminación ya que esta Vació. Después si el Árbol tiene Elementos lo ordenamos y hacemos un búsqueda lineal para encontrar el dato. Después usamos el método de la Burbuja para dejar el Elemento Eliminado hasta el final y le Restamos a N un Elemento. Algoritmo: Eliminar (Arbol, N, Elemento) Si N ≠ 0 OrdMon (Arbol, N) I -> Mientras I < N Si Arbol[i] = Elemento J -> i + 1 Mientras j < N t -> Arbol[i] Arbol[i] -> Arbol[j] Arbol[j] -> t j -> j + 1 //Fin del ciclo// N -> n - 1 Imprimir "Elemento Eliminado..." Salir //Fin de la condición// i -> i + 1 //Fin del ciclo// Fin de la condición Imprimir "Arbol Vacio... Imposible Eliminar..." Salir [email protected] Página 30 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO DIAGRAMA: CORRIDA: 1.3.4 Recorrido (Ordenado) Definición: El Recorrido simplemente ira desplegando cada uno de los Elementos del Árbol. Solo existen 2 posibles casos: 1. Que el Árbol este Vació y no se pueda recorrer 2. El Árbol tenga Elementos para desplegar Detalle: Comparamos para comprobar que el Árbol tiene Elementos dentro de el, de ser así Desplegamos cada uno de ellos. De otra manera Desplegamos Árbol Vació. Algoritmo: [email protected] Página 31 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO Recorrido(Arbol, N) Si N ≠ 0 i -> Mientras i < N Imprimir Arbol[i] i -> i + 1 //Fin del ciclo// Salir //Fin de la condición// Imprimir "Arbol Vacio..." Salir CORRIDA: PROGRAMA #include <conio.h> #include <iostream.h> class Arbol_Monton { private: int Arbol[25]; int N; public: [email protected] Página 32 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO Arbol_Monton() { for(int i=0;i<25;i++) Arbol[i]=0; N=0; } void Insertar(int a) { if (N<25) { Arbol[N]=a; N++; OrdMon(N); return; } cout<<"Arbol Lleno..."<<endl; } void Eliminar(int a) { int t; if(N!=0) { OrdMon(N); for(int i=0;i<N;i++) { if(Arbol[i]==a) { for(int j=i+1;j<N;j++) { [email protected] Página 33 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO t=Arbol[i]; Arbol[i]=Arbol[j]; Arbol[j]=t; } N--; cout<<"Elemento Eliminado..."<<endl; return; } } } cout<<"Arbol Vacio... Imposible Eliminar..."<<endl; } void Busqueda(int a) { if(N!=0) { OrdMon(N); for(int i=0;i<N;i++) if(Arbol[i]==a) { cout<<"Elemento Encontrado..."<<endl; return; } cout<<"El Elemento no esta en el Arbol..."<<endl; return; } cout<<"Arbol Vacio..."<<endl; } void OrdMon(int n) [email protected] Página 34 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO { ConstMon(n); while(n>1) { n--; Burbuja(0,n); RecMon(n,0); } } void ConstMon(int n) { for(int v=n/2-1;v>=0;v--) RecMon(n,v); } void RecMon(int n,int v) { int w=2*v+1; while(w<n) { if(w+1<n) if (Arbol[w+1]>Arbol[w]) w++; if(Arbol[v]>=Arbol[w]) return; Burbuja(v,w); v=w; w=2*v+1; } } [email protected] Página 35 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO void Burbuja(int i,int j) { int t=Arbol[i]; Arbol[i]=Arbol[j]; Arbol[j]=t; } void Recorrido() { if(N!=0) { for(int i=0;i<N;i++) cout<<Arbol[i]<<endl; return; } cout<<"Arbol Vacio..."<<endl; } }tec; main() { int res,op=0; while(op!=5) { clrscr(); cout<<"\n1) Recorrido\n2) Busqueda\n3) Insercion\n4) Eliminar\n5) Salir"<<endl; gotoxy(1,1); cout<<"Que deseas hacer?: "; cin>>op; gotoxy(1,10); switch (op) [email protected] Página 36 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO { case 1: tec.Recorrido(); break; case 2: cout<<"Que Numero deseas buscar?"<<endl; cin>>res; tec.Busqueda(res); break; case 3: cout<<"Que Numero quieres Insertar?"<<endl; cin>>res; tec.Insertar(res); break; case 4: cout<<"Que Numero quieres Eliminar?"<<endl; cin>>res; tec.Eliminar(res); break; case 5: cout<<"Salida..."; break; default: cout<<"Opcion Erronea"<<endl; break; } getch(); } } [email protected] Página 37 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO 1.4 METODOS DE BUSQUEDAS 1.4.1 BUSQUEDA SECUENCIAL DEFINICION: La búsqueda es el proceso de localizar un registro (elemento) con un valor de llave particular. La búsqueda termina exitosamente cuando se localiza el registro que contenga la llave buscada, o termina sin éxito, cuando se determina que no aparece ningún registro con esa llave. Búsqueda secuencial, también se le conoce como búsqueda lineal. Supongamos una colección de registros organizados como una lista lineal. El algoritmo básico de búsqueda secuencial consiste en empezar al inicio de la lista e ir a través de cada registro hasta encontrar la llave indicada (k), o hasta al final de la lista. La situación óptima es que el registro buscado sea el primero en ser examinado. El peor caso es cuando las llaves de todos los n registros son comparados con k (lo que se busca). El caso promedio es n/2 comparaciones. Este método de búsqueda es muy lento, pero si los datos no están en orden es el único método que puede emplearse para hacer las búsquedas. Si los valores de la llave no son únicos, para encontrar todos los registros con una llave particular, se requiere buscar en toda la lista. MEJORAS EN LA EFICIENCIA DE LA BÚSQUEDA SECUENCIAL 1) MUESTREO DE ACCESO Este método consiste en observar que tan frecuentemente se solicita cada registro y ordenarlos de acuerdo a las probabilidades de acceso detectadas. 2) MOVIMIENTO HACIA EL FRENTE Este esquema consiste en que la lista de registros se reorganice dinámicamente. Con este método, cada vez que búsqueda de una llave sea exitosa, el registro correspondiente se mueve a la primera posición de la lista y se recorren una posición hacia abajo los que estaban antes que el. 3) TRANSPOSICIÓN Este es otro esquema de reorganización dinámica que consiste en que, cada vez que se lleve a cabo una búsqueda exitosa, el registro correspondiente se intercambia con el anterior. Con este procedimiento, entre más accesos tenga el registro, mas rápidamente avanzara hacia la primera posición. Comparado con el método de movimiento al frente, el método requiere más tiempo de actividad para reorganizar al conjunto de registros. Una ventaja de método de transposición es que no permite que el requerimiento aislado de un registro, cambie de posición todo el conjunto de registros. De hecho, un registro debe ganar poco a poco su derecho a alcanzar el inicio de la lista. [email protected] Página 38 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO 4) ORDENAMIENTO Una forma de reducir el numero de comparaciones esperadas cuando hay una significativa frecuencia de búsqueda sin éxito es la de ordenar los registros en base al valor de la llave. Esta técnica es útil cuando la lista es una lista de excepciones, tales como una lista de decisiones, en cuyo caso la mayoría de las búsquedas no tendrán éxito. Con este método una búsqueda sin éxito termina cuando se encuentra el primer valor de la llave mayor que el buscado, en lugar de la final de la lista. Programa: #include <conio.h> #include <iostream.h> class Lista { private: int Lista[10],N; public: Lista() { for(int i=0;i<10;i++) Lista[i]=0; N=0; } void Busqueda(int Elem) { if(N!=0) { for(int i=0;i<N;i++) if(Lista[i]==Elem) { cout<<"El "<<Elem<<" esta en la Lista"<<endl; return; } [email protected] Página 39 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO cout<<"El "<<Elem<<" no esta en la Lista"<<endl; return; } cout<<"Lista Vacia..."<<endl; return; } void Insertar(int Elem) { if(N<10) { Lista[N]=Elem; N++; cout<<"El "<<Elem<<" fue Insertado"<<endl; return; } cout<<"Lista Llena... Imposible Insertar"<<endl; return; } void Eliminar(int Elem) { if(N!=0) { for(int i=0;i<N;i++) if(Lista[i]==Elem) { Lista[i]=0; N--; return; } [email protected] Página 40 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO } cout<<"Lista Vacia... Imposible Eliminar..."<<endl; return; } void Recorrido() { if(N!=0) { for(int i=0;i<N;i++) cout<<Lista[i]<<endl; } cout<<"Lista Vacia..."<<endl; } }tec; main() { int op=0,res; while(op!=5) { clrscr(); cout<<"\n1) Recorrido\n2) Busqueda\n3) Insercion\n4) Eliminar un Dato\n5) Salir"<<endl; gotoxy(1,1); cout<<"Que deseas hacer: "; cin>>op; gotoxy(1,10); switch (op) { case 1: tec.Recorrido(); [email protected] Página 41 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO break; case 2: cout<<"Que Numero de Control deseas buscar?"<<endl; cin>>res; tec.Busqueda(res); break; case 3: cout<<"Que Numero Deseas Insertar?"<<endl; cin>>res; tec.Insertar(res); break; case 4: cout<<"Que Numero de Control deseas Eliminar?"<<endl; cin>>res; tec.Eliminar(res); break; case 5: cout<<"Salida..."; break; default: cout<<"Opcion Erronea"<<endl; break; } getch(); } } [email protected] Página 42 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO CORRIDA: 1.4.2 BÚSQUEDA BINARIA Definicion: Se puede aplicar tanto a datos en listas lineales como en árboles binarios de búsqueda. Los prerrequisitos principales para la búsqueda binaria son: La lista debe estar ordenada en un orden especifíco de acuerdo al valor de la llave. Debe conocerse el número de registros. Algoritmo: Se compara la llave buscada con la llave localizada al centro del arreglo. Si la llave analizada corresponde a la buscada fin de búsqueda si no. Si la llave buscada es menor que la analizada repetir proceso en mitad superior, sino en la mitad inferior. [email protected] Página 43 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO El proceso de partir por la mitad el arreglo se repite hasta encontrar el registro o hasta que el tamaño de la lista restante sea cero, lo cual implica que el valor de la llave buscada no esta en la lista. El esfuerzo máximo para este algoritmo es de log2n. El mínimo de 1 y en promedio ½ log2 n. Programa: #include <conio.h> #include <iostream.h> class Lista { private: int Lista[10],N; public: Lista() { for(int i=0;i<10;i++) Lista[i]=0; N=0; } void Busqueda(int Elem) { if(N!=0) { int inicio=0,medio,final=9; while(inicio<=final) { medio=(inicio+final)/2; if(Elem==Lista[medio]) [email protected] Página 44 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO { cout<<"El "<<Elem<<" esta en la Lista"<<endl; return; } else if(Elem<Lista[medio]) { final=medio-1; } else { inicio=medio+1; } } cout<<"El "<<Elem<<" no esta en la Lista"<<endl; return; } cout<<"Lista Vacia..."<<endl; return; } void Insertar(int Elem) { if(N<10) { Lista[N]=Elem; N++; cout<<"El "<<Elem<<" fue Insertado"<<endl; return; } cout<<"Lista Llena... Imposible Insertar"<<endl; [email protected] Página 45 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO return; } void Eliminar(int Elem) { if(N!=0) { for(int i=0;i<N;i++) if(Lista[i]==Elem) { Lista[i]=0; N--; return; } } cout<<"Lista Vacia... Imposible Eliminar..."<<endl; return; } void Recorrido() { if(N!=0) { for(int i=0;i<N;i++) cout<<Lista[i]<<endl; } cout<<"Lista Vacia..."<<endl; } }tec; main() { [email protected] Página 46 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO int op=0,res; while(op!=5) { clrscr(); cout<<"\n1) Recorrido\n2) Busqueda\n3) Insercion\n4) Eliminar un Dato\n5) Salir"<<endl; gotoxy(1,1); cout<<"Que deseas hacer: "; cin>>op; gotoxy(1,10); switch (op) { case 1: tec.Recorrido(); break; case 2: cout<<"Que Numero de Control deseas buscar?"<<endl; cin>>res; tec.Busqueda(res); break; case 3: cout<<"Que Numero Deseas Insertar?"<<endl; cin>>res; tec.Insertar(res); break; case 4: cout<<"Que Numero de Control deseas Eliminar?"<<endl; cin>>res; tec.Eliminar(res); break; [email protected] Página 47 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO case 5: cout<<"Salida..."; break; default: cout<<"Opcion Erronea"<<endl; break; } getch(); } CORRIDA } 1.4.3 BÚSQUEDA POR HASH Definición: [email protected] Página 48 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO Hasta ahora las técnicas de localización de registros vistas, emplean un proceso de búsqueda que implica cierto tiempo y esfuerzo. El siguiente método nos permite encontrar directamente el registro buscado. La idea básica de este método consiste en aplicar una función que traduce un conjunto de posibles valores llave en un rango de direcciones relativas. Un problema potencial encontrado en este proceso, es que tal función no puede ser uno a uno; las direcciones calculadas pueden no ser todas únicas, cuando R (k1)= R (k2) Pero: K1 diferente de K2 decimos que hay una colisión. A dos llaves diferentes que les corresponda la misma dirección relativa se les llama sinónimos. A las técnicas de cálculo de direcciones también se les conoce como: Técnicas de almacenamiento disperso Técnicas aleatorias Métodos de transformación de llave - a- dirección Técnicas de direccionamiento directo Métodos de tabla Hash Métodos de Hastings Pero el término mas usado es el de Hastings. Al cálculo que se realiza para obtener una dirección a partir de una llave se le conoce como función hash. Ventaja 1. Se pueden usar los valores naturales de la llave, puesto que se traducen internamente a direcciones fáciles de localizar 2. Se logra independencia lógica y física, debido a que los valores de las llaves son independientes del espacio de direcciones 3. No se requiere almacenamiento adicional para los índices. Desventajas 1. 2. 3. 4. No pueden usarse registros de longitud variable El archivo no esta clasificado No permite llaves repetidas Solo permite acceso por una sola llave Costos Tiempo de procesamiento requerido para la aplicación de la función hash Tiempo de procesamiento y los accesos E/S requeridos para solucionar las colisiones. La eficiencia de una función hash depende de: 1. La distribución de los valores de llave que realmente se usan 2. El numero de valores de llave que realmente están en uso con respecto al tamaño del espacio de direcciones [email protected] Página 49 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO 3. El numero de registros que pueden almacenarse en una dirección dad sin causar una colisión 4. La técnica usada para resolver el problema de las colisiones Las funciones hash más comunes son: Residuo de la división Medio del cuadrado Pliegue HASHING POR RESIDUO DE LA DIVISIÓN La idea de este método es la de dividir el valor de la llave entre un numero apropiado, y después utilizar el residuo de la división como dirección relativa para el registro (dirección = llave módulo divisor). Mientras que el valor calculado real de una dirección relativa, dados tanto un valor de llave como el divisor, es directo; la elección del divisor apropiado puede no ser tan simple. Existen varios factores que deben considerarse para seleccionar el divisor: 1) El rango de valores que resultan de la operación “llave % divisor”, va desde cero hasta el divisor 1. Luego, el divisor determina el tamaño del espacio de direcciones relativas. Si se sabe que el archivo va a contener por lo menos n registros, entonces tendremos que hacer que divisor > n, suponiendo que solamente un registro puede ser almacenado en una dirección relativa dada. 2) El divisor deberá seleccionarse de tal forma que la probabilidad de colisión sea minimizada. ¿Como escoger este numero? Mediante investigaciones se ha demostrado que los divisores que son números pares tienden a comportase pobremente, especialmente con los conjuntos de valores de llave que son predominantemente impares. Algunas investigaciones sugieren que el divisor deberá ser un número primo. Sin embargo, otras sugieren que los divisores no primos trabajan también como los divisores primos, siempre y cuando los divisores no primos no contengan ningún factor primo menor de 20. Lo más común es elegir el número primo más próximo al total de direcciones. Ejemplo: Independientemente de que tan bueno sea el divisor, cuando el espacio de direcciones de un archivo está completamente lleno, la probabilidad de colisión crece dramáticamente. La saturación de archivo de mide mediante su factor de carga, el cual se define como la relación del número de registros en el archivo contra el número de registros que el archivo podría contener si estuviese completamente lleno. Todas las funciones hash comienzan a trabajar probablemente cuando el archivo está casi lleno. Por lo general el máximo factor de carga que puede tolerarse en un archivo para un rendimiento razonable es de entre el 70 % y 80 %. HASHING POR MEDIO DEL CUADRADO En esta técnica, la llave es elevada al cuadrado, después algunos dígitos específicos se extraen de la mitad del resultado para constituir la dirección relativa. Si se desea [email protected] Página 50 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO una dirección de n dígitos, entonces los dígitos se truncan en ambos extremos de la llave elevada al cuadrado, tomando n dígitos intermedios. Las mismas posiciones de n dígitos deben extraerse para cada llave. Ejemplo: Utilizando esta función Hastings el tamaño del archivo resultante es de 10n donde n es el número de dígitos extraídos de los valores de la llave elevada al cuadrado. HASHING POR PLIEGUE En esta técnica el valor de la llave es particionada en varias partes, cada una de las cuales (Excepto la última) tiene el mismo número de dígitos que tiene la dirección relativa objetivo. Estas particiones son después plegadas una sobre otra y sumadas. El resultado, es la dirección relativa. Igual que para el método del medio del cuadrado, el tamaño del espacio de direcciones relativas es una potencia de 10. Ejemplo: COMPARACIÓN ENTRE LAS FUNCIONES HASH Aunque alguna otra técnica pueda desempeñarse mejor en situaciones particulares, la técnica del residuo de la división proporciona el mejor desempeño. Ninguna función hash se desempeña siempre mejor que las otras. El método del medio del cuadrado puede aplicarse en archivos con factores de cargas bastantes bajas para dar generalmente un buen desempeño. El método de pliegues puede ser la técnica más fácil de calcular pero produce resultados bastante erráticos, a menos que la longitud de la llave se aproximadamente igual a la longitud de la dirección. Si la distribución de los valores de llaves no es conocida, entonces el método del residuo de la división es preferible. Note que el Hastings puede ser aplicado a llaves no numéricas. Las posiciones de ordenamiento de secuencia de los caracteres en un valor de llave pueden ser utilizadas como sus equivalentes “numéricos”. Alternativamente, el algoritmo hash actúa sobre las representaciones binarias de los caracteres. Todas las funciones hash presentadas tienen destinado un espacio de tamaño fijo. Aumentar el tamaño del archivo relativo creado al usar una de estas funciones, implica cambiar la función hash, para que se refiera a un espacio mayor y volver a cargar el nuevo archivo. [email protected] Página 51 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO CAPITULO II 2. MÉTODOS PARA RESOLVER EL PROBLEMA DE LAS COLISIONES Considere las llaves K1 y K2 que son sinónimas para la función hash R. Si K1 es almacenada primero en el archivo y su dirección es R (K1), entonces se dice que K1 está almacenado en su dirección de origen. Existen dos métodos básicos para determinar dónde debe ser alojado K2 : Direccionamiento abierto.- Se encuentra entre dirección de origen para K2 dentro del archivo. Separación de desborde (Área de desborde).- Se encuentra una dirección para K2 fuera del área principal del archivo, en un área especial de desborde, que es utilizada exclusivamente para almacenar registro que no pueden ser asignados en su dirección de origen Los métodos más conocidos para resolver colisiones son: 2.1.1 SONDEO LINEAL Que es una técnica de direccionamiento abierto. Este es un proceso de búsqueda secuencial desde la dirección de origen para encontrar la siguiente localidad vacía. Esta técnica es también conocida como método de desbordamiento consecutivo. Para almacenar un registro por Hastings con sondeo lineal, la dirección no debe caer fuera del límite del archivo, En lugar de terminar cuando el límite del espacio de dirección se alcanza, se regresa al inicio del espacio y sondeamos desde ahí. Por lo que debe ser posible detectar si la dirección base ha sido encontrada de nuevo, lo cual indica que el archivo está lleno y no hay espacio para la llave. Para la búsqueda de un registro por Hastings con sondeo lineal, los valores de llave de los registros encontrados en la dirección de origen, y en las direcciones alcanzadas con el sondeo lineal, deberá compararse con el valor de la llave buscada, para determinar si el registro objetivo ha sido localizado o no. El sondeo lineal puede usarse para cualquier técnica de Hastings. Si se emplea sondeo lineal para almacenar registros, también deberá emplearse para recuperarlos. 2.1.2 DOBLE HASHING En esta técnica se aplica una segunda función hash para combinar la llave original con el resultado del primer hash. El resultado del segundo hash puede situarse dentro del mismo archivo o en un archivo de sobre flujo independiente; de cualquier modo, será necesario algún método de solución si ocurren colisiones durante el segundo hash. La ventaja del método de separación de desborde es que reduce la situación de una doble colisión, la cual puede ocurrir con el método de direccionamiento abierto, en el cual un registro que no está almacenado en su dirección de origen desplazara a otro [email protected] Página 52 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO registro, el que después buscará su dirección de origen. Esto puede evitarse con direccionamiento abierto, simplemente moviendo el registro extraño a otra localidad y almacenando al nuevo registro en la dirección de origen ahora vacía. Puede ser aplicado como cualquier direccionamiento abierto o técnica de separación de desborde. Para ambas métodos para la solución de colisiones existen técnicas para mejorar su desempeño como: 1.- ENCADENAMIENTO DE SINÓNIMOS Una buena manera de mejorar la eficiencia de un archivo que utiliza el cálculo de direcciones, sin directorio auxiliar para guiar la recuperación de registros, es el encadenamiento de sinónimos. Mantener una lista ligada de registros, con la misma dirección de origen, no reduce el número de colisiones, pero reduce los tiempos de acceso para recuperar los registros que no se encuentran en su localidad de origen. El encadenamiento de sinónimos puede emplearse con cualquier técnica de solución de colisiones. Cuando un registro debe ser recuperado del archivo, solo los sinónimos de la llave objetivo son accesados. 2.- Direccionamiento por cubetas Otro enfoque para resolver el problema de las colisiones es asignar bloques de espacio (cubetas), que pueden acomodar ocurrencias múltiples de registros, en lugar de asignar celdas individuales a registros. Cuando una cubeta es desbordada, alguna nueva localización deberá ser encontrada para el registro. Los métodos para el problema de sobrecupo son básicamente los mismos que los métodos para resolver colisiones. COMPARACIÓN ENTRE SONDEO LINEAL Y DOBLE HASHING De ambos métodos resultan distribuciones diferentes de sinónimos en un archivo relativo. Para aquellos casos en que el factor de carga es bajo (< 0.5), el sondeo lineal tiende a agrupar los sinónimos, mientras que el doble Hastings tiende a dispersar los sinónimos más ampliamente a través del espacio de direcciones. El doble Hastings tiende a comportarse casi también como el sondeo lineal con factores de carga pequeños (< 0.5), pero actúa un poco mejor para factores de carga mayores. Con un factor de carga > 80 %, el sondeo lineal por lo general resulta tener un comportamiento terrible, mientras que el doble Hastings es bastante tolerable para búsquedas exitosas pero no así en búsquedas no exitosas. [email protected] Página 53 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO 2.2 ORDENAMIENTOS INTERNOS Introducción: En esta Unidad explicaremos 4 algoritmos para el Ordenamiento de Arreglos en Memoria RAM. A continuación mencionaremos los diferentes métodos para ordenar: 1. 2. 3. 4. Burbuja ShellSort RadixSort QuickSort 2.2.1 BURBUJA DEFINICIÓN: El método de la burbuja es una comparación lineal con cada uno de los elementos, el elemento que sea menor contra el que se está comparado intercambiaran posiciones. Este método no es recomendado para grandes comparaciones, ya que es un proceso muy lento y requiere de una gran cantidad de Memoria RAM. Programa: #include <conio.h> #include <iostream.h> class Lista { private: int Lista[10],N; public: Lista() { for(int i=0;i<10;i++) Lista[i]=0; N=0; } [email protected] Página 54 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO void Burbuja(void) { if(N!=0) { int i,j,aux; for(i=0;i<9;i++) for(j=i+1;j<10;j++) if(Lista[i]<Lista[j]) { aux=Lista[i]; Lista[i]=Lista[j]; Lista[j]=aux; } cout<<"Lista Ordenada..."<<endl; return; } cout<<"Lista Vacia..."<<endl; } void Busqueda(int Elem) { if(N!=0) { for(int i=0;i<N;i++) if(Lista[i]==Elem) { cout<<"El "<<Elem<<" esta en la Lista"<<endl; return; } } [email protected] Página 55 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO cout<<"Lista Vacia..."<<endl; return; } void Insertar(int Elem) { if(N<10) { Lista[N]=Elem; N++; cout<<"El "<<Elem<<" fue Insertado"<<endl; return; } cout<<"Lista Llena... Imposible Insertar"<<endl; return; } void Eliminar(int Elem) { if(N!=0) { for(int i=0;i<N;i++) if(Lista[i]==Elem) { Lista[i]=0; Burbuja(); N--; return; } } cout<<"Lista Vacia... Imposible Eliminar..."<<endl; [email protected] Página 56 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO return; } void Recorrido() { if(N!=0) { for(int i=0;i<N;i++) cout<<Lista[i]<<endl; } cout<<"Lista Vacia..."<<endl; } }tec; main() { int op=0,res; while(op!=6) { clrscr(); cout<<"\n1) Recorrido\n2) Ordenar\n3) Busqueda\n4) Insercion\n5) Eliminar un Dato\n6) Salir"<<endl; gotoxy(1,1); cout<<"Que deseas hacer: "; cin>>op; gotoxy(1,10); switch (op) { case 1: tec.Recorrido(); break; case 2: [email protected] Página 57 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO tec.Burbuja(); break; case 3: cout<<"Que Numero de Control deseas buscar?"<<endl; cin>>res; tec.Busqueda(res); break; case 4: cout<<"Que Numero Deseas Insertar?"<<endl; cin>>res; tec.Insertar(res); break; case 5: cout<<"Que Numero de Control deseas Eliminar?"<<endl; cin>>res; tec.Eliminar(res); break; case 6: cout<<"Salida..."; break; default: cout<<"Opcion Erronea"<<endl; break; } getch(); } } [email protected] Página 58 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO 2.2.2 SHELLSORT Definición: Esta forma de ordenación es muy parecida a la ordenación con burbuja. La diferencia es que no es una comparación lineal, sino que trabaja con una segmentación entre los datos. Por lo tanto es un buen método, pero no el mejor para implementarlos en grandes arreglos. Programa: #include <conio.h> #include <iostream.h> class Lista { private: int Lista[10],N; public: Lista() { for(int i=0;i<10;i++) Lista[i]=0; N=0; } void ShellSort(void) { if(N!=0) { int salto,aux,i; for(salto=6/2;salto!=0;salto/=2) { for(i=salto;i<6;i++) if(Lista[i-salto]<Lista[i]) { [email protected] Página 59 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO aux=Lista[i]; Lista[i]=Lista[i-salto]; Lista[i-salto]=aux; } } cout<<"Lista Ordenada..."<<endl; return; } cout<<"Lista Vacia..."<<endl; } void Busqueda(int Elem) { if(N!=0) { for(int i=0;i<N;i++) if(Lista[i]==Elem) { cout<<"El "<<Elem<<" esta en la Lista"<<endl; return; } } cout<<"Lista Vacia..."<<endl; return; } void Insertar(int Elem) { if(N<10) { Lista[N]=Elem; [email protected] Página 60 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO N++; cout<<"El "<<Elem<<" fue Insertado"<<endl; return; } cout<<"Lista Llena... Imposible Insertar"<<endl; return; } void Eliminar(int Elem) { if(N!=0) { for(int i=0;i<N;i++) if(Lista[i]==Elem) { Lista[i]=0; ShellSort(); N--; return; } } cout<<"Lista Vacia... Imposible Eliminar..."<<endl; return; } void Recorrido() { if(N!=0) { for(int i=0;i<N;i++) cout<<Lista[i]<<endl; [email protected] Página 61 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO } cout<<"Lista Vacia..."<<endl; } }tec; main() { int op=0,res; while(op!=6) { clrscr(); cout<<"\n1) Recorrido\n2) Ordenar\n3) Busqueda\n4) Insercion\n5) Eliminar un Dato\n6) Salir"<<endl; gotoxy(1,1); cout<<"Que deseas hacer: "; cin>>op; gotoxy(1,10); switch (op) { case 1: tec.Recorrido(); break; case 2: tec.ShellSort(); break; case 3: cout<<"Que Numero de Control deseas buscar?"<<endl; cin>>res; tec.Busqueda(res); break; [email protected] Página 62 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO case 4: cout<<"Que Numero Deseas Insertar?"<<endl; cin>>res; tec.Insertar(res); break; case 5: cout<<"Que Numero de Control deseas Eliminar?"<<endl; cin>>res; tec.Eliminar(res); break; case 6: cout<<"Salida..."; break; default: cout<<"Opcion Erronea"<<endl; break; } getch(); } } 2.2.3 RADIXSORT Definición: Este ordenamiento se basa en los valores de los dígitos reales en las representaciones de posiciones de los números que se ordenan. Es decir… toma un número y lo descompone en sus unidades, decenas, centenas, etc… de esta manera va determinando las posiciones de cada uno de ellos. Programa: #include <math.h> #include <conio.h> [email protected] Página 63 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO #include <iostream.h> class Lista { private: int Lista[10],Temp[10],Elementos,N; public: Lista() { for(int i=0;i<10;i++) Lista[i]=0; N=9; Elementos=0; } void Ordenar() { if(N!=9) { RadixSort(0,Elementos,Lista,Temp); RadixSort(1,Elementos,Temp,Lista); RadixSort(2,Elementos,Lista,Temp); RadixSort(3,Elementos,Temp,Lista); cout<<"Lista Ordenada..."<<endl; return; } cout<<"Lista Vacia..."<<endl; } void RadixSort (int byte, int N, int *fuente, int *dest) { int cont[256]; [email protected] Página 64 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO int ind[256]; int i; memset(cont,0,sizeof(cont)); for(i=0;i<10;i++) cont[((fuente[i])>>(byte*8))&0xff]++; ind[0]=0; for(i=1;i<256;i++) ind[i]=ind[i-1]+cont[i-1]; for(i=0;i<10;i++) dest[ind[((fuente[i])>>(byte*8))&0xff]++]=fuente[i]; } void Busqueda(int Elem) { if(N!=9) { for(int i=0;i<N;i++) if(Lista[i]==Elem) { cout<<"El "<<Elem<<" esta en la Lista"<<endl; return; } } cout<<"Lista Vacia..."<<endl; return; } void Insertar(int Elem) { if(N!=-1) { [email protected] Página 65 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO Elementos++; Lista[N]=Elem; N--; cout<<"El "<<Elem<<" fue Insertado"<<endl; return; } cout<<"Lista Llena... Imposible Insertar"<<endl; return; } void Eliminar(int Elem) { if(N!=9) { for(int i=0;i<N;i++) if(Lista[i]==Elem) { Lista[i]=0; Ordenar(); N++; Elementos--; return; } } cout<<"Lista Vacia... Imposible Eliminar..."<<endl; return; } void Recorrido() { if(N!=9) [email protected] Página 66 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO { for(int i=9;i!=N;i--) cout<<Lista[i]<<endl; return; } cout<<"Lista Vacia..."<<endl; } }tec; main() { int op=0,res; while(op!=6) { clrscr(); cout<<"\n1) Recorrido\n2) Ordenar\n3) Busqueda\n4) Insercion\n5) Eliminar un Dato\n6) Salir"<<endl; gotoxy(1,1); cout<<"Que deseas hacer: "; cin>>op; gotoxy(1,10); switch (op) { case 1: tec.Recorrido(); break; case 2: tec.Ordenar(); break; case 3: cout<<"Que Numero de Control deseas buscar?"<<endl; [email protected] Página 67 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO cin>>res; tec.Busqueda(res); break; case 4: cout<<"Que Numero Deseas Insertar?"<<endl; cin>>res; tec.Insertar(res); break; case 5: cout<<"Que Numero de Control deseas Eliminar?"<<endl; cin>>res; tec.Eliminar(res); break; case 6: cout<<"Salida..."; break; default: cout<<"Opcion Erronea"<<endl; break; } getch(); } } [email protected] Página 68 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO 2.2.4 QUICKSORT Definición: Probablemente este será el mejor de los métodos que mencionamos en esta unidad. Este divide aleatoriamente el arreglo para comparar si un elemento es mayor o menor. Dependiendo el resultado lo partirá ya sea por la izquierda o derecha, de esta forma se repite el procedimiento para ordenarlos. Programa: #include <conio.h> #include <iostream.h> class Lista { private: int Lista[10],N; public: Lista() { for(int i=0;i<10;i++) Lista[i]=0; N=1; } int Dividir(int menor,int mayor) { int izq,dch,temp; izq=menor; dch=mayor; while(izq<dch) { while(Lista[dch]>Lista[menor]) dch--; while((izq<dch)&&(Lista[izq]<=Lista[menor])) [email protected] Página 69 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO izq++; if(izq<dch) { temp=Lista[izq]; Lista[izq]=Lista[dch]; Lista[dch]=temp; } } temp=Lista[dch]; Lista[dch]=Lista[menor]; Lista[menor]=temp; return dch; } void QuickSort(int menor,int mayor) { if(N!=1) { int medio; if(menor<mayor) { medio=Dividir(menor,mayor); QuickSort (menor,medio-1); QuickSort (medio+1,mayor); } cout<<"Lista Ordenada..."<<endl; } cout<<"Lista Vacia..."<<endl; } void Busqueda(int Elem) [email protected] Página 70 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO { if(N!=0) { for(int i=0;i<N;i++) if(Lista[i]==Elem) { cout<<"El "<<Elem<<" esta en la Lista"<<endl; return; } } cout<<"Lista Vacia..."<<endl; return; } void Insertar(int Elem) { if(N<11) { Lista[10-N]=Elem; N++; cout<<"El "<<Elem<<" fue Insertado"<<endl; return; } cout<<"Lista Llena... Imposible Insertar"<<endl; return; } void Eliminar(int Elem) { if(N!=0) { [email protected] Página 71 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO for(int i=0;i<N;i++) if(Lista[i]==Elem) { Lista[i]=0; QuickSort(0,9); N--; return; } } cout<<"Lista Vacia... Imposible Eliminar..."<<endl; return; } void Recorrido() { if(N!=1) { for(int i=1;i!=N;i++) cout<<Lista[10-i]<<endl; } cout<<"Lista Vacia..."<<endl; } }tec; main() { int op=0,res; while(op!=6) { clrscr(); [email protected] Página 72 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO cout<<"\n1) Recorrido\n2) Ordenar\n3) Busqueda\n4) Insercion\n5) Eliminar un Dato\n6) Salir"<<endl; gotoxy(1,1); cout<<"Que deseas hacer: "; cin>>op; gotoxy(1,10); switch (op) { case 1: tec.Recorrido(); break; case 2: tec.QuickSort(0,9); break; case 3: cout<<"Que Numero de Control deseas buscar?"<<endl; cin>>res; tec.Busqueda(res); break; case 4: cout<<"Que Numero Deseas Insertar?"<<endl; cin>>res; tec.Insertar(res); break; case 5: cout<<"Que Numero de Control deseas Eliminar?"<<endl; cin>>res; tec.Eliminar(res); break; case 6: [email protected] Página 73 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO cout<<"Salida..."; break; default: cout<<"Opcion Erronea"<<endl; break; } getch(); } } 2.3 ORDENAMIENTOS EXTERNOS Introducción: En esta Unidad explicaremos 2 algoritmos para el Ordenamiento de Archivos. A continuación mencionaremos los diferentes métodos para ordenar: 1. Mezcla Directa 2. Mezcla Natural 2.3.1 MEZCLA DIRECTA Definición: Este algoritmo consiste en tener un archivo A desordenado. Este archivo se ordenara haciendo los siguientes pasos: 1.- Definir tamaño de tramo igual a 1 2.- Repartir el archivo A en dos archivos B y C escribiendo alternadamente un tramo en cada uno 3.- Aplicar el algoritmo de mezcla simple a cada par de tramos correspondiente de los archivos B y C guardando el resultado en el archivo A 4.- Duplicar el tamaño del tramo 5.- Regresar al paso 2 si el tamaño del tramo es menor que la cantidad de elementos a ordenar Programa: #include <stdio.h> [email protected] Página 74 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO #include <conio.h> #include <stdlib.h> #include <string.h> #include <iostream.h> class Archivos { public: void Mostrar(FILE *fich) { char linea[128]; rewind(fich); fgets(linea, 128, fich); while(!feof(fich)) { puts(linea); fgets(linea, 128, fich); } } void Mezcla(FILE *fich) { int ordenado; FILE *aux[2]; do { aux[0] = fopen("aux1.txt", "w+"); aux[1] = fopen("aux2.txt", "w+"); rewind(fich); Separar(fich, aux); rewind(aux[0]); [email protected] Página 75 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO rewind(aux[1]); rewind(fich); ordenado = Mezclar(fich, aux); fclose(aux[0]); fclose(aux[1]); }while(!ordenado); remove("aux1.txt"); remove("aux2.txt"); } void Separar(FILE *fich, FILE **aux) { char linea[128], anterior[2][128]; int salida = 0; strcpy(anterior[0], ""); strcpy(anterior[1], ""); fgets(linea, 128, fich); while(!feof(fich)) { if(salida == 0 && strcmp(linea, anterior[0]) < 0) salida = 1; else if(salida == 1 && strcmp(linea, anterior[1]) < 0) salida = 0; strcpy(anterior[salida], linea); fputs(linea, aux[salida]); fgets(linea, 128, fich); } } int Mezclar(FILE *fich, FILE **aux) { [email protected] Página 76 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO char ultima[128], linea[2][128], anterior[2][128]; int entrada; int tramos = 0; fgets(linea[0], 128, aux[0]); fgets(linea[1], 128, aux[1]); strcpy(ultima, ""); strcpy(anterior[0], ""); strcpy(anterior[1], ""); while(!feof(aux[0]) && !feof(aux[1])) { if(strcmp(linea[0], linea[1]) <= 0) entrada = 0; else entrada = 1; strcpy(anterior[entrada], linea[entrada]); fputs(linea[entrada], fich); fgets(linea[entrada], 128, aux[entrada]); if(strcmp(anterior[entrada], linea[entrada]) >= 0) { if(!entrada) entrada = 1; else entrada = 0; tramos++; do { strcpy(anterior[entrada], linea[entrada]); fputs(linea[entrada], fich); fgets(linea[entrada], 128, aux[entrada]); [email protected] Página 77 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO }while(!feof(aux[entrada]) && strcmp(anterior[entrada], linea[entrada]) <= 0); } } if(!feof(aux[0])) tramos++; while(!feof(aux[0])) { fputs(linea[0], fich); fgets(linea[0], 128, aux[0]); } if(!feof(aux[1])) tramos++; while(!feof(aux[1])) { fputs(linea[1], fich); fgets(linea[1], 128, aux[1]); } return(tramos == 1); } }tec; main() { FILE *fichero; int res,op=0,b=0; while(op!=3) { clrscr(); cout<<"\n1) Recorrido Desordenado\n2) Recorrido Ordenado\n3) Salir"<<endl; gotoxy(1,1); [email protected] Página 78 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO cout<<"Que deseas hacer?: "; cin>>op; gotoxy(1,10); fichero = fopen("mezcla.txt", "r+"); switch (op) { case 1: if(b!=1) { b=1; tec.Mostrar(fichero); } else cout<<"El Archivo ya esta Ordenado..."<<endl; break; case 2: tec.Mezcla(fichero); tec.Mostrar(fichero); break; case 3: cout<<"Salir..."<<endl; break; default: cout<<"Opcion Erronea..."<<endl; break; } fclose(fichero); getch(); } [email protected] Página 79 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO } 2.3.2 MEZCLA DIRECTA Definición: Es una mejora del algoritmo de mezcla directa puesto que en vez de considerar tramos de tamaño fijo se toman en cuenta para la ordenación en todo momento tramos de longitud máxima. Al igual que la mezcla directa se debe hacer un proceso de partir el archivo original para mezclarlo, posteriormente mientras en el archivo C haya elementos a mezclar. Programa: #include <conio.h> #include <stdio.h> #include <iostream.h> #include <string.h> void mezcla_directa(char *); void mezclar(char *, int ); void partir(char *, int ); void mezcla_simple(char *,char *,char *); void main(){ char n[10]="mezcla.txt"; mezcla_directa(n); getch(); } void mezcla_simple(char *A,char *B,char *C) { FILE *a,*b,*c; int ra,rb; a=fopen(A,"rb"); b=fopen(B,"rb"); c=fopen(C,"rb"); [email protected] Página 80 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO if(a&&b&&c) { fread(&ra,sizeof(ra),1,a); fread(&rb,sizeof(rb),1,b); while(!feof(a)&&!feof(b)) { if(ra<=rb) { fwrite(&ra,sizeof(ra),1,c); fread(&ra,sizeof(ra),1,a); } else { fwrite(&rb,sizeof(rb),1,c); fread(&ra,sizeof(ra),1,b); } } while(!feof(a)) { fwrite(&ra,sizeof(ra),1,c); fread(&ra,sizeof(ra),1,a); } while(!feof(a)) { fwrite(&rb,sizeof(rb),1,c); fread(&rb,sizeof(rb),1,b); } fclose(a); fclose(b); [email protected] Página 81 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO fclose(c); } } void mezcla_directa(char *nom){ int t=1, n=5; FILE *a,*b,*c; a=fopen(nom,"r+"); b=fopen("m1.txt","r+"); c=fopen("m2.txt","r+"); while(t<n){ partir(nom,t); mezcla_simple("m1.txt","m2.txt",nom); mezclar(nom,t); t = t* 2; } } void partir(char *nom, int t){ FILE *a,*b,*c; int reg, cont, sw=1; a=fopen(nom,"r+"); b=fopen("m1.txt","a+"); c=fopen("m2.txt","a+"); if(a&&b&&c){ fread(&reg,sizeof(reg),1,a); while(!feof(a)){ for(cont=0;cont<t && !feof(a);cont++){ if(sw) fwrite(&reg,sizeof(reg),1,b); else [email protected] Página 82 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO fwrite(&reg,sizeof(reg),1,c); fread(&reg,sizeof(reg),1,a); } sw=!sw ; } } fclose(a); fclose(b); fclose(c); } void mezclar(char *nom, int t){ FILE *a,*b,*c; int rb,rc,ctb,ctc; a= fopen(nom,"w+"); b= fopen("m1","r+"); c= fopen("m2","r+"); if(a&&b&&c){ fread(&rb,sizeof(rb),1,b); fread(&rc,sizeof(rb),1,c); while(!feof(b) && !feof(c)){ ctb=ctc=t; while(ctb && ctc && !feof(b) && !feof(c)){ if(rb<rc){ fwrite(&rb,sizeof(rb),1,a); fread(&rb,sizeof(rb),1,b); ctb--; } else{ fwrite(&rc,sizeof(rc),1,a); [email protected] Página 83 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO fread(&rc,sizeof(rc),1,c); ctc--; } } while(ctb && !feof(b)){ fwrite(&rb,sizeof(rb),1,a); fread(&rb,sizeof(rb),1,b); ctb--; } while(ctc && !feof(c)){ fwrite(&rc,sizeof(rc),1,a); fread(&rc,sizeof(rc),1,c); ctc--; } } while(!feof(b)){ fwrite(&rb,sizeof(rb),1,a); fread(&rb,sizeof(rb),1,b); } while(!feof(c)){ fwrite(&rc,sizeof(rc),1,a); fread(&rc,sizeof(rc),1,c); } } fclose(a); fclose(b); fclose(c); remove("m1"); remove("m2"); } [email protected] Página 84 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO CAPITULO III 3. GRAFOS Definición: Un grafo dirigido G consiste en un conjunto de vértices V y un conjunto de arcos o aristas A. Los vértices se denominan también nodos o puntos. Un arco, es un par ordenado de vértices (V, W) donde V es el vértice inicial y W es el vértice terminal del arco. Un arco se expresa como: V–>W y se representa de la siguiente manera: Los vértices de un grafo pueden usarse para representar objetos. Los arcos se utilizan para representar relaciones entre estos objetos. Las aplicaciones más importantes de los grafos son las siguientes: Rutas entre ciudades. Determinar tiempos máximos y mínimos en un proceso. Flujo y control en un programa. 2.1 OPERACIONES SOBRE GRAFOS: En esta sección analizaremos algunas de las operaciones sobre grafos, como: Creación. Inserción. Búsqueda. Eliminación. En esta sección, continuaremos utilizando los apuntadores que se usaron en las secciones anteriores. TOP para hacer referencia al primer nodo, LD para indicar liga derecha y LA para indicar liga abajo, por último usaremos los apuntadores P y Q para hacer referencia a los nuevos nodos que vayan a ser usados. [email protected] Página 85 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO 2.1.1 ALGORITMO DE CREACION. repite si top=NIL entonces new(top) top(la)←NIL top(ld)←NIL lee(top(dato)) q←top en caso contrario new(p) p(ld)←NIL p(la)←NIL q(la)←p lee(p(dato)) q←-p mensaje(otro vertice ?) lee(respuesta) hasta repuesta=no p←top mientras p<>NIL haz mensaje(tiene vértices adyacentes p(dato) ?) lee(respuesta) si respueta=si entonces repite new(q) [email protected] Página 86 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO lee(q(dato)) q(ld)←p(ld) p(ld)←q mensaje(otro vértice ?) lee(respuesta2) hasta respuesta2=no p←p(la) 2.1.2 ALGORITMO DE INSERCION mensaje(valor a insertar ?) lee(valor_a_insertar) si top<>NIL entonces p←top mientras p(la)<>NIL haz p←p(la) new(q) lee(q(dato)) p(la)←q q(la)←NIL mensaje(Hay vértices adyacentes?) lee(respuesta) si respuesta=si entonces mensaje(Cuantos vértices?) lee(número_vértices) desde i=1 hasta número_vértices haz [email protected] Página 87 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO new(p) lee(p(dato)) q(ld)←p q←q(ld) en caso contrario mensaje(no existe lista) 2.1.3 ALGORITMO DE BUSQUEDA mensaje(vértice a buscar) lee(vértice_a_buscar) p←top repite si p(dato)=vértice_a_buscar entonces repite p←p(ld) escribe(p(dato)) hasta p(ld)=NIL en caso contrario p←(la) hasta p=NIL 2.1.4 ALGORITMOS DE BORRADO mensaje(vértice a borrar ?) lee(vértice_a_borrar) [email protected] Página 88 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO p←top r←p q←p sw←falso repite si p(dato)=vértice_a_borrar entonces si p=top entonces top←top(la) r←top sw←verdadero en caso contrario r(la)←p(la) repite p←p(ld) dispose(q) q←p hasta p=NIL si sw=verdadero entonces p←r q←p en caso contrario p←r(la) q←p en caso contrario r←p repite [email protected] Página 89 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO q←p(ld) si q(dato)=vértice_a_borrar entonces p(ld)←q(ld) dispose(q) q←p en caso contrario p←p(ld) hasta p=NIL 2.1.5 CAMINO MÍNIMO: Se denomina camino mínimo entre dos vértices V y W, al camino óptimo entre ambos vértices. Para determinar el camino mínimo entre dos vértices se utiliza el siguiente algoritmo: desde i=1 hasta número_vértices haz desde j=1 hasta número_vértices haz si w[i,j]=0 entonces q[[i,j]←infinito en caso contrario q[i,j]←w[i,j] desde k=1 hasta número_vértices haz desde i=1 hasta número_vértices haz desde j=1 hasta número_vértices haz q[i,j]←min(q[i,j], q[i,k] + q[k,j]) [email protected] Página 90 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO 2.2 MATRICES DISPERSAS La computación paralela es una herramienta esencial para la industria y la investigación, que demandan ingentes cantidades de procesamiento. Entre la gran variedad de campos que requieren computaciones de alto rendimiento, el álgebra lineal es un área de especial interés porque constituye el núcleo computacional de muchos problemas científicos y de ingeniería. Esta tesis se va a centrar en técnicas de paralelización de algoritmos para la factorización de matrices, concretamente para la factorización QR. El ámbito de la tesis es más específico todavía porque nos vamos a limitar a matrices que tienen una gran cantidad de elementos nulos (matrices dispersas). Consideraremos la paralelización de estos algoritmos a nivel de lazo y siguiendo diversos enfoques que van a depender del grado de esfuerzo del programador para desarrollar códigos paralelos. La factorización QR consiste en la descomposición de una matriz A en el producto de dos matrices: Q y R, donde Q es una matriz ortogonal y R una matriz triangular superior. Hemos utilizado los tres métodos habituales que realizan la factorización QR: el algoritmo de Gram-Schmidt modificado (GSM), las transformaciones de Householder y las rotaciones de Givens. Esta factorización, que presenta una buena estabilidad numérica, tiene diversas aplicaciones en álgebra lineal: resolución de sistemas de ecuaciones lineales, problemas de mínimos cuadrados, cálculo de autovalores y autovectores, problemas de optimización, etc. Los algoritmos QR que hemos implementados incorporan un pivotaje por columnas para preservar la estabilidad numérica y para revelar el rango de la matriz a factorizar en el caso de que ésta no tenga rango máximo (QR rankrevealing). En numerosas aplicaciones científicas, la matriz que se va a descomponer es dispersa, es decir, tiene un gran número de ceros. En estas situaciones puede resultar conveniente variar los algoritmos de la QR para tener en cuenta esa característica, con el fin de ahorrar espacio de almacenamiento de las matrices en memoria, así como una gran cantidad de computaciones, ya que éstas se van a realizar solamente con los elementos no nulos. La elección de una estructura de almacenamiento apropiada para la matriz dispersa es muy importante. Durante la factorización de la matriz se produce un llenado (fill-in) de la misma, es decir, se generan nuevos elementos no nulos, por lo que deberemos utilizar estructuras de datos dinámicas. Concretamente, en nuestros algoritmos hemos utilizado listas enlazadas y vectores comprimidos para almacenar la matriz dispersa. Debido a que en estos algoritmos la matriz es accedida por columnas principalmente, las estructuras de datos tienen una orientación por columnas, de tal forma que cada columna de la matriz se va a representar mediante una lista enlazada o un vector comprimido. Uno de los principales inconvenientes de la factorización QR para matrices dispersas es el llenado apuntado anteriormente, que requiere memoria y computaciones para los nuevos elementos. Con el fin de reducir la generación de nuevos elementos no nulos, hemos propuesto una estrategia que aprovecha el pivotaje por columnas. Básicamente, este nuevo criterio consiste en seleccionar como columna pivote aquella que contiene el menor número de elementos no nulos. Para probar esta estrategia, hemos utilizado matrices dispersas de la colección Harwell-Boeing y hemos conseguido reducir su llenado, por término medio, en un 77% para el algoritmo GSM, 65% para Householder y 78% para Givens. También hemos comprobado que el error numérico de los resultados se mantiene utilizando este criterio. Una vez estudiados los algoritmos QR secuenciales y su adaptación para matrices dispersas, abordamos su paralización manual sobre sistemas multiprocesador de [email protected] Página 91 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO memoria distribuida considerando una topología de malla y un paradigma de programación de paso de mensajes. Un factor fundamental en la paralelización es la elección de una distribución adecuada para los datos. Para todos nuestros algoritmos hemos elegido una distribución cíclica de la matriz a factorizar, por filas y por columnas, como si la matriz fuese densa, pero solamente los elementos no nulos son almacenados utilizando las estructuras de datos mencionadas anteriormente. Las ventajas de esta distribución para nuestros algoritmos es que proporciona, en general, un buen equilibrio de los datos y de las computaciones entre los diversos procesadores. Los algoritmos paralelos implantados van a tratar de reducir dos parámetros: las Computaciones locales y las comunicaciones entre procesadores. Con respecto a la reducción de computaciones locales, hemos incorporado a los algoritmos paralelos la estrategia descrita anteriormente para reducir el llenado de la matriz; además, hemos desarrollado operaciones optimizadas entre matrices dispersas y vectores, para distintas estructuras de almacenamiento, con el fin de reducir los tiempos de ejecución. En cuanto a la reducción de comunicaciones, en algunas ocasiones utilizamos replicación de datos (principalmente vectores) sobre los procesadores para favorecer la localidad de las computaciones. También hemos diseñado operaciones optimizadas de reducción y radiación (broadcast) específicas para los algoritmos paralelos con el fin de reducir las latencias de los mensajes enviados entre los procesadores. con la misma finalidad, hemos intentado además agrupar las comunicaciones para tratar de enviar pocos mensajes grandes en vez de muchos mensajes de pequeño tamaño. Por último, proponemos una estrategia de pivotaje local para eliminar las comunicaciones asociadas a esta fase durante la ejecución de los Algoritmos. Los multiprocesadores sobre los que hemos ejecutado los algoritmos paralelos son el Fujitsu AP1000 y el Cray T3D. Estos algoritmos incluyen, además de la factorización QR, su aplicación a la resolución del problema de mínimos cuadrados. El lenguaje de programación es C extendido con la librería de paso de mensajes PVM (Parallel Virtual Machine) en el Cray y con las rutinas nativas CellOS en el AP1000. Los experimentos, con matrices Harwell- Boeing, incluyen tiempos de ejecución, eficiencias, errores numéricos y análisis del llenado de la matriz. Como conclusiones, estos algoritmos presentan unas eficiencias bastante aceptables. Además, los algoritmos paralelos presentan unos errores numéricos similares a los correspondientes algoritmos secuenciales, siendo GSM el algoritmo con mayor error numérico. Los mayores tiempos de ejecución corresponden a la algoritmo de Householder, debido a que presenta un mayor llenado de la matriz mientras que Givens es el más rápido. Las versiones de algoritmos que utilizan vectores comprimidos son más rápidas que las que utilizan listas enlazadas debido a la mayor localidad espacial del vector comprimido. El siguiente paso consiste en aprovechar la experiencia obtenida en la paralelización manual de los algoritmos e incorporar esas técnicas en una librería. Concretamente, hemos desarrollado 3LM (Linked List Management Library), una librería para realizar computaciones con matrices dispersas (principalmente factorizaciones) en paralelo. Su objetivo es ayudar al programador a implementar de forma rápida y sencilla algoritmos dispersos sobre multiprocesadores. La idea básica consiste en que el usuario escribe programas pseudo-secuenciales y la librería se encarga de insertar las comunicaciones necesarias, de forma totalmente transparente al usuario. También se oculta al usuario la estructura interna de los esquemas de almacenamiento de las matrices dispersas, para facilitar su manejo. 3LM está disponible para lenguaje C en un entorno PVM. La librería incorpora un conjunto completo de rutinas para realizar fácilmente distribuciones y redistribuciones de [email protected] Página 92 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO matrices dispersas (utilizando las estructuras de datos dinámicas ya mencionadas), operaciones que soportan el llenado de una matriz, operaciones de reducción predefinidas o definidas por el usuario, rutinas de pivotaje, etc. En el caso de que estas rutinas de alto nivel no sean suficientes para implementar un algoritmo paralelo determinado, 3LM también proporciona un conjunto de rutinas de bajo nivel que permiten acceder directamente a los procesadores de la malla, así como a las estructuras de datos dispersas. Estas rutinas permiten una mayor flexibilidad de programación, pero como contrapartida con más difíciles de programar porque exigen al usuario un conocimiento detallado de la estructura y distribución de los datos, características que ya no son transparentes al programador. Para probar la librería 3LM hemos implementado con sus rutinas de alto nivel los algoritmos para la factorización QR. La reducción del esfuerzo de desarrollo (en número de líneas de código) ha sido enorme con respecto a los códigos manuales anteriormente descritos. Sin embargo, los tiempos de ejecución no son tan buenos debido a que las rutinas de esta librería son genéricas, no son particulares para los algoritmos QR y, obviamente, 3LM no pueden competir con el conocimiento profundo que tiene el programador sobre los algoritmos, conocimiento que le permite desarrollar códigos paralelos manuales muy optimizados. Un paso más adelante en la reducción del esfuerzo de programación de algoritmos dispersos paralelos consiste en la extensión de un lenguaje de paralelismo de datos (data-parallel), para que incorpore estructuras de datos y distribuciones adecuadas para computaciones dispersas. En un paradigma de programación de paralelismo de datos, el usuario escribe un programa secuencial y añade un conjunto de directivas de compilación para ayudar al compilador a generar código paralelo eficiente (paralelización semiautomática). Los lenguajes de paralelismo de datos están orientados principalmente a computaciones con matrices densas y, generalmente, no soportan directivas para optimizar la generación de códigos paralelos para matrices dispersas. Nuestro objetivo es incorporar en el lenguaje de paralelismo de datos estándar HPF (High Performance Fortran), cuyo lenguaje base en Frotran 90, un soporte de códigos dispersos. Para ello, hemos extendido la sintaxis de HPF con una nueva directiva que hemos denominado SPARSE. Mediante esta directiva podremos incorporar en HPF esquemas de almacenamiento apropiados para matrices y vectores dispersos (listas, vectores comprimidos), así como distribuciones de los mismos. La inclusión de la nueva directiva SPARSE supone una extensión de la sintaxis de HPF. Para ello, hemos desarrollado un módulo de compilación que funciona como un preprocesador del código HPF extendido. La función de este módulo va a ser reconocer los objetos (matrices, vectores) definidos por la directiva SPARSE e insertar el soporte de ejecución necesario para realizar las comunicaciones pertinentes en el código paralelo generado. El módulo de compilación se ha diseñado con la herramienta de construcción de compiladores Cocktail. El soporte de ejecución insertado por el módulo de compilación realiza funciones de comunicación asociadas a la distribución y alineamiento de las estructuras de datos dispersas, gestión de entrada/salida de dichas estructuras y comunicaciones necesarias para la obtención de datos no locales. Este soporte de ejecución se ha desarrollado en Frotran 90 como lenguaje base y las rutinas de comunicación SHMEM (Shared Memory), nativas de los multiprocesadores Cray. También se ha desarrollado otra versión utilizando la librería de paso de mensajes estándar MPI (Message Passing Interface) para garantizar la portabilidad del soporte de ejecución. Para comprobar la calidad de nuestro compilador de HPF extendido para computaciones dispersas, hemos utilizado el código paralelo generado por este compilador para algoritmos QR dispersos. Este código se ha ejecutado en un multiprocesador Cray T3E y se obtuvieron unas eficiencias muy buenas del código [email protected] Página 93 INSTITUTO TECNOLÓGICO SUPERIOR “DAVID AUSUBEL” SEMIPRESENCIAL VICERRECTORADO ACADÉMICO paralelo, alcanzando la superlinealidad en algunas ocasiones para un determinado número de procesadores. Estos resultados ratifican la idoneidad de extender el lenguaje HPF con funcionalidades específicas para matrices dispersas. A pesar de todos estos soportes para facilitar la programación de multiprocesadores, los usuarios no expertos en supercomputación demandan herramientas de paralelización automáticas para facilitar todavía más la programación de supercomputadores. Por lo tanto, el paradigma de programación deseable sería que el usuario escribiera programas secuenciales y que un reestructurador de código generara el correspondiente código paralelo de forma totalmente automática. Actualmente existen reestructuradores como SUIF y Polaris que realizan esta labor, basándose en técnicas de análisis de dependencias. Sin embargo, sólo funcionan de forma eficiente para un conjunto determinado de problemas regulares. Su labor se complica enormemente para códigos que utilizan matrices dispersas, debido a la aparición de una gran cantidad de direcciones en el programa que hace muy difícil su análisis. Estas paralelizadas reses automáticas siguen una aproximación conservadora, de tal forma que si tienen duda sobre si un lazo se puede paralelizar, no lo paralelizan. En esta tesis, como introducción a técnicas de paralelización automática, proponemos un par de sencillos test en tiempos de ejecución para detectar paralelismo en códigos que utilizan matrices dispersas. Estos dos test son la prueba de mono tonicidad en los vectores de índices y la prueba de no solapamiento en los rangos de variables de inducción. Estas pruebas son apropiadas para las estructuras de datos comprimidas utilizadas y para los algoritmos de factorización QR, entre otros. La sobrecarga en el tiempo de ejecución de estos test es mínima y sus beneficios son evidentes, ya que permiten detectar automáticamente paralelismo en lazos a priori no paralelizadles. Como conclusiones finales, esta tesis ha descubierto un amplio espectro de técnicas y paradigmas de programación de arquitecturas multiprocesador. Se han realizado diversas aportaciones en el campo de la paralelización manual de algoritmos para matrices dispersas, en la paralelización semiautomáticas a través de la extensión de un lenguaje de paralelismo de datos y en la paralelización automática de códigos dispersos. Para ilustrar estas aportaciones se han utilizado, a lo largo de toda la tesis, algoritmos para la factorización QR, aunque las ideas presentadas podrían aplicarse, sin pérdida de generalidad, a una amplia variedad de algoritmos dispersos. [email protected] Página 94