






























Prepara tus exámenes y mejora tus resultados gracias a la gran cantidad de recursos disponibles en Docsity
Gana puntos ayudando a otros estudiantes o consíguelos activando un Plan Premium
Prepara tus exámenes
Prepara tus exámenes y mejora tus resultados gracias a la gran cantidad de recursos disponibles en Docsity
Prepara tus exámenes con los documentos que comparten otros estudiantes como tú en Docsity
Encuentra los documentos específicos para los exámenes de tu universidad
Estudia con lecciones y exámenes resueltos basados en los programas académicos de las mejores universidades
Responde a preguntas de exámenes reales y pon a prueba tu preparación
Consigue puntos base para descargar
Gana puntos ayudando a otros estudiantes o consíguelos activando un Plan Premium
Comunidad
Pide ayuda a la comunidad y resuelve tus dudas de estudio
Ebooks gratuitos
Descarga nuestras guías gratuitas sobre técnicas de estudio, métodos para controlar la ansiedad y consejos para la tesis preparadas por los tutores de Docsity
Programacion en C++ ejercicios practicos
Tipo: Apuntes
1 / 38
Esta página no es visible en la vista previa
¡No te pierdas las partes importantes!































El que no sabe por qué camino llegar al mar debe buscar el río por compañero. Plauto Búsqueda y ordenamiento constituyen dos tareas fundamentales en la administración de datos, especialmente si se trata de grandes volúmenes. Las dos operaciones se desarrollan con base en un dato de referencia al que comúnmente se llama clave. La búsqueda permite encontrar un elemento particular en el conjunto, mientras que el ordenamiento consiste en ubicar los datos atendiendo a un criterio de manera que sea más fácil encontrar el elemento que se requiere o identificar las relaciones entre los datos. En este capítulo se estudian y explican detalladamente los algoritmos de búsqueda y ordenamiento, apoyados con ejemplos y gráficas que facilitan su comprensión. 7.1 ALGORITMOS DE BÚSQUEDA La búsqueda es una operación de vital importancia cuando se manipulan grandes conjuntos de datos donde localizar un elemento no es tarea fácil, como afirman Lopez, Jeder y Vega (2009: 129). Para buscar un dato en un vector existen dos métodos: búsqueda secuencial o lineal y búsqueda binaria. El primero es más fácil de implementar pero puede tomar más tiempo, el segundo es más eficiente, pero requiere que el vector esté ordenado. 7.1.1. Búsqueda Lineal Este método consiste en tomar un dato clave que identifica al elemento que se busca y hacer un recorrido a través de todo el arreglo comparando el dato de referencia con el dato de cada posición. Supóngase que se tienen una lista de estudiantes y se desea ubicar al que se identifica con el número 27844562. La búsqueda consiste en comparar, dicho número con la identificación de cada estudiante de la lista. La búsqueda terminará en el evento de encontrar
una coincidencia en los números o si al llegar al final de la lista no se encontró identificación igual al número buscado, en cuyo caso se concluye que el dato no existe en el vector. En la figura 111 se presenta el diagrama del flujo de una función con los pasos generales para hacer una búsqueda secuencial en un vector. La función recibe como parámetros el vector y la clave del elemento a buscar, recorre el vector hasta que se encuentre el elemento, en cuyo caso la posición se registra en la variable pos , o hasta que se llegue al final del vector. Al finalizar el algoritmo devuelve la variable pos , si el dato fue encontrado ésta contiene la posición que ocupa en el vector, en caso contrario, reporta el valor menos uno (- 1 ) indicando que el dato no está en el vector. Figura 111. Diagrama de flujo del algoritmo de búsqueda lineal 7.1.2. Ejemplos de búsqueda lineal Ejemplo 68. Buscar un estudiante Un profesor guarda los datos de sus estudiantes en tres vectores: código, nombre y nota, como se muestra en la figura 112. Se requiere un algoritmo para consultar la nota de un estudiante a partir de su código. Inicio Entero: i=1, pos = - 1 Fin Mientras i<= n y pos < 0 clave = v[i] pos = i i = i + 1 Parámetros: v[], n, clave No Si Retornar p
Ejemplo 69. Consultar saldo En un hipotético cajero electrónico, cuando un cliente solicita el saldo de su cuenta desliza la tarjeta, el lector toma el número de cuenta y el sistema busca dicho número en la base de datos. Si lo encuentra reporta el saldo, si no muestra un mensaje de error. Suponiendo que la base de datos consiste en tres vectores: número de cuenta, titular y saldo. Diseñar un algoritmo para consultar el saldo de una cuenta. En este algoritmo se lee el número de la cuenta y se invoca la función busquedalineal() proporcionándole el vector con los números de cuenta y el dato leído, esta función hace la búsqueda y retorna la posición dónde se encuentran los datos correspondientes a dicha cuenta. Si el dato devuelto por la función es un entero positivo se muestran los datos de todos los vectores, si es - 1 significa que la cuenta no existe y se muestra un mensaje informando de esta situación. El pseudocódigo de este algoritmo se presenta en el cuadro 104 Cuadro 104. Pseudocódigo del algoritmo consultar saldo 1 Inicio 2 Entero num, pos, cuenta[1000] Cadena: titular[1000] Real: saldo[1000] 3 Llenardatos() 4 Leer num 5 pos = busquedalineal(cuenta[], 10000, num) 6 Si pos > 0 entonces 7 Escribir “Cuenta:”, cuenta[pos] 8 Escribir “Titular: “,titular[pos], 9 Escribir “Saldo: “,saldo[pos] 10 Si no 11 Escribir “Número de cuenta no encontrado” 12 Fin si 13 Fin algoritmo 7.1.3. Búsqueda Binaria Este método es más eficiente que la búsqueda secuencial pero sólo se puede aplicar sobre vectores o listas de datos ordenados, como lo confirman López, Jeder y Vega (2009:
En la búsqueda binaria no se hace un recorrido de principio a fin, sino que se delimita progresivamente el espacio de búsqueda hasta llegar al elemento buscado. La primera comparación se hace con el elemento de la mitad del arreglo, si aquel no es el dato buscado,
se decide si buscar en la mitad inferior o en la mitad superior según la clave sea menor o mayor del elemento de la mitad. Se toma como espacio de búsqueda la mitad del vector que corresponda y se procede de igual forma, se compara con el elemento del centro, si ese no es el que se busca, se toma un nuevo espacio de búsqueda correspondiente a la mitad inferior o superior del espacio anterior, se compara nuevamente con el elemento del centro, y así sucesivamente hasta que se encuentre el elemento o el espacio de búsqueda se haya reducido un elemento. En la búsqueda binaria el número de elementos que conforman el campo de búsqueda se reduce a la mitad en cada iteración, siendo: n para la primera iteración ( n = tamaño del vector), n /2 para la segunda, n /2^2 en la tercera y n /2^3 para la cuarta. En general, el espacio de búsqueda en la i - ésima iteración está conformado por n/2 i-^1 elementos. Supóngase un vector v de 20 elementos ordenado de forma ascendente, como se muestra en la figura 114 , en el que se busca el número 10. (clave = 10). La primera iteración toma como espacio de búsqueda el vector completo y se ubica en el elemento de la mitad. Para determinar cuál es elemento de la mitad se suma el índice del extremo inferior con el índice del extremo superior del espacio de búsqueda y se divide para dos. (1 + 13) / 2 = 7 Se averigua si la clave está en el elemento del centro: clave = v[7]? 10 = 14? Figura 114. Diagrama de flujo del algoritmo de búsqueda lineal Espacio 1ra iteración Espacio 2da iteración Espacio 3ra iteración 2 4 6 8 10 12 14 16 18 20 22 24 26 1 2 3 4 5 6 7 8 9 10 11 12 13 Segunda comparación Tercera comparación Primera comparación
Cuadro 105. Pseudocódigo de la función búsqueda binaria 1 Entero busquedabinaria(entero v[], entero n, entero clave) 2 Entero inf = 1, sup = n, centro, pos = - 1 3 Mientras inf <= sup y pos < 0 hacer 4 centro = (inf + sup) / 2 5 Si v[centro] = clave entonces 6 pos = centro 7 Si no 8 Si clave > v[centro] entonces 9 inf = centro + 1 10 Si no 11 sup = centro – 1 12 Fin si 13 Fin si 14 Fin mientras 15 Retornar pos 16 Fin busquedabinaria La función declara cuatro variables locales, dos para mantener los límites del espacio de búsqueda: inf y sup , estas comienzan en 1 y n respectivamente, lo que permite que la primera iteración se aplique sobre todo el vector, la variable centro se actualiza en cada iteración y su propósito es identificar el dato ubicado en el centro del espacio de búsqueda para compararlo con la clave; finalmente, la variable pos se destina a almacenar la posición del elemento en caso de hallarlo, se inicializa en - 1 lo que indica que el dato no ha sido encontrado. El ciclo tiene dos condiciones: que el límite inferior sea menor que el superior, es decir que haya un espacio dónde hacer la búsqueda y que el dato no haya sido encontrado. En el momento en que el dato se localiza la variable pos toma un valor positivo y el ciclo deja de ejecutarse. Al terminar el ciclo se devuelve la variable pos , si tiene un valor positivo, éste corresponde a la posición dónde se encuentra el dato buscado, pero si contiene - 1 significa que el dato no está en el vector. 7.1.4. Ejemplos de búsqueda binaria Ejemplo 70. Número ganador La lotería de Mundo Rico registra los números de los billetes vendidos y el lugar dónde se vendió, en orden ascendente. En el momento de jugar la lotería, al conocer el número ganador se requiere conocer inmediatamente en qué lugar fue vendido. Diseñar un algoritmo para realizar esta consulta.
Los datos se guardan en una estructura conformada por dos vectores como se muestra en la figura 115. Dado que los números están ordenados se puede aplicar el algoritmo de búsqueda binaria, éste encontrará el número mucho más rápido que si se utilizara la búsqueda lineal. Figura 115. Número de billetes de lotería y lugar de venta 1 001 1 Pasto 2 002 2 Medellín 3 003 3 Manizales 4 004 4 Cali 5 005 5 Santa Marta 6 006 6 Bogotá … …^ … … Número[] Lugar[] Las operaciones a realizar en este ejercicio son: leer el número ganador, pasarlo a la función de búsqueda y mostrar los resultados. La función proporciona la posición dónde se encuentra el dato o en su defecto informará que éste no se encuentra, lo que se interpreta como número no vendido. La lectura de datos y la impresión de resultados son acciones que debe realizar el algoritmo principal. Ver cuadro 106. Cuadro 106. Pseudocódigo del algoritmo número ganador 1 Inicio 2 Entero numero[1000], lugar[1000], ganador, pos 3 Llenardatos() 4 Leer ganador 5 pos = busquedabinaria(numero[], 1000, ganador) 6 Si pos> 0 entonces 7 Escribir “El numero: “, ganador, “ fue vendido en: “, lugar[pos] 8 Si no 9 Escribir “El número no fue vendido” 10 Fin si 11 Fin algoritmo En la línea 3 del algoritmo se invoca un procedimiento para llenar los datos, lo que garantiza que los vectores contienen datos, no obstante la implementación de éste no se incluye. En la línea 5 se invoca a la función busquedabinaria() enviando como pará-metros el vector que contiene los número, el tamaño del vector y el número ganador.
Los datos de un vector, una lista o un archivo están ordenados cuando cada elemento ocupa el lugar que le corresponde según su valor, un dato clave o un criterio (en este documento sólo se aborda el ordenamiento de vectores). Si cada elemento del vector diferente del primero es mayor que los anteriores, se dice que está ordenado ascendentemente, mientras que si cada elemento diferente del primero es menor que los anteriores, está ordenado de forma descendente. En un pequeño conjunto de datos el orden en que estos se presenten puede ser irrelevante, pero cuando la cantidad aumenta el orden toma importancia. Qué tan útil podría ser un diccionario si no estuviera ordenado? O el directorio telefónico? Baase y Van Gelder (2002: 150) mencionan que el ordena-miento de datos fue una de las principales preocupaciones de las ciencias de la computación, prueba de ello es la cantidad de métodos de ordenamiento que se han diseñado. En este capítulo se explican los algoritmos más utilizados para este propósito. 7.2.1 Algoritmo de intercambio Este algoritmo no es el más eficiente, pero es muy didáctico y por ende es común su utilización en los primeros cursos programa-ción. Consiste en tomar cada elemento y compararlo con los que están a su derecha, cada vez que se identifica un par de elementos que no cumplen el criterio de ordenamiento que se está aplicando se intercambian. En cada iteración se encuentra el elemento que corresponde a una posición. Considérese el vector v de la figura 116 , para ordenar los números de forma ascendente se toma el primer elemento v[1] y se compara con v[2]. Si v[1] menor que v[2] éstos están en orden, pero si v[1] > v[2] están desordenados y es necesario inter-cambiarlos. Figura 116. Algoritmo de intercambio comparaciones del primer elemento 1 2 3 4 5 17 aux v^17 12 13 8 15 3 7 22 11 6 7 8 9 10 Comparaciones
Cuadro 10 9. Función ordenar vector por el método de intercambio 1 Entero[] intercambio(entero v[], Entero n) 2 Entero i, j, aux 3 Para i = 1 hasta n-1 hacer 4 Para j = i+1 hasta n hacer 5 Si v[i] > v[j] entonces 6 aux = v[i] 7 v[i] = v[j] 8 v[j] = aux 9 Fin si 10 Fin para 11 Fin para 12 Retornar v[] 13 Fin intercambio 7.2.2 Algoritmo de Selección Este método es similar al anterior en cuanto a los recorridos del vector y las comparaciones, pero con un número menor de intercambios. En el método de intercambio cada vez que se comparan dos posiciones y éstas no están ordenadas se hace el intercambio de los datos, de manera que en un mismo recorrido puede haber varios intercambios antes de que el número ocupe el lugar que le corresponde en el arreglo ordenado. En el método de selección, en cada recorrido se identifica el elemento que pertenece a una posición y se hace un solo intercambio. Considérese el vector de la figura 117 , donde se muestra el intercambio efectuado para la primera posición. Figura 117. Algoritmo de selección – intercambio del primer elemento 1 2 3 4 5 6 Índice del menor v^17 12 13 8 15 3 7 22 11 6 7 8 9 10 17 aux
Se declara una variable para guardar la posición del menor y se inicializa en 1 para comenzar las comparaciones en la primera posición, se hace un recorrido desde la segunda posición hasta la última y cada vez que se encuentra un elemento menor al que indica la variable se la actualiza. Estando en la posición i del vector v , el recorrido para identificar el elemento que corresponde a dicha posición en el vector ordenado ascendentemente se lleva a cabo con las instrucciones que se presentan en el cuadro 110. Cuadro 110. Recorrido para seleccionar el i-ésimo elemento 1 posmenor = i 2 Para j = i+1 hasta n hacer 3 Si v[posmenor] > v[j] entonces 4 posmenor = j 5 Fin si 6 Fin para 7 Aux = v[i] 8 v[i] = v[posmenor] 9 v[posmenor] = aux Como se aprecia en el pseudocódigo del cuadro 110, el recorrido coloca el índice del menor elemento encontrado en la variable posmenor y al finalizar el recorrido se hace el intercambio entre la posición i y la posición que indica posmenor. Ahora bien, para ordenar todo el vector solo hay que hacer que la variable i se mueva desde el primer elemento hasta el penúltimo, como se muestra en el cuadro 111 , donde se presenta la función para ordenar un vector aplicando el algoritmo de selección. Esta función recibe un vector no ordenado como parámetro y lo devuelve ordenado. Cuadro 111. Función ordenar vector por el método de selección 1 Entero[] seleccion(entero v[], entero n) 2 Entero: i, j, posmenor, aux 3 Para i = 1 hasta n-1 hacer 4 posmenor = i 5 Para j = i+1 hasta n hacer 6 Si v[posmenor] > v[j] entonces 7 posmenor = j 8 Fin si 9 Fin para 10 aux = v[i] 11 v[i] = v[posmenor]
Cuadro 112. Recorrido para burbujear un elemento 1 Para j = 1 hasta n- 1 hacer 2 Si v[j] > v[j+1] entonces 3 aux = v[j] 4 v[j] = v[j+1] 5 v[j+1] = aux 6 Fin si 7 Fin para Para ordenar completamente el vector, considerando que en una comparación se ordenan dos elementos y en un recorrido se lleva un elemento hasta su posición ordenada, es necesario realizar n- 1 recorridos. Para mejorar el desempeño de este algoritmo se pueden reducir el número de comparaciones y en algunos casos la cantidad de recorridos. Si se tienen en cuenta que cada recorrido toma el dato más grande y lo desplaza hacia la derecha ocurre que el primer recorrido lleva el dato más grande a la posición n , el segundo recorrido lleva el segundo dato más grande a la posición n- 1 , el tercero el que sigue a la posición n- 1. De esto se desprende que en el segundo recorrido la comparación v[n-1] > v[n] es inútil pues ya se sabe que en la última posición está el elemento más grande. También ocurre que en el tercer recorrido, la comparación v[n-2] > v[n-1] y v[n-1] > v[n] no aportan nada, pues las últimas posiciones se van ordenando en cada recorrido. En conclusión, todos los recorridos no necesitan llegar hasta n- 1 , el segundo va hasta n- 2 , el tercero hasta n- 3 y así sucesivamente. En un vector con muchos elementos el número de comparaciones que se reduce es importante. En el cuadro 113 se muestra el recorrido mejorado para la i-ésima iteración. Cuadro 1 13. Recorrido mejorado para burbujear el i-ésimo elemento 1 Para j = i hasta n-i hacer 2 Si v[j] > v[j+1] entonces 3 aux = v[j] 4 v[j] = v[j+1] 5 v[j+1] = aux 6 Fin si 7 Fin para Por otra parte puede ocurrir que un vector quede completamente ordenado en una cantidad de recorridos menor a n- 1 y por ende los últimos recorridos sean innecesarios. Para evitar esta pérdida de tiempo se vigila que en cada recorrido hayan intercambios, si en el i-ésimo recorrido no tuvo lugar ninguno significa que el vector ya está ordenado y no es conveniente
hacer los recorridos faltantes. Para ello se puede utilizar un contador de intercambios o un conmutador (bandera) que cambia de estado al efectuar un intercambio. En el cuadro 114 se presenta la función para ordenar un vector aplicando el algoritmo de la burbuja con las dos mejoras analizadas. 7.2.4 Algoritmo de Inserción Este método consiste en ordenar los elementos del arreglo progresivamente, comenzando por los primeros y avanzando hasta ordenarlos todos. Dado el elemento de una posición i ( i comienza en 2 y va hasta el fin del arreglo) se guarda en una variable auxiliar y ésta se compara con el elemento que está a la izquierda; si no están ordenados, el elemento de la izquierda se desplaza hacia la derecha. Se vuelve a comparar la variable auxiliar con el elemento que sigue por la izquierda. Todo elemento que no esté ordenado se desplaza una posición a la derecha, hasta que se encuentre uno que si esté en orden o se llegue al inicio del vector. Al terminar este recorrido se deposita, en el espacio que quedó libre, el elemento contenido en la variable auxiliar. Cuadro 114. Función ordenar vector por el método de la burbuja
Cuadro 1 16. Función ordenar vector por el método de inserción 1 Entero[] insercion(entero v[], entero n) 2 Entero: aux, i , j 3 Para i = 2 hasta n hacer 4 j = i – 1 5 aux = v[i] 6 Mientras v[j] > aux y j >= 1 hacer 7 v[j+1] = v[j] 8 j = j - 1 9 Fin mientras 10 v[j+1] = aux 11 Fin para 12 Retornar v[] 13 Fin inserción Este algoritmo puede mejorar su eficiencia cambiando el método de búsqueda que se aplican en la parte izquierda del vector. Teniendo en cuenta que el subvector de la izquierda de cada elemento está ordenado, se puede utilizar búsqueda binaria en vez de búsqueda secuencial, de esta forma se reduce el tiempo que el algoritmo tarda en encontrar el lugar que le corresponde al elemento. Esta reducción en el tiempo de búsqueda puede ser significativa en vectores con muchos elementos. Hernández et al (2001: 53) expresan este cambio en los siguientes pasos: a. Tomar un elemento en la posición i b. Buscar de forma binaria su lugar en las posiciones anteriores c. Mover los elementos restantes hacia la derecha d. Insertar el elemento 7.2.5 Algoritmo de Donald Shell Es un algoritmo de inserción con saltos decrecientes diseñado por Donald Shell†^ y reconocido generalmente por el nombre de su creador. Funciona de forma similar al algoritmo de inserción, pero a diferencia de éste no mueve los elementos una posición, sino varias posiciones a la vez, de manera que los elementos llegan más rápido a su destino. Este método es muy adecuado para vectores con gran cantidad de datos. En este algoritmo, se toma un elemento y se lo compara con los que están a su izquierda, si se busca un orden ascendente, los elementos mayores al de referencia se mueven a la † (^) Donald Shell trabajó en la división de ingeniería de General electric , se doctoró en matemáticas en la Universidad de Cincinnati en 1959 y en ese mismo año publicó el algoritmo que hoy lleva su nombre con el título A high-speed sorting procedure en Communications of the ACM.
derecha y éste se ubica en el lugar que le corresponde, pero no se compara con el elemento que está inmediatamente a la izquierda, sino con el que se encuentra x posiciones atrás. A x se le llama salto, en la primera iteración se dan saltos de la mitad del tamaño del vector, de manera que se comparan los elementos de la mitad izquierda con los elementos de la derecha y cada intercambio implica pasar de un lado al otro. Para la segunda iteración el salto se reduce a la mitad y para la tercera nuevamente a la mitad y así sucesivamente hasta llegar a hacer comparaciones de uno en uno. Para analizar el funcionamiento de este algoritmo considérese un vector de 10 elementos. Entonces: Salto = 10/2 = 5 En este caso, en la primera iteración las comparaciones se hacen con una diferencia de 5 posiciones, v[1] con v[6] , v[2] con v[7] y así sucesivamente, como se muestra en la figura
Figura 120. Algoritmo de Shell – primera iteración En la primera iteración cada elemento del lado izquierdo sólo se compara con uno del lado derecho ya que el salto divide el vector en dos partes. Comparación Resultado Intercambio V[1] > v[6] Verdadero Si V[2] > v[7] Verdadero Si V[3] > v[ 8 ] Falso No V[4] > v[ 9 ] Falso No V[5] > v[ 10 ] Falso No Para la segunda iteración se actualiza el salto tomando como valor la cuarta parte del tamaño del vector, lo que implica que desde algunos elementos se pueden dar varios saltos a la izquierda. salto = salto/ salto = 5/2 = 2 En la figura 121 se muestra el vector después de la primera iteración y las comparaciones que se harán en la segunda iteración. 1 2 3 4 5 v^17 13 12 8 15 3 7 22 11 6 7 8 9 10 salto = 5