Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                

Busqueda y Ordenamiento en C++

Descargar como pdf o txt
Descargar como pdf o txt
Está en la página 1de 12

Bsqueda y Ordenamiento

Introduccin
La bsqueda de datos implica el determinar si un valor (conocido como la clave de bsqueda) est presente en los
datos y, de ser as, hay que encontrar su ubicacin. Dos algoritmos populares de bsqueda son la bsqueda lineal simple
y la bsqueda binaria, que es ms rpida pero a la vez ms compleja, y que presentaremos
en este captulo.

El ordenamiento coloca los datos en orden, por lo general ascendente o descendente, con base en una o ms claves
de ordenamiento. Una lista de nombres se podra ordenar en forma alfabtica, las cuentas bancarias podran ordenarse
por nmero de cuenta, los registros de nminas de empleados podran ordenarse por nmero de seguro social, etctera.
En este captulo se presenta el ordenamiento por combinacin, que es ms eficiente pero ms complejo

Algoritmos de bsqueda
Buscar un nmero telefnico, acceder a un sitio Web y comprobar la definicin de una palabra en un diccionario son
acciones que implican buscar entre grandes cantidades de datos. Todos los algoritmos de bsqueda logran el mismo obje-
tivo: encontrar un elemento que coincida con una clave de bsqueda dada, si es que existe dicho elemento. Sin embargo,
hay varias cosas que diferencian a unos algoritmos de bsqueda de otros. La principal diferencia es la cantidad de esfuerzo
que requieren para completar la bsqueda. Una manera de describir este esfuerzo es mediante la notacin Big O. Para los
algoritmos de bsqueda y ordenamiento, esto es en especial dependiente del nmero de elementos de datos.
En el captulo 7 hablamos sobre el algoritmo de bsqueda lineal, que es un algoritmo de bsqueda simple y fcil
de implementar. Ahora hablaremos sobre la eficiencia del algoritmo de bsqueda lineal en base a la notacin Big O.
Despus presentaremos un algoritmo de bsqueda que sea relativamente eficiente, pero ms complejo y difcil de
implementar.
Eficiencia de la bsqueda lineal
Suponga que un algoritmo simplemente evala si el primer elemento de un vector es igual al segundo elemento. Si el
vector tiene 10 elementos, este algoritmo slo requiere una comparacin. Si el vector tiene 1000 elementos, sigue requi-
riendo una comparacin. De hecho, el algoritmo es independiente del nmero de elementos en el vector. Se dice que este
algoritmo tiene un tiempo de ejecucin constante, el cual se representa en la notacin Big O como O(1). Un algoritmo
que es O(1) no necesariamente requiere slo de una comparacin. O(1) slo significa que el nmero de comparaciones
es constante; no crece a medida que aumenta el tamao del arreglo. Un algoritmo que evala si el primer elemento de un
arreglo es igual a los siguientes tres elementos sigue siendo O(1), aun y cuando requiera tres comparaciones.

Un algoritmo que evala si el primer elemento de un vector es igual a cualquiera de los dems elementos del vector
requerir cuando menos de n - 1 comparaciones, en donde n es el nmero de elementos en el vector. Si el vector tiene
10 elementos, este algoritmo requiere hasta nueve comparaciones. Si el vector tiene 1000 elementos, requiere hasta 999
comparaciones. A medida que n aumenta en tamao, la parte de la expresin correspondiente a la n domina, y si le
restamos uno no hay consecuencias. Big O est diseado para resaltar estos trminos dominantes e ignorar los trminos
que pierden importancia, a medida que n crece. Por esta razn, se dice que un algoritmo que requiere un total de n - 1
comparaciones (como el que describimos en este prrafo) es O(n). Se considera que un algoritmo O(n) tiene un tiempo
de ejecucin lineal. A menudo, O(n) significa en el orden de n, o dicho en forma ms simple, orden n.


Ahora, suponga que tiene un algoritmo que evala si cualquier elemento de un vector se duplica en cualquier otra
parte del mismo. El primer elemento debe compararse con todos los dems elementos del vector. El segundo elemento
debe compararse con todos los dems elementos, excepto con el primero (ya se compar con ste). El tercer elemento
debe compararse con todos los elementos, excepto los primeros dos. Al final, este algoritmo terminar realizando (n - 1) +
(n - 2) + + 2 + 1, o n
2
/2 - n/2 comparaciones. A medida que n aumenta, el trmino n
2
domina y el trmino n se
vuelve intrascendente. De nuevo, la notacin Big O resalta el trmino n
2
, dejando a n
2
/2. Pero como veremos pronto,
los factores constantes se omiten en la notacin Big O.


