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

Busqueda Interna

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

Universidad Nacional Autónoma de Nicaragua, Managua

UNAN-Managua
Facultad de Ciencias e Ingenierías
Departamento de Computación

Búsqueda interna
Introducción.

La búsqueda es una de las operaciones más importantes en el procesamiento de la información,


permite la recuperación de datos previamente almacenados, se puede aplicar sobre elementos que se
encuentren ordenados o en elementos desordenados.
El proceso de encontrar un elemento en un conjunto de datos se denomina búsqueda.
La búsqueda interna hace referencia a que todos los elementos de una estructura ya sea estática o
dinámica, se encuentren almacenados en la memoria principal.
Los algoritmos de búsqueda tienen dos finalidades:
 Determinar si el elemento buscado se encuentra en el conjunto de datos donde se busca.
 Si el elemento se encuentra en el conjunto de datos, mostrar la posición en la que se encuentra.
En el presente trabajo, explicaremos los algoritmos de: búsqueda secuencial, búsqueda binaria y
búsqueda mediante transformación de claves (Hash).
Búsqueda secuencial.
Este método también es llamado búsqueda lineal, consiste en revisar la estructura de datos elemento
por elemento e ir comparando con el valor buscado, este procedimiento se realiza hasta que se
encuentra el elemento buscado o se han revisado todos los valores de la estructura.
Algoritmo de la búsqueda secuencial.

Iniciar con el primer registro de


la estructura.

¿lista
vacía? Si

No El elemento no
se encontró. Fin.

Si
Valor=
arre[i]

No

El elemento
Avanzar al siguiente se encontró.
registro. Fin.

¿Fin de
No la lista? Si
Ejemplo práctico.
Se tiene el siguiente arreglo y se está buscando el número 24.

Elementos 7 5 13 10 24 17 3 14

Posiciones 0 1 2 3 4 5 6 7

Posición del número 24 × × × × 4 × × ×

Análisis de eficiencia.
El método de búsqueda secuencial tiene una complejidad lineal O (n) esto en el peor de los casos que
se da cuando el elemento buscado no se encuentra en la lista o se encuentra en la última posición, el
mejor caso se presenta cuando el valor buscado se encuentra en la primera posición, es decir, solo
realiza una comparación, en este caso el tiempo de ejecución es O (1).

Ventajas.
 Es el algoritmo de búsqueda más sencillo.
 Fácil implementación.
 No requiere ningún proceso previo de los datos.
 Es un método seguro, ya que revisa cada elemento sin brincar ninguno.
 No requiere memoria auxiliar.

Desventajas.
 Es un método muy lento, realiza numerosas comparaciones.
 No es muy eficiente cuando los datos están ordenados o cuando la lista de elementos es de
gran tamaño.
Búsqueda binaria.
Este algoritmo se basa en la técnica de divide y vencerás, consiste en dividir el arreglo en dos
sublistas, se identifica el elemento central y se compara con el valor buscado, en caso de no ser
iguales, se determina si el elemento buscado es menor o mayor al elemento central, para determinar
si la búsqueda continua del lado izquierdo (menor) o derecho (mayor) del central, este procedimiento
de división y comparación se realiza hasta encontrar el elemento buscado o que la división ya no sea
posible.
Es importante destacar que este método solo funciona con estructuras de datos previamente
ordenadas, dividiendo a la mitad el proceso de búsqueda en cada iteración, lo que hace que el método
sea más eficiente.

Ejemplo práctico.
Se tiene el siguiente arreglo con los datos ya ordenados y se desea encontrar el número 15.

Mostrar su índice.

Elementos 3 6 9 11 12 14 15 18

Posiciones 0 1 2 3 4 5 6 7

Posición del número 15 × × × × x × 6 ×

Análisis de eficiencia.
El mejor caso se presenta cuando el elemento buscado se encuentra en la posición central del arreglo,
en este caso la complejidad es O (1) dado que solo se realiza una comparación. El peor caso se produce
cuando se debe continuar la búsqueda hasta llegar a una sublista de longitud 1 o cuando el elemento
buscado no se encuentra en el arreglo, cuando esto se presenta la complejidad es O (log2n).
Algoritmo de la búsqueda binaria.

