Está en la página 1de 13

Ejercicios de aplicación de las estructuras de datos

Entrega Final - Semana 7

Peña Juan Pablo


Peñaloza González Carlos Ernesto
Orozco Tabares Kelly Andrea
Orjuela Vargas Cristian Camilo

Prof. Edwin Niño

Universidad Politécnico Grancolombiano


Facultad de ingeniería y Diseño
Estructura de Datos grupo B01-Sub Grupo 17
03 de mayo de 2022
Semana 7

1. Implemente un método que, dado un árbol binario ordenado y un valor, retorne el sucesor

del valor en el árbol. Calcule la complejidad temporal del método.

Solución

import java.util.ArrayList;
import java.util.List;
public class SucesorVEDArbin<E> {
protected Integer val;
protected SucesorVEDArbin<Integer> izq;
protected SucesorVEDArbin<Integer> der;
//Arbol Vacio
public SucesorVEDArbin() {
val=null;
izq=null;
der=null;
}
//Arbol no vacío
public SucesorVEDArbin (Integer pVal, SucesorVEDArbin<Integer> pIzq,
SucesorVEDArbin<Integer> pDer) {
if (pVal==null) {
throw new NullPointerException ("¡Un Arbol no vacío debe tener
raíz!");}
if (pIzq==null) {
throw new NullPointerException ("¡Un Arbol no vacío debe tener
Subárbol izquierdo");}
if (pDer==null) {
throw new NullPointerException ("¡Un Arbol no vacío debe tener
Subárbol Derecho!");}
val=pVal;
izq=pIzq;
der=pDer;
}
public static <E> void main(String[] args) {
// Crear nuevo Arbol
SucesorVEDArbin<Integer> nArbol=new SucesorVEDArbin<>();
int Cantnodos=ent_ramdom()/2;
//Invocar Insertar elementos en el arbol
for(int i=0;i<Cantnodos;i++) {
int Elemento=ent_ramdom();
if (nArbol.Buscar(Elemento)) { //si el elemento se repite no aumenta i y
//busca otro elemento; usamos metodo busqueda
i--;}
else {nArbol.insertar(Elemento);}//Si elemento no es repetido se
//inserta en el arbol;Usamos metodo busqueda
}
//Imprimir raiz y Recorrido
System.out.println("Dado el Arbol de busqueda");
System.out.println(nArbol.inorden());
System.out.println("\n");

//Buscar elemento en el Arbol, su sucesor e imprimir respuesta.


int nBusqueda = ent_ramdom();
if(nArbol.Buscar(nBusqueda)) {
if(nArbol.inordenSucesor(nBusqueda)!=null){ System.out.println("El número
"+nBusqueda+" si se encuentra en el Árbol, Su sucesor es el número "
+ ""+nArbol.inordenSucesor(nBusqueda)+".");}
else {System.out.println("El número "+nBusqueda+" si se encuentra en el
Árbol pero no tiene sucesor porque es el mayor elemento del arbol.");}
}else {System.out.println("El número "+nBusqueda+" No se encuentra en el
Árbol.");}
}

//Método insertar
public void insertar (Integer nElemento) {
if(esVacio()) {
this.val=nElemento;
this.izq= new SucesorVEDArbin<>();
this.der= new SucesorVEDArbin<>();
}else {
if(this.val>nElemento) {
if (this.izq==null) {
this.izq=new SucesorVEDArbin<>(nElemento,new
SucesorVEDArbin<>(),new SucesorVEDArbin<>());
}else {this.izq.insertar(nElemento);}
}else {
if(this.der==null) {
this.der= new SucesorVEDArbin<>(nElemento,new
SucesorVEDArbin<>(),new SucesorVEDArbin<>());
}else {
this.der.insertar(nElemento);
}
}
}
}
//***********Sub 17 Método Recursivo Buscar Elemento en el
//arbol******************************

public boolean Buscar (Integer bElemento) {


if(esVacio()) {//si es el arbol es vacio el elemento no existe, por tanto no está
return false;}
else if(this.val==bElemento) { // si la raiz es el elemento retorna true |el mejor
//caso|
return true;}
else if(bElemento<this.val){
if(this.izq!=null) {
return this.izq.Buscar(bElemento);}}//si el elemento es menor que la
//raiz y el subárbol izquierdo no es nulo, recorre cada sunárbol izquierdo.
else if(this.der!=null){
return this.der.Buscar(bElemento);//si no encontró el elemento en los
//subárbol izquierdo, recorre cada subárbol Derecho no nulo, hasta el último seria |peor Caso|
} // recorre una vez todos los nodos del Arbol.
return false; // si no encuentra el elemento en ningun nodo, retorna false.
}

//************-*-*-*-*-*-*Sub 17 _Método encontrar sucesor de número*-*-*-*-**-*-*-*-


//*-**********************

public Integer inordenSucesor(Integer num){// Modificamos el método de recorrido


//inorden, para obtener el indice 0 de una lista que contiene solamente los

//numeros mayores en recorrido inorden


List<Integer> lista=new ArrayList<>();
inordenSucesor(lista,num);
if (lista.isEmpty()) { // si la lista de inorden es vacia retornamos null
return null;
}else { // si la lista no es vacia retornamos el elemento de indice 0, el cual es
//el sucesor.
return lista.get(0);
}
}
private void inordenSucesor(List<Integer> pLista,Integer num) {
if(esVacio()){
}else {
izq.inordenSucesor(pLista,num);
if (val>num) { // solamente adicionamos a a la lista los números
//mayores al número el cual se busca su sucesor, el Peor Caso O(n), en caso de que el
//numero buscado sea el último de la lista
pLista.add(val);}
der.inordenSucesor(pLista,num);
}
}
//**************************************************************************
//**********
// generar números ramdom
public static int ent_ramdom() {
int entero=0;
double d = Math.random();
entero= (int) (d*100);
return entero;
}
//Evaluar si está Vacío el Arbol.
public boolean esVacio() {
if(val==null) {
return true;
}else {
return false;
}
}
//************************************************************
public List<Integer> preorden(){
List<Integer> lista=new ArrayList<>();
preorden(lista);
return lista;
}
private void preorden(List<Integer> pLista) {
if(esVacio()) {
}else {
pLista.add(val);
izq.preorden(pLista);
der.preorden(pLista);
}
}
//***************************************************************
public List<Integer> inorden(){
List<Integer> lista=new ArrayList<>();
inorden(lista);
return lista;
}
private void inorden(List<Integer> pLista) {
if(esVacio()) {
}else {
izq.inorden(pLista);
pLista.add(val);
der.inorden(pLista);
}
}
//****************************************************************
public List<Integer> posorden(){
List<Integer> lista=new ArrayList<>();
posorden(lista);
return lista;
}
private void posorden(List<Integer> pLista) {
if(esVacio()) {
}else {
izq.posorden(pLista);
der.posorden(pLista);
pLista.add(val);
}
}
public Integer getVal() {
return val;
}
public SucesorVEDArbin<Integer> getIzq() {
return izq;
}
public SucesorVEDArbin<Integer> getDer() {
return der;
}
}

2. Investigue en qué consiste cada una de las siguientes estrategias de resolución de colisiones

en tablas hash y para cada una de ellas proponga un ejemplo:

A. Sondeo lineal

B. Sondeo cuadrático

C. Doble hash

Solución

A. Sondeo lineal: es un esquema utilizado en la programación de computadores para resolver

colisiones (recordando que se presenta una colisión cuando tenemos 2 valores

diferentes en un mismo índice) en tablas hash. Busca sostener la colección de pares-

clave-valor y buscar, asociado a una clave determinada. Se creó en 1954 Gene Amdahl,

Elaine M. McGraw y Arthur Samuel. Junto con el sondeo cuadrático y el de hash doble,

el sondeo lineal es una forma de direccionamiento abierto (método que resuelve las

colisiones con sondeos, o buscando a través de ubicaciones alternas dentro de la matriz

hasta encontrar una ranura que no esté utilizada). Puntualmente el sondeo lineal se

ejecuta al momento en el que la función hash provoca una colisión al asignar una nueva

clave a una celda de la tabla hash que ya está ocupada por otra clave, eventualmente el

sondeo lineal buscará en la propia tabla la siguiente ubicación libre más cercana para

insertar en ese espacio la nueva clave (Hmn. Wiki).


Esta solución es la más compleja y no es la más óptima (de O(n)), ya que el algoritmo

tendría que buscar 1 por 1 en los índices hasta encontrar un espacio vacío para el

elemento, lo que retardaría la ejecución cuando partimos de muchos distintos

elementos. (Vida MRR - Diseño y desarrollo web)

Ejemplo de sondeo lineal:

(Fuente: elaboración propia)


Clave Valor Función hash N
esteban 56231132 hash 738 0 4856941
esteban -
milena 4854941 738mod10=8 1
56231132
pedro 148989 La función hash, el cual consistiría Index 8 2
en el siguiente algoritmo: mapear las 3
letras de cada letra de los nombres hash 630 4
milena -
y transformarlos en un número por 629mod10=0 5
4856941
medio del valor ASCII de cada Index 0 6
letra y posteriormente sumarlas para 7
finalmente utilizar el operador de hash 538 8 56231132
módulo entre el número de casillas 538mod10=8 9 148989
pedro -
disponibles, en este caso 10. 8 - al estar ocupada la celda 8 el
148989
Index sondeo lienal pasa el valor a la
celda 9

En caso de producirse una colisión, con este método y el uso de un ciclo for o while (int

i=0,i<tablasHash.size(),i++), se buscará si el siguiente índice de la tabla hash está vacío, de no

estarlo, se seguirá buscando hasta encontrarlo; es de aclarar que no solamente se puede buscar

en el siguiente índice, se puede buscar saltando cada 2, 3, 4 etc., índices, pero sigue siendo una

operación lineal, y en caso de que el índice vació esté en la última posición la complejidad sería

O(n).

public static Integer SondeoLineal (ArrayList <Integer>HashSetA, int indiceOriginal) {

for (int i=indiceOriginal; i<HashSetA.size();i++) {

if(HashSetA.get(i)==null) {
return i;
}
}
return null;
}
En este caso como en el cuadrático, retornamos el índice que se encuentra vacío para con otro

método insertar el elemento en dicha posición.

B. Sondeo cuadrático: es un esquema de direccionamiento abierto en programación,

para resolver colisiones hash en tablas hash. El sondeo cuadrático funciona tomando el índice

hash original y agregando valores sucesivos de un polinomio cuadrático arbitrario hasta que se

encuentra una ranura abierta.

El sondeo cuadrático puede ser el algoritmo más eficiente en una tabla de direccionamiento

abierta, porque evita el problema de agrupamiento que puede ocurrir con el sondeo

lineal, aunque no es inmune, también proporciona un buen almacenamiento en la

memoria cache porque conserva alguna localidad de referencia; sin embargo, el sondeo

lineal tiene mayor localidad, por lo que es un mejor rendimiento en cache. (hmong.es).

Simplificando un poco lo anterior el sondeo cuadrático, consiste al igual que en el sondeo lineal

en buscar un índice vacío cuando se produce una colisión; pero en este caso para buscar

dicho índice vacío lo que se hace es que el índice resultado de la función hash se suma

a un contador incremental que está elevado al cuadrado, es decir, si el índice que nos

da la función hash es 8 y el contador está en 3, entonces a 3 se le suma 3 2, si esta

posición no está vacía, el contador se incrementa y a 3 se le suma 42, hasta encontrar el

índice vacío; el problema de este método es que por la naturaleza incremental


cuadrática, puede que haya elementos que no se lleguen a asignar a un índice o índices

que nunca se llenan.

Ejemplo de sondeo cuadrático

Tabla Hash
Elemento Tamaño tabla Hash Indice Contador i Cálculo indice Nuevo Indice Indice elemento
85 21 1 0
14 21 14 1 85
35 21 14 1 14+1 15 2
36 21 15 2 15+4 19 3
12 21 12 4
48 21 6 5 89
89 21 5 6 48
50 21 8 7
41 21 20 8 50
64 21 1 3 1+9 10 9
10 64
11
12 12
13
14 14
15 35
16 37
17
18
19 36
(Fuente : elaboración propia) 20 41

Al igual que en el sondeo lineal para incrementar el contador se puede usar un ciclo for o
while (int i=0, i<tablasHash.size(), i++), sin embargo, en este caso la como i debe estar al
cuadrado entonces la primera línea del método debe contener i=(int) Math.pow(i,2) de esta
manera podemos hacer las operaciones correspondientes y retornar el nuevo índice.

public static Integer SondeoCuadratico (ArrayList <Integer>HashSetA, int indiceOriginal) {

for (int i=indiceOriginal; i<HashSetA.size();i++) {


i=(int) Math.pow(i, 2);
if(HashSetA.get(i)==null) {
return i;
}
}
return null;
}

C. Doble hash: El doble hash es una técnica de programación informática que se utiliza junto

con el direccionamiento abierto en tablas hash para resolver colisiones hash, mediante el uso

de un hash secundario de la clave como compensación cuando se produce una colisión. El hash

doble con direccionamiento abierto es una estructura de datos clásica en una tabla. La técnica

de doble hash utiliza un valor hash como índice en la tabla y luego avanza repetidamente un

intervalo hasta que se encuentra el valor deseado, se alcanza una ubicación vacía o se ha
buscado en toda la tabla; pero este intervalo lo establece una segunda función hash

independiente. A diferencia de los métodos alternativos de resolución de colisiones de sondeo

lineal y sondeo cuadrático el intervalo depende de los datos, por lo que los valores que se

asignan a la misma ubicación tienen diferentes secuencias de cubos.}

El intervalo entre intentos es constante para cada registro, pero es calculado por otra función

hash. (hmong.es)

Ejemplo de Doble Hash

(Acervolima.com)

public static Integer SondeoCuadratico (ArrayList <Integer>HashSetA, int


indiceOriginal,int elemento) {
//por ejemplo para una tabla de tamaño 30, usar el número primo 29 para hallar
un segundo hash
int Clave2=29-(elemento%29);

for (int i=indiceOriginal; i<HashSetA.size();i++) {


if(HashSetA.get(indiceOriginal+i*Clave2)==null) {
return i;
}
}
return null;
}
Como en los dos ejemplos anteriores, lo que retornamos es el índice que se encuentra vacío

para posteriormente insertar el elemento en dicho índice.

3. Escriba una función java que, dados dos arreglos de enteros S = [s0, s1, …, sm-1] y T = [t0,

t1, …, tn-1], decida si S ⊆ T en tiempo esperado O (m + n).

Solución

import java.util.HashSet;
public class Conjuntos<E>{
//Atributos de la clase conjuntos <E>
protected int elementos;
protected int tamanoHashset;
protected HashSet<Integer> TablaHash;
//Metodo constructor
public Conjuntos(int Elem){
elementos=Elem; //Elem aleatorio
tamanoHashset=Elem*4; //Tamaño inicial es Elem * 4, procurando factor de
//carga <30% (La clase por si misma procura factor de carga 0.75)
TablaHash= new HashSet<Integer>(tamanoHashset); //factor de carga <30%
//procurando evitar que la clase redimensione la tabla hash.
}
public static void main(String[] args) {
//Crear conjuntos aleatorios, para probar cualquier instancia del problema
Conjuntos<Integer> ConjuntoS=new Conjuntos<Integer>(NumerosAleatorios()/4);
//Procurar que elementos T>S para prueba del algoritmo.
Conjuntos<Integer> ConjuntoT=new Conjuntos<Integer>(NumerosAleatorios()*2);
//Procurar que elementos T>S para prueba del algoritmo.
ConjuntoS.AgregarElementos(ConjuntoS.TablaHash,ConjuntoS.elementos);
//Agregar elementos a S
ConjuntoT.AgregarElementos(ConjuntoT.TablaHash,ConjuntoT.elementos);
//Agregar elementos a T

//Comparar los conjuntos O(m+n), retorno de metodo boolean


if (CompararConjuntos(ConjuntoS.TablaHash,ConjuntoT.TablaHash)){
System.out.println("El conjunto S está contenido estrictamente en en el conjunto T");
}
else{System.out.println("El conjunto S NO está contenido estrictamente en en el
conjunto T");
}
}
//Metodo agregar elementos
public void AgregarElementos(HashSet<Integer>Conj,int elem){
for (int i=0;i<elem;i++) { //Ciclo agregar elementos aleatorios al conjunto
//instanciado
Conj.add(NumerosAleatorios());
}
}

//Método comparar conjuntos


public static boolean CompararConjuntos(HashSet<Integer> ConjuntoS,HashSet<Integer>
ConjuntoT) {
System.out.println("S="+ConjuntoS); //Imprimir S
System.out.println("T="+ConjuntoT); //Imprimir T
if (ConjuntoS.isEmpty()) { //Si S está vacio retornamos false, porque S=Vacío
//esta contenido //solo sobre si mismo.
return false;
}else {
return ConjuntoT.containsAll(ConjuntoS); //Comparamos si los elementos de S estan
//en T, 1 a 1, los elementos de S se buscan en T en tiempo O(1) por
//medio de Hashset, para este caso se buscaran Sm-1 en T, es decir, el tiempo que tarde el
//algoritmo en buscar
//será la cantidad de elementos de S, O(m+n), asumiendo factor de carga de la clase HashSet
0.75 el tiempo esperado de las operaciones O(1).
}
}
public static Integer NumerosAleatorios(){//Buscar Numeros Aleatorios
double num= (Math.random()*100)/2;
return (int) num;
}
}
Referencias:

Direccionamiento abierto. (s. f.). Hmn.Wiki. Recuperado 30 de abril de 2022, de

https://hmn.wiki/es/Open_addressing

Sondeo lineal. (s. f.). Hmn.Wiki. Recuperado 30 de abril de 2022, de

https://hmn.wiki/es/Linear_probing

TABLA DE HASH: QUÉ ES Y CÓMO FUNCIONAN. (2020, 5 marzo). [Vídeo]. YouTube.

https://www.youtube.com/watch?v=9tZsDJ3JBUA

Sondeo lineal y cuadrático nicosiored (2018). Recuperado de (136) Sondeo lineal y

cuadrático - 36 - Estructuras de Datos en C# - YouTube

Wikipedia (2022) wikituscany Hash doble - es.wikituscany.com

Sondeo cuadrático en hash – Acervo Lima. (s. f.). acervolima.com. Recuperado 27 de julio de

2022, de https://es.acervolima.com/sondeo-cuadratico-en-hash/

También podría gustarte