Big O se enfoca en la forma en que aumenta el tiempo de ejecucin de un algoritmo, en relacin con el nmero
de elementos procesados. Suponga que un algoritmo requiere n
2
comparaciones. Con cuatro elementos, el algoritmo
requiere 16 comparaciones; con ocho elementos, 64 comparaciones. Con este algoritmo, al duplicar el nmero de ele-
mentos se cuadruplica el nmero de comparaciones. Considere un algoritmo similar que requiere n
2
/2 comparaciones.
Con cuatro elementos, el algoritmo requiere ocho comparaciones; con ocho elementos, 32 comparaciones. De nuevo,
al duplicar el nmero de elementos se cuadruplica el nmero de comparaciones. Ambos algoritmos aumentan como el
cuadrado de n, por lo que Big O ignora la constante y ambos algoritmos se consideran como O(n
2
), lo cual se conoce
como tiempo de ejecucin cuadrtico y se pronuncia como en el orden de n al cuadrado, o dicho en forma ms sim-
ple, orden n al cuadrado.

Cuando n es pequea, los algoritmos O(n
2
) (que se ejecutan en las computadoras personales de la actualidad, con
miles de millones de operaciones por segundo) no afectan el rendimiento en forma considerable. Pero a medida que n
aumenta, se empieza a notar la reduccin en el rendimiento. Un algori tmo O(n
2
) que se ejecuta en un vector de un
milln de elementos requerira tres mil millones de operaciones (en donde cada una requerira en realidad varias ins-
trucciones de mquina para ejecutarse). Esto podra requerir varias horas para ejecutarse. Un vector de mil millones de
elementos requerira un trilln de operaciones, un nmero tan grande que el algoritmo tardara dcadas! Por desgracia,
los algoritmos O(n
2
) tienden a ser ms fciles de escribir. En este captulo veremos algoritmos con medidas de Big O
requieren un poco ms de astucia y esfuerzo para crearlos, pero









su rendimiento superior bien vale la pena el esfuerzo adicional, en especial a medida que n aumenta y los algoritmos se
combinan en programas ms grandes.
El algoritmo de bsqueda lineal se ejecuta en un tiempo O(n). El peor caso en este algoritmo es que se debe com-
probar cada elemento para determinar si la clave de bsqueda existe en el vector. Si el tamao del vector se duplica, el
nmero de comparaciones que el algoritmo debe realizar tambin se duplica. Observe que la bsqueda lineal puede
proporcionar un rendimiento sorprendente, si el elemento que coincide con la clave de bsqueda se encuentra en
(o est cerca de) la parte frontal del vector. Pero buscamos algoritmos que tengan un buen desempeo, en promedio,
en todas las bsquedas, incluyendo aquellas en las que el elemento que coincide con la clave de bsqueda se encuentra
cerca del final del vector.
La bsqueda lineal es el algoritmo de bsqueda ms fcil de programar, pero puede ser lento si se le compara con otros
algoritmos de bsqueda. Si un programa necesita realizar muchas bsquedas en vectores grandes, puede ser mejor imple-
mentar un algoritmo distinto ms eficiente, como la bsqueda binaria, el cual presentaremos en la siguiente seccin.
Tip de rendimiento 19.1
Algunas veces los algoritmos ms simples tienen un desempeo pobre. Su virtud es que son fciles de programar, probar y depurar. Algunas veces se
requieren algoritmos ms complejos para obtener el mximo rendimiento.