Inicio

Bajo=1 Alto=N

𝐴𝑙𝑡𝑜 + 𝐵𝑎𝑗𝑜
𝑐𝑒𝑛𝑡𝑟𝑎𝑙 =
2

Mientras Bajo<Alto && are[central] !=valor

Valor<are[central] Si
Alto=central-1

No

Bajo=central+1

𝐴𝑙𝑡𝑜 + 𝐵𝑎𝑗𝑜
𝑐𝑒𝑛𝑡𝑟𝑎𝑙 =
2

Valor no se Valor=
No Si Valor se encuentra en la
encuentra. are[central] posición (central)

Fin
Ventajas.
 Es el método más eficiente cuando se trabaja con estructuras ordenadas.
 Fácil implementación, el código de este método es corto en comparación con otras técnicas
de búsqueda.
 Reduce el tiempo de búsqueda de un elemento.
 Es factible para estructuras de grandes tamaños de datos.
 No requiere memoria auxiliar.

Desventajas.
 La estructura de datos con la que se trabaja debe estar previamente ordenada.

Búsqueda por transformación de claves (Hash).

Para trabajar con este método de búsqueda se debe elegir previamente:


 Una función hash que distribuya uniformemente las direcciones.
 Un método para el tratamiento a colisiones.

Hash.
Es un número que representa un objeto.
Función Hash.
Es una función que recibe como parámetro un objeto y devuelve un número tal que se cumple:
 Para el mismo objeto, la función siempre devuelve el mismo número hash.
 Si dos objetos son iguales, entonces deben tener el mismo número hash.
 Si dos objetos son distintos, en la medida de lo posible, no deben tener el mismo número
hash.
Cuando dos objetos distintos tienen el mismo número hash, se presenta una colisión.
 Si una función hash no presenta colisiones se dice que es “perfecta”.

Una función hash ideal debería ser biyectiva, es decir, que a cada elemento le corresponda
un índice, y a cada índice le corresponda un elemento. La función hash depende de cada
problema y cada finalidad, esta se puede aplicar ya sea con números o cadenas de
caracteres.
El principal objetivo de este método es accesar directamente a los datos almacenados en un
arreglo a través de la clave generada por la función hash con la que fueron insertados los
datos.

Funciones hash más utilizadas:

 La forma más sencilla asignar directamente los elementos, es decir al 0 le corresponde el


índice 0, al 1 el 1, y así sucesivamente, pero cuando los elementos son muy grandes se
desperdicia espacio ya que se necesita un arreglo de gran tamaño para almacenarlo y entre
los elementos quedan muchos espacios libres.

 Mitad de cuadrado: Esto consiste en elevar al cuadrado el valor y tomar las cifras centrales
del resultado, en caso que la cifra resultante sea impar se toma el valor número y el anterior.
Ejemplo:
879^2=772641>26

 Restas sucesivas: Esta función se emplea con claves numéricas entre las que hay espacios
de tamaño conocido, obteniéndose como resultado direcciones consecutivas.

 Aritmética modular: El índice de un elemento es el resto de la división de ese elemento


entre un número N prefijado, preferentemente primo, el más cercano al tamaño de la
estructura.

Ejemplo:
Si N vale 7, el índice los siguientes elementos serían:
5033>>0.
8471>>1.

 Plegamiento: consiste en dividir el número en diferentes partes, para luego operar con ellas
por ejemplo (suma o multiplicación).
Ejemplo:
se tiene el siguiente número de 7 cifras 3403782 si lo dividimos en 2, 2, y 3 cifras y luego
lo sumamos, el índice será el resultado.
3403782= 34+03+782= 819.

Tratamiento de colisiones.

 Hash abierto
consiste en asignarle una lista a una posición en la que se presente colisión, de esta forma,
al tener varios elementos con el mismo valor hash estos se van almacenando en la lista de la
posición dada por el valor generado.

 Hash cerrado
Este método lo que hace es buscar una nueva posición en la estructura. La elección de la
posición donde el elemento que presenta colisión será almacenado se puede hacer mediante
una nueva función hash, o eligiendo la próxima posición vacía en la estructura.