Bsqueda binaria
El algoritmo de bsqueda binaria es ms eficiente que el algoritmo de bsqueda lineal, pero primero requiere que se
ordene el vector. Esto slo vale la pena cuando se realizarn muchas bsquedas en el vector, una vez ordenado, o cuando
la aplicacin de bsqueda tiene requerimientos de rendimiento estrictos. La primera iteracin de este algoritmo evala el
elemento medio en el vector. Si ste coincide con la clave de bsqueda, el algoritmo termina. Suponiendo que el vector
se ordene en forma ascendente, entonces si la clave de bsqueda es menor que el elemento de en medio, no puede coin-
cidir con ningn elemento en la segunda mitad del vector, y el algoritmo contina slo con la primera mitad (es decir,
el primer elemento hasta, pero sin incluir, el elemento de en medio). Si la clave de bsqueda es mayor que el elemento
de en medio, no puede coincidir con ninguno de los elementos de la primera mitad del vector, y el algoritmo contina
slo con la segunda mitad del vector (es decir, desde el elemento despus del elemento de en medio, hasta el ltimo ele-
mento). Cada iteracin evala el valor medio de la porcin restante del vector. Si la clave de bsqueda no coincide con
el elemento, el algoritmo elimina la mitad de los elementos restantes. Para terminar, el algoritmo encuentra un elemento
que coincide con la clave de bsqueda o reduce el subvector hasta un tamao de cero.
Como ejemplo, considere el siguiente vector ordenado de 15 elementos:
2 3 5 10 27 30 34 51 65 77 81 82 93 99
y la clave de bsqueda de 65. Un programa que implemente el algoritmo de bsqueda binaria primero comprobara si el
51 es la clave de bsqueda (ya que 51 es el elemento de en medio del vector). La clave de bsqueda (65) es mayor que 51,
por lo que este nmero se descarta junto con la primera mitad del vector (todos los elementos menores que 51). A conti-
nuacin, el algoritmo comprueba si 81 (el elemento de en medio del resto del vector) coincide con la clave de bsqueda.
La clave de bsqueda (65) es menor que 81, por lo que se descarta este nmero junto con los elementos mayores de 81.
Despus de slo dos pruebas, el algoritmo ha reducido el nmero de valores a comprobar a tres (56, 65 y 77). Despus
el algoritmo comprueba el 65 (que coincide con la clave de bsqueda), y devuelve el ndice (9) del elemento del vector
que contiene el 65. En este caso, el algoritmo slo requiri tres comparaciones para determinar si la clave de bsqueda
coincidi con un elemento del vector. Un algoritmo de bsqueda lineal hubiera requerido 10 comparaciones. [Nota: en
este ejemplo hemos optado por usar un vector con 15 elementos, para que siempre haya un elemento obvio en medio del
vector. Con un nmero par de elementos, la parte media del vector se encuentra entre dos elementos. Implementamos
el algoritmo para elegir el mayor de estos dos elementos].

En las figuras 19.2 y 19.3 se define la clase BusquedaBinaria y sus funciones miembro, respectivamente. La clase
BusquedaBinaria es similar a BusquedaLineal: tiene un constructor, una funcin de bsqueda (busquedaBinaria),
una funcin mostrarElementos, dos miembros de datos private y una funcin utilitaria private
(mostrarSubElementos). En las lneas 18 a 28 de la figura 19.3 se define el constructor. Una vez que se ini cializa el
vector con valores int aleatorios de 10 a 99 (lneas 24 y 25), en la lnea 27 se hace una llamada a la funcin sort de la
Biblioteca estndar con el vector datos. Recuerde que el algoritmo de bsqueda binaria slo trabaja con un vector
ordenado. La funcin sort requiere dos argumentos que especifiquen el rango de elementos a ordenar. Estos argumentos
se especifican con iteradores (que vimos brevemente en la seccin 10.9, y veremos con detalle en el captulo 22). Las
funciones miembro begin y end de vector devuelven iteradores que se pueden utilizar con la funcin sort para indicar
que se deben ordenar todos los elementos, desde el principio hasta el final.

En las lneas 31 a 61 se define la funcin busquedaBinaria. La clave de bsqueda se pasa al parmetro elemento-
Busqueda (lnea 31). En las lneas 33 a 35 se calcula el ndice del extremo inferior, el ndice del extremo superior y
el
ndice medio de la parte del vector en la que el programa est buscando en un momento dado. Al principio de la funcin,
el extremo inferior es 0, el extremo superior es el tamao del vector menos 1, y el medio es el promedio de estos
dos
valores. En la lnea 36 se inicializa la ubicacion del elemento encontrado en -1; el valor que se devolver si la clave
de
bsqueda no se encuentra. En las lneas 38 a 58 se itera hasta que inferior es mayor que superior (esto ocurre cuando
el elemento no se encuentra) o ubicacion no es igual a -1 (indicando que se encontr la clave de bsqueda). En la lnea
50 se evala si el valor en el elemento medio es igual a elementoBusqueda. Si es true, en la lnea 51 se asigna medio
a ubicacion. Despus el ciclo termina y ubicacion se devuelve al que hizo la llamada. Cada iteracin del ciclo evala
un solo valor (lnea 50) y elimina la mitad de los valores restantes en el vector (lnea 53 o 55).


1 // Fig 19.2: BusquedaBinaria.h
2 // Clase que contiene un vector de enteros aleatorios y una funcin
3 // que utiliza la bsqueda binaria para encontrar un entero.
4 #include <vector>
5 using std::vector;
6
7 class BusquedaBinaria
8 {
9 public:
10 BusquedaBinaria( int ); // el constructor inicializa el vector
11 int busquedaBinaria( int ) const; // realiza una bsqueda binaria en el vector
12 void mostrarElementos() const; // muestra los elementos del vector
13 private:
14 int tamanio; // tamao del vector
15 vector< int > datos; // vector entero
16 void mostrarSubElementos( int, int ) const; // muestra el rango de valores
17 }; // fin de la clase BusquedaBinaria
Figura 19.2 | Definicin de la clase BusquedaBinaria.

1 // Fig 19.3: BusquedaBinaria.cpp
2 // Definicin de las funciones miembro de la clase BusquedaBinaria.
3 #include <iostream>
4 using std::cout;
5 using std::endl;
6
7 #include <cstdlib> // prototipos para las funciones srand y rand
8 using std::rand;
9 using std::srand;
10
11 #include <ctime> // prototipo para la funcin time
12 using std::time;
13
14 #include <algorithm> // prototipo para la funcin sort
15 #include "BusquedaBinaria.h" // definicin de la clase BusquedaBinaria
16
17 // el constructor inicializa el vector con valores int aleatorios y ordena el vector
18 BusquedaBinaria::BusquedaBinaria( int tamanioVector )
19 {
20 tamanio = ( tamanioVector > 0 ? tamanioVector : 10 ); // valida tamanioVector
21 srand( time( 0 ) ); // siembra usando el tiempo actual
22
23 // llena el vector con valores int aleatorios en el rango 10 a 99
24 for ( int i = 0; i < tamanio; i++ )
25 datos.push_back( 10 + rand() % 90 ); // 10 a 99
26
27 std::sort( datos.begin(), datos.end() ); // ordena los datos
28 } // fin del constructor BusquedaBinaria
Figura 19.3 | Definicin de la funcin miembro de la clase BusquedaBinaria. (Parte 1 de 2).
774 Captulo 19 Bsqueda y ordenamiento

29
30 // realiza una bsqueda binaria en los datos
31 int BusquedaBinaria::busquedaBinaria( int elementoBusqueda ) const
32 {
33 int inferior = 0; // extremo inferior del rea de bsqueda
34 int superior = tamanio - 1; // extremo superior del rea de bsqueda
35 int medio = ( inferior + superior + 1 ) / 2; // elemento medio
36 int ubicacion = -1; // devuelve el valor; -1 si no lo encuentra
37
38 do // itera para buscar el elemento
39 {
40 // imprime el resto de los elementos del vector en el que se busca
41 mostrarSubElementos( inferior, superior );
42
43 // imprime espacios para alineacin
44 for ( int i = 0; i < medio; i++ )
45 cout << " ";
46
47 cout << " * " << endl; // indica el elemento medio actual
48
49 // si encuentra el elemento en el medio
50 if ( elementoBusqueda == datos[ medio ] )
51 ubicacion = medio; // ubicacion es el medio actual
52 else if ( elementoBusqueda < datos[ medio ] ) // el medio es demasiado alto
53 superior = medio - 1; // elimina la mitad superior
54 else // el elemeto medio es demasiado inferior
55 inferior = medio + 1; // elimina la mitad inferior
56
57 medio = ( inferior + superior + 1 ) / 2; // recalcula el elemento medio
58 } while ( ( inferior <= superior ) && ( ubicacion == -1 ) );
59
60 return ubicacion; // devuelve la ubicacin de la clave de bsqueda
61 } // fin de la funcin busquedaBinaria
62
63 // muestra los valores en el vector
64 void BusquedaBinaria::mostrarElementos() const
65 {
66 mostrarSubElementos( 0, tamanio - 1 );
67 } // fin de la funcin mostrarElementos
68
69 // muestra ciertos valores en el vector
70 void BusquedaBinaria::mostrarSubElementos( int inferior, int superior ) const
71 {
72 for ( int i = 0; i < inferior; i++ ) // imprime espacios para alineacin
73 cout << " ";
74
75 for ( int i = inferior; i <= superior; i++ ) // imprime los elementos que quedan en el
vector
76 cout << datos[ i ] << " ";
77
78 cout << endl;
79 } // fin de la funcin mostrarSubElementos
Figura 19.3 | Definicin de la funcin miembro de la clase BusquedaBinaria. (Parte 2 de 2).