Pos = h(x) + i, el valor de i comienza en 1, y se incrementa en caso de que la posición esté


ocupada.
1. Posición = h(x) + I, I = 1, 2, 3, 4…: exploración lineal.

2. Posición = h(x) + I2, I=1, 2, 3, 4…: exploración cuadrática

3. Posición = h(x) + polinomio (I), I=1, 2, 3, 4…: exploración polinomial.


Se ha observado un problema en el hash cerrado, llamado aglomeramiento. Al haber varias colisiones
y resolverlas buscando la próxima ubicación libre, se forman grupos de datos densos, que no tienen
espacios libres entre sus elementos. Esto es un problema importante porque disminuye la performance
de la búsqueda, inserción y borrado de la tabla, le quita los beneficios a la técnica hashing.
Algoritmo del método hash.

Inicio

Ingresar el dato a
buscar.

Elaborar_clave (valor_buscar)

No
¿Clave está Valor no se
ocupada? encuentra.

Si

No
¿Valor está en la lista? Valor no se
encuentra.

Si

Valor se encuentra en la
Fin
posición: clave
Análisis de eficiencia.
Este algoritmo presenta una eficiencia aproximada O (k), donde k es una constante, es decir que
trabaja casi de forma independiente a la cantidad de elementos que se encuentran en la estructura.
Ventajas.
 Permite el acceso de forma casi directa a los datos.

 El tiempo de búsqueda es independiente al tamaño de la estructura, lo que permite trabajar


con estructuras de gran tamaño.

 No requiere ningún procedimiento previo de los datos.

 Se puede determinar si el elemento buscado se encuentra o no, sin recorrer toda la estructura,
ni realizar muchas comparaciones.
Desventajas.
 Es un método eficiente en inserción y búsqueda, pero su implementación es compleja.

 Requiere memoria adicional.

Código fuente búsqueda Lineal y búsqueda binaria

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;

namespace Ejemplo_de_archivo
{
class Program
{
static void CrearArchivo(ref int i)
{
Console.Clear();
FileStream stream = null;
BinaryWriter escribir = null;
i = 0;
try
{
stream = new FileStream("Archivo", FileMode.Create, FileAccess.Write);
escribir = new BinaryWriter(stream);
char resp;
do
{
i++;
Console.Write("Digite el valor #{0}: ", i);
int valor = int.Parse(Console.ReadLine());
escribir.Write(valor);
Console.Write("Desea agregar otro valor? ");
resp = char.Parse(Console.ReadLine());
} while (resp == 's' || resp == 'S');
}
catch (IOException e)
{
Console.WriteLine("ERROR" + e.Message);
}
finally
{
stream.Close();
escribir.Close();
Console.WriteLine();
Console.WriteLine("EL ARCHIVO SE CREO EXITOSAMENTE");
}
}

static void Crear_Archivo_Aleatorio(ref int i)


{
Console.Clear();
FileStream stream = null;
BinaryWriter escribir = null;

try
{
stream = new FileStream("Archivo", FileMode.Create, FileAccess.Write);
escribir = new BinaryWriter(stream);
Random r = new Random();
Console.WriteLine("Se ingresaran 5 elementos aleatorios...");
for (int a = 0; a<5;a++ )
escribir.Write(r.Next(0, 100));
/*char resp;
do
{
i++;
Console.Write("Digite el valor #{0}: ", i);
int valor = int.Parse(Console.ReadLine());
escribir.Write(valor);
Console.Write("Desea agregar otro valor? ");
resp = char.Parse(Console.ReadLine());
} while (resp == 's' || resp == 'S');*/

}
catch (IOException e)
{
Console.WriteLine("ERROR" + e.Message);
}
finally
{
stream.Close();
escribir.Close();
Console.WriteLine();
Console.WriteLine("EL ARCHIVO SE CREO EXITOSAMENTE");
}
}

static int Lectura()


{
int g = 0;
BinaryReader leer = null;
try
{
if (File.Exists("Archivo"))
{
leer = new BinaryReader(new FileStream("Archivo", FileMode.Open,
FileAccess.Read));
do
{
int num = leer.ReadInt32();
g++;
} while (true);
}
}
catch (EndOfStreamException)
{
}
finally
{
if (leer != null)
leer.Close();
}
return g;
}

static int[] LeerArchivo(int i)


{
if (i == 0)
i = Lectura();
int[] vector = new int[i];
BinaryReader leer = null;
try
{
if (File.Exists("Archivo"))
{
leer = new BinaryReader(new FileStream("Archivo", FileMode.Open,
FileAccess.Read));
int g = 0;
Console.WriteLine();
do
{
int num = leer.ReadInt32();
vector[g] = num;
g++;
} while (true);
}
}
catch (EndOfStreamException)
{

}
finally
{
if (leer != null)
{
leer.Close();
}
}

return vector;
}

static void Impresion(int[]arreglo)


{
for (int i = 0; i < arreglo.Length; i++)
Console.Write(" " + arreglo[i]);
}
static void Busqueda_Lineal(int[] arreglo, int i)
{
arreglo = LeerArchivo(i);
int[] Lineal = arreglo;
Console.WriteLine("Ingrese un numero a buscar: ");
int a = int.Parse(Console.ReadLine());
int b = 0;
bool band = false;
while(b<Lineal.Length)
{
if (a == Lineal[b])
{
Console.WriteLine("{0} encontrado en la posicion {1}", a, b);
b = Lineal.Length;
band = true;
}
b++;
}
if (!band)
Console.WriteLine("{0} no se encuentra en el arreglo...", a);
Console.WriteLine("\n\n----Fin del metodo----");
Lineal = null;
}

static void Busqueda_Binaria(int[] arreglo)


{
int[] Binario = arreglo;
Array.Sort(Binario);
Console.WriteLine("Este es el arreglo ordenado: ");
for(int i = 0;i<Binario.Length;i++)
Console.Write(" " + Binario[i]);
int valor, alto, central, bajo;
Console.WriteLine("\n\n\nIngresa un valor a buscar: ");
valor = int.Parse(Console.ReadLine());
bajo = 0;
alto = Binario.Length - 1;
central = (bajo + alto) / 2;
while(bajo<=alto && Binario[central]!=valor)
{
if (valor < Binario[central])
alto = central - 1;
else
bajo = central + 1;
central = (bajo + alto) / 2;
}
if (valor == Binario[central])
Console.WriteLine("El valor se encuentra el la posicion {0}", central);
else
Console.WriteLine("El valor no se encuentra");
Console.WriteLine("\n\n----Fin del metodo----");
Binario = null;
}

static void Main(string[] args)


{

int opc;
int i = 0;
int[] vector = { };

do
{

Console.Clear();
Console.WriteLine("\n MENU\n");
Console.WriteLine(" 1. Crear archivo de números enteros");
Console.WriteLine(" 2. Crear archivo con inserciones aleatorias");
Console.WriteLine(" 3. Enviar el archivo a la memoria(en forma de Arreglo)");
Console.WriteLine(" 4. Imprimir el arreglo");
Console.WriteLine(" 5. Busqueda Lineal");
Console.WriteLine(" 6. Busqueda Binaria");
Console.WriteLine(" 7. Salir\n");
Console.Write("Seleccione una opcion del MENU: ");
opc = int.Parse(Console.ReadLine());
switch (opc)
{
case 1: CrearArchivo(ref i); break;
case 2: Crear_Archivo_Aleatorio(ref i); break;
case 3: vector = LeerArchivo(i); break;
case 4: Console.Clear();
Console.WriteLine("Impresion del arreglo: ");
Impresion(vector);
break;
case 5: Busqueda_Lineal(vector, i);break;
case 6: Busqueda_Binaria(vector); break;
case 7: Console.WriteLine("Saliendo del programa..."); break;
default: Console.WriteLine("Digite un valor del menu."); break;
}
Console.ReadKey();
} while (opc != 7);
}
}
}

Código Fuente de transformación de clave Hash


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;