En las lneas 25 a 41 de la figura 19.4 se itera hasta que el usuario introduzca el valor -1. Para cada otro nmero
que
introduce el usuario, el programa realiza una bsqueda binaria en los datos para determinar si coinciden con un
elemento
en el vector. La primera lnea de salida de este programa es el vector de valores int, en orden ascendente. Cuando el
usua-
rio instruye al programa que busque el nmero 38, el programa primero evala el elemento medio, que es 67 (como
lo
indica el smbolo *). La clave de bsqueda es menor que 67, por lo que el programa elimina la segunda mitad del
vector
y evala el elemento medio, empezando desde la primera mitad del vector. La clave de bsqueda es igual a 38, por lo
que
el programa devuelve el ndice 3.



1 // Fig 19.4: Fig19_04.cpp
2 // Programa de prueba de BusquedaBinaria.
3 #include <iostream>
4 using std::cin;
5 using std::cout;
6 using
std::endl;
7
19.2 Algoritmos de bsqueda
77
5
8 #include "BusquedaBinaria.h" // definicin de la clase BusquedaBinaria
9
10 int main()
11 {
12 int busquedaInt; // clave de bsqueda
13 int posicion; // ubicacion de la clave de bsqueda en el vector
14
15 // crea el vector y lo imprime
16 BusquedaBinaria vectorBusqueda ( 15 );
17 vectorBusqueda.mostrarElementos();
18
19 // obtiene la entrada del usuario
20 cout << "\nEscriba un valor entero (-1 para terminar): ";
21 cin >> busquedaInt; // lee un valor int del usuario
22 cout << endl;
23
24 // introduce un entero en forma repetida; -1 termina el programa
25 while ( busquedaInt != -1 )
26 {
27 // usa la bsqueda binaria para tratar de encontrar el entero
28 posicion = vectorBusqueda.busquedaBinaria( busquedaInt );
29
30 // el valor de retorno de -1 indica que no se encontr el entero
31 if ( posicion == -1 )
32 cout << "El entero " << busquedaInt << " no se encontro.\n";
33 else
34 cout << "El entero " << busquedaInt
35 << " se encontro en la posicion " << posicion << ".\n";
36
37 // obtiene la entrada del usuario
38 cout << "\n\nEscriba un valor entero (-1 para terminar): ";
39 cin >> busquedaInt; // lee un valor int del usuario
40 cout << endl;
41 } // fin de while
42
43 return 0;
44 } // fin de main

27 30 32 33 36 40 57 60 73 76 83 88 94 96 99
Escriba un valor entero (-1 para terminar): 33
27 30 32 33 36 40 57 60 73 76 83 88 94 96 99
27 30 32 33 36 40 57
El entero 33 se encontro en la posicion 3.

Escriba un valor entero (-1 para terminar): 96
*

27 30 32 33 36 40 57 60 73 76 83 88 94 96 99
73 76 83 88 94 96 99
94 96 99
El entero 96 se encontro en la posicion 13.
Figura 19.4 | Programa de prueba de BusquedaBinaria. (Parte 1 de 2).

Escriba un valor entero (-1 para terminar): 25
27 30 32 33 36 40 57 60 73 76 83 88 94 96 99
27 30 32 33 36 40 57
27 30 32
27
El entero 25 no se encontro.