namespace Hash_con_Archivos
{
public class Listas
{
class Nodo
{
public string info;
public Nodo sig;
}

private Nodo raiz;

public Listas()
{
raiz = null;
}

Nodo Crear_Nodo(string elemento)


{
string valor = elemento;
Nodo q = new Nodo();
q.info = valor;
q.sig = null;
return q;
}

public void Crear_lista(string elemento)


{
Nodo t;
raiz = Crear_Nodo(elemento);
t = raiz;
}

public void Insertar_al_final(string elemento)


{
Nodo t;
Nodo nuevo;
t = raiz;
while (t.sig != null)
t = t.sig;
nuevo = Crear_Nodo(elemento);
t.sig = nuevo;
}

public void Imprimir()


{
Nodo q;
q = raiz;
Console.Write(" ");
while (q != null)
{
Console.Write("{0}", q.info);
q = q.sig;
if (q != null)
Console.Write(", ");
}
}

public void Busqueda(string elemento, int indice)


{
Nodo q;
bool band = true;
q = raiz;
while (q.info != elemento && band)
{
if (q.sig != null)
q = q.sig;
else
band = false;
}
if (!band)
Console.WriteLine(elemento + " No se encuentra en la Tabla");
else
Console.WriteLine(elemento + " Si se encuentra en la Tabla en el Hash: " + indice);
}
public void Eliminar(string elemento)
{
Nodo q;
Nodo t;
bool band = true;
q = raiz;
t = raiz;
while (q.info != elemento && band)
{
if (q.sig != null)
{
t = q;
q = q.sig;
}
else
band = false;
}
if (!band)
Console.WriteLine(elemento + " No existe en la Tabla");
else
{
if (raiz == q)
raiz = q.sig;
else
t.sig = q.sig;
Console.WriteLine(elemento + " Fue eliminado de la tabla");
q = null;
}
}
}

class Hash
{
public void Crear_Archivo_Hash(ref int i, Hashing h)
{
Console.Clear();
FileStream stream = null;
BinaryWriter escribir = null;
i = 0;
try
{
stream = new FileStream("Archivo_Hash", FileMode.Create, FileAccess.Write);
escribir = new BinaryWriter(stream);
char resp;
do
{
i++;
Console.WriteLine("Ingrese los elementos a insertar: ");
string elemento = Console.ReadLine();
escribir.Write(elemento);
Console.WriteLine("Desea ingresar otro elemento? ");
resp = char.Parse(Console.ReadLine());
}while(resp == 's' || resp =='S');
}
catch (IOException e)
{
Console.WriteLine("Error" + e.Message);
}

finally
{
stream.Close();
escribir.Close();
Console.WriteLine("\n\nEl archivo fue creado exitosamente");
Console.WriteLine("Regresando al menu");
}
}

public int Lectura_Hash()


{
int g = 0;
BinaryReader leer = null;
try
{
if(File.Exists("Archivo_Hash"))
{
leer = new BinaryReader(new FileStream("Archivo_Hash", FileMode.Open,
FileAccess.Read));
do
{
string elemento = leer.ReadString();
g++;
} while (true);
}
}
catch(EndOfStreamException)
{
}
finally
{
if (leer != null)
leer.Close();
}
return g;
}
public void Leer_Archivo_Hash(int i, Hashing h)
{
Console.Clear();
if (i == 0)
i = Lectura_Hash();

BinaryReader leer = null;


try
{
if(File.Exists("Archivo_Hash"))
{
leer = new BinaryReader(new FileStream("Archivo_Hash", FileMode.Open,
FileAccess.Read));
do
{
string elemento = leer.ReadString();
Funcion_Hash(elemento, h);
} while (true);
}
}
catch(EndOfStreamException)
{
Console.WriteLine();
}
finally
{
if (leer != null)
leer.Close();
}

}
public struct hash
{
public Listas lista;
public void l()
{
lista = new Listas();
}
}

public struct Hashing


{
public hash[] arreglo;
public void arre()
{
arreglo = new hash[97];
}
}
int Metodo_Hash(string palabra)
{
int indice = 0;
for (int i = 0; i < palabra.Length; i++)
indice += (int)palabra[i];
indice %= 97;
return indice;
}//Generador del Hash

void Funcion_Hash(string elemento, Hashing h)


{
int indice = Metodo_Hash(elemento);
if (h.arreglo[indice].lista == null)
{
h.arreglo[indice].l();
h.arreglo[indice].lista.Crear_lista(elemento);
}
else
h.arreglo[indice].lista.Insertar_al_final(elemento);
}

void Mostrar(Hashing h)
{
for (int i = 0; i < h.arreglo.Length; i++)
{
Console.Write("Para el Hash {0,2}: ", i);

if (h.arreglo[i].lista != null)
h.arreglo[i].lista.Imprimir();
Console.WriteLine();

}
Console.ReadKey();
}

void Buscar(Hashing h)
{
string buscador;
Pedir("Ingresa el valor a buscar: ", out buscador);
int indice = Metodo_Hash(buscador);
if (h.arreglo[indice].lista == null)
Console.WriteLine("EL elemento " + buscador + " no se encuentra en la Tabla");
else
h.arreglo[indice].lista.Busqueda(buscador, indice);
Console.ReadKey();
char op;
Pedir("Desea buscar otro elemento en la Tabla: S/N", out op);
op = char.ToLower(op);
if (op == 's')
Buscar(h);
}

/*void Eliminar(Hashing h)
{
string elemento;
Pedir("Ingresa el elemento que desea eliminar de la tabla: ", out elemento);
int indice = Metodo_Hash(elemento);
if (h.arreglo[indice].lista == null)
Console.WriteLine(elemento + " No existe en la Tabla");
else
h.arreglo[indice].lista.Eliminar(elemento);
Console.ReadKey();
}*/

/*void Eliminar_Hash(Hashing h)
{
int indice;
Pedir("Ingresa el Hash a eliminar: ", out indice);
while (indice < 0 || indice > 96)
Pedir("Ingrese un Hash valido: ", out indice);
if (h.arreglo[indice].lista == null)
Console.WriteLine("El hash se encontraba Vacio");
else
{
h.arreglo[indice].lista = null;
Console.WriteLine("Hash " + indice + " eliminado");
}
Console.ReadKey();
}*/

/*void Eliminar_Tabla(Hashing h)
{
for (int i = 0; i < h.arreglo.Length; i++)
h.arreglo[i].lista = null;
Console.WriteLine("Tabla Hash Eliminada");
Console.ReadKey();
}*/

void Menu()
{
Console.WriteLine("Presiona 1 para crear un archivo");
Console.WriteLine("Presiona 2 para mandar el archivo a la memoria(necesario para
la busqueda interna)");
Console.WriteLine("Presiona 3 para mostrar todos los elementos de la Tabla");
Console.WriteLine("Presiona 4 para buscar un elemento en la Tabla");
//Console.WriteLine("Presiona 5 para eliminar un elemento en la Tabla");
//Console.WriteLine("Presiona 6 para eliminar un Hash de la Tabla");
//Console.WriteLine("Presiona 7 para eliminar la Tabla Hash");
Console.WriteLine("Presiona 0 para salir");
}

public void Ejecutar()


{
Hashing h = new Hashing();
h.arre();
int i = 0;
int op;
do
{
Console.Clear();
Menu();
Pedir("Ingresa una opcion: ", out op);

switch (op)
{
case 1: Crear_Archivo_Hash(ref i, h);
break;
case 2: Leer_Archivo_Hash(i, h);
break;
case 3: Mostrar(h);
break;
case 4: Buscar(h);
break;
//case 5: Eliminar(h);
// break;
//case 6: Eliminar_Hash(h);
// break;
//case 7: Eliminar_Tabla(h);
// break;
case 0: Console.WriteLine("Saliendo del programa"); Console.ReadKey();
break;
default: Console.WriteLine("Opcion incorrecta"); Console.ReadKey();
break;
}
} while (op != 0);
}

void Pedir(string ped, out string x)


{
Console.WriteLine(ped);
x = Console.ReadLine();
}
void Pedir(string ped, out int x)
{
Console.WriteLine(ped);
x = int.Parse(Console.ReadLine());
}

void Pedir(string ped, out char x)


{
Console.WriteLine(ped);
x = char.Parse(Console.ReadLine());
}
}

class Program
{
static void Main(string[] args)
{
Hash programa = new Hash();
programa.Ejecutar();
}
}
}

También podría gustarte