Escriba un valor entero (-1 para terminar): -1
Figura 19.4 | Programa de prueba de BusquedaBinaria. (Parte 2 de 2).


Eficiencia de la bsqueda binaria
En el peor de los casos, el proceso de buscar en un vector ordenado de 1023 elementos slo requiere 10 comparaciones
cuando se utiliza una bsqueda binaria. Al dividir 1023 entre 2 en forma repetida (ya que despus de cada comparacin
podemos eliminar la mitad del vector) y redondear ( porque tambin eliminamos el elemento medio), se producen los valo-
res 511, 255, 127, 63, 31, 15, 7, 3, 1 y 0. El nmero 1023 (2
10
- 1) se divide entre 2 slo 10 veces para obtener el valor
0, que indica que no hay ms elementos para probar. La divisin entre 2 equivale a una comparacin en el algoritmo
de bsqueda binaria. Por ende, un vector de 1,048,575 (2
20
- 1) elementos requiere un mximo de 20 comparaciones
para encontrar la clave, y un vector de ms de mil millones de elementos requiere un mximo de 30 comparaciones para
encontrar la clave. sta es una enorme mejora en el rendimiento, en comparacin con la bsqueda lineal. Para un vector
de mil millones de elementos, sta es una diferencia entre un promedio de 500 millones de comparaciones para la bs-
queda lineal, y un mximo de slo 30 comparaciones para la bsqueda binaria! El nmero mximo de comparaciones
necesarias para la bsqueda binaria de cualquier vector ordenado es el exponente de la primera potencia de 2 mayor
que
el nmero de elementos en el vector, que se representa como log
2
n. Todos los logaritmos crecen aproximadamente a
la
misma proporcin, por lo que en notacin Big O se puede omitir la base. Esto produce un valor Big O de O(log n)
para
una bsqueda binaria, que tambin se conoce como tiempo de ejecucin logartmico y se pronuncia en el orden
de
log n, o en forma ms simple como orden log n.

Algoritmos de ordenamiento
El ordenamiento de datos (es decir, colocar los datos en cierto orden especfico, como ascendente o descendente) es
una
de las aplicaciones computacionales ms importantes. Un banco ordena todos los cheques por nmero de cuenta, de
manera que pueda preparar instrucciones bancarias individuales al final de cada mes. Las compaas telefnicas orde-
nan sus listas de cuentas por apellido paterno y luego por primer nombre, para facilitar el proceso de buscar nmeros
telefnicos. Casi cualquier organizacin debe ordenar datos, y a menudo cantidades masivas de ellos. El ordenamiento
de datos es un problema intrigante, que requiere un uso intensivo de la computadora, y ha atrado un enorme esfuerzo
de
investigacin.
Un punto importante a comprender acerca del ordenamiento es que el resultado final (el vector ordenado) ser
el mismo, sin importar qu algoritmo se utilice para ordenarlo. La eleccin del algoritmo slo afecta al tiempo de
ejecucin y el uso que haga el programa de la memoria. En captulos anteriores presentamos el ordenamiento por
seleccin y el ordenamiento por insercin: algoritmos simples de implementar pero ineficientes. En la siguiente seccin
examinaremos la eficiencia de estos dos algoritmos, usando la notacin Big O.



Repaso
En este captulo vimos cmo realizar bsquedas y ordenar datos. Hablamos sobre el algoritmo de bsqueda binaria, que
es ms rpido pero ms complejo que la bsqueda lineal (seccin 7.7). El algoritmo de bsqueda binaria slo funciona
con un arreglo ordenado, pero cada iteracin de la bsqueda binaria deja fuera a la mitad de los elementos en el arreglo.
Tambin vimos el algoritmo de ordenamiento por combinacin, que es ms eficiente que el ordenamiento por insercin
(seccin 7.8) o el ordenamiento por seleccin (seccin 8.6). Adems presentamos la notacin Big O, que nos ayuda a
expresar la eficiencia de un algoritmo. La notacin Big O mide el tiempo de ejecucin para un algoritmo en el peor caso.
El valor Big O es til para comparar algoritmos y seleccionar el ms eficiente. En el siguiente captulo aprender acerca
de las estructuras dinmicas de datos que pueden aumentar o reducir su tamao en tiempo de ejecucin.

También podría gustarte