BOLETÍN DE PROBLEMAS

Anuncio
EDA – ITIS/ITIG
ETSINF. UPV
Curso 2010/2011.
A. Casanova. Grupo 2D
BOLETÍN DE PROBLEMAS
Tema I.5
1. Demuéstrese por inducción sobre el número n de discos que en el algoritmo de Hanoi nunca
se mueve un disco más grande sobre otro más pequeño, es decir, la secuencia de
movimientos resultante cumple las reglas del juego.
/** Juego de las torres de Hanoi: En origen se encuentran los n menores
* discos del juegos apilados de mayor a menor tamaño, n>=1. Se calcula la
* secuencia de movimientos que tranfiere la torre de n discos desde
* origen a destino.
*/
public static void hanoi(int n, String origen, String auxiliar,
String destino)
{ if (n==1) System.out.println("Mover de "+ origen+ " a "+destino);
else { // n>1
hanoi(n-1, origen, destino, auxiliar); //A
System.out.println("Mover de "+ origen+ " a "+destino); //B
hanoi(n-1, auxiliar, origen, destino); //C
}
}
Caso base: n=1. Con un único movimiento se tranfiere toda la torre al destino, dado que
la torre está formada únicamente por el disco más pequeño. Por lo tanto, sea cual sea el
destino, al mover este disco no se situará sobre un disco menor.
Caso general: n>1. Supóngase, por hipótesis de inducción, que con la llamada A se
transfiere la torre formada por los n-1 discos más pequeños al auxiliar, habiendo sido
todos los movimientos realizados correctos; en el destino no puede quedar ningún disco
menor que el n-ésimo disco, por lo que el movimiento que se describe en B es correcto.
Finalmente la llamada C, también por hipótesis de inducción, deja la subtorre de los n-1
menores discos sobre el disco n-ésimo, sin hacer ningún movimiento incorrecto. Así
pues, la torre queda reconfigurada en destino, y habiendo cumplido las reglas del juego.
1
2. Estúdiese el coste temporal de los siguientes métodos recursivos:
a. /* Cálculo de a^n, a>0, n>=0 */
public static int potencia(int a, int n)
{ if (n==0) return 1;
else return a*potencia(a,n-1);
}
No hay diferentes instancias.
T(n)= T(n-1) + k1
n>1
T(n) = k2
n=1
(n)
b. /* Cálculo de a^n, a>0, n>=0 */
public static int potencia(int a, int n)
{ if (n==0) return 1;
else {
{ int aux=potencia(a,n/2);
if (n%2==0) return aux*aux;
else return aux*aux*a;}
}
No hay diferentes instancias.
T(n)= T(n/2) + k1
n>1
T(n) = k2
n=1
(log2 n)
c. /* 0<=i<a.length */
public static <T extends Comparable<T>> int minimo(T[] a,int i)
{if (i==a.length-1) return i;
else
{ int posMin=minimo(a,i+1);
if (a[i].compareTo(a[posMin])<0) posMin=i;
return posMin;}
}
No hay diferentes instancias. Sea n=a.length-i.
T(n)= T(n-1) + k1
n>1
T(n) = k2
n=1
(n)
d. /* 0<=izq<=der<a.length */
public static <T extends Comparable<T>> int minimo(T[] a,
int izq,int der)
{ if (izq<der){
int medio=(izq+der)/2;
int min1=minimo(a,izq,medio);
EDA, ITIS/ITIG, ETSInf, UPV. A. Casanova. Grupo 2D
2
int min2=minimo(a,medio+1,der);
if (a[min2].compareTo(a[min1])<0) return min2;
else return min1;}
else return izq;
}
No hay diferentes instancias. Sea n=der-izq+1.
T(n)= 2 T(n/2) + k1
n>1
T(n) = k2
n=1
(nlog22)= (n)
3. Se tiene un array a ordenado de enteros diferentes. Se pide un algoritmo recursivo que
encuentre, si existe, un índice i, 0 i<a.lenght, tal que a[i]=i, con un coste O(log n).
/* Busca un índice k en el rango izq..der tal que k==a[k],
* 0<=izq, der<a.length */
public static int indiceValor(double[] a, int izq, int der)
{if (izq<=der){ int medio=(izq+der)/2;
if (a[medio]==medio) return medio;
else if (a[medio]>medio)
return indiceValor(a,izq,medio-1);
else return indiceValor(a,medio+1,der);
}
else return -1;
}
4. Se tiene un array a que contiene n valores reales positivos, y que se ajustan al perfil de una
curva cóncava, es decir, existe un mínimo en una cierta posición k, 0≤k<n, a[0..k-1]
está ordenado descendentemente y a[k+1..n-1] está ordenado ascendemente (figura 1).
Se debe escribir un método recursivo eficiente que encuentre la posición k.
Figura 1
/* Busca el mínimo de a[izq..der], suponiendo que esos valores
* se ajustan a un curva cóncava, 0<=izq<=der<a.length */
public static int concava(double[] a, int izq, int der)
EDA, ITIS/ITIG, ETSInf, UPV. A. Casanova. Grupo 2D
3
{ int n=der-izq+1;
if (n>=3) { int medio=(izq+der)/2;
if (a[medio-1]>a[medio])
if (a[medio+1]>a[medio]) return medio;
else return concava(a,medio+1,der);
else return concava(a,izq,medio-1);
}
else if (n==2) if (a[izq]<a[der]) return izq;
else return der;
else return der;
}
El coste es O(log n) y Ω(1), siendo n=der-izq+1.
5. Se debe escribir un método recursivo con el siguiente perfil
public static <T extends Comparable<T>> void selDir(T[] a,int i)
que ordene a[i..a.length-1] con la estrategia de selección directa.
/* Ordenación por selección directa de a[i..a.length], 0<=i */
public static
{
<T extends Comparable<T>> void selDir(T[] a, int i)
if (i<a.length-1)
{ int pos=minimo(a,i);// calcula la posición del mínimo en
// a[i..a.length-1]
T aux=a[pos];
a[pos]=a[i];
a[i]=aux;
selDir(a,i+1);
}
}
6. La figura 2 muestra una traza completa en árbol de los argumentos de las llamadas
recursivas que genera mergesort para ordenar el array {10,3,50,11,3,1,3,45,1}. Para cada
llamada se ha representado el array de entrada y unas casillas en blanco que se deben
completar con el estado del array a la salida de la llamada. Además, se deben numerar las
llamadas por el orden en que se van generando y por el orden en que se van completando.
EDA, ITIS/ITIG, ETSInf, UPV. A. Casanova. Grupo 2D
4
Orden en que se generan las llamadas:
1
1
1
3
3
2
3
10
11 45
50
9
1
3
10
3
11
50
1
6
3
10
1
3
10
11
50
3
45
1
3
13
1
3
45
15
4
5
7
8
11
12
1
14
45
16
17
Orden en que se completan las llamadas:
17
1
1
3
3
7
3
10
11 45
50
16
1
3
10
3
11
50
1
6
3
10
1
3
10
11
50
3
45
1
3
15
1
3
45
14
1
2
4
5
8
9
11
1
12
45
13
Figura 2
7. Dados los siguientes algoritmos de ordenación de un array a[izq..der], indíquese qué
relación de recurrencia para el coste describe el comportamiento temporal de cada uno de
ellos cuando se aplican sobre un array que está ordenado ascendentemente y no tiene
elementos repetidos. En adelante, n denota der-izq+1.
a. public static <T extends Comparable<T>> void quickSort(T[] a,
int izq, int der )
{ if( izq<der )
{ int pos = (izq+der)/2;
int i= particion(a,izq,der,pos);
EDA, ITIS/ITIG, ETSInf, UPV. A. Casanova. Grupo 2D
5
quickSort(a,izq,i-1);
quickSort(a,i+1,der);
}
}
en donde particion es el método (visto en clase) que toma a[pos] como
pivote, lo deja en su posición, reubica a su izquierda los elementos ≤ que el pivote,
y a su derecha los ≥ que el pivote. Devuelve la posición del pivote. Su coste es
proporcional a n.
T(n)= 2 T(n/2) + k1n
n>1
T(n) = k2
n 1
(n log2 n)
b. private static <T extends Comparable<T>> void mergeSort(T[]
a, int izq, int der)
{ if ( izq < der )
{ int mitad = (izq+der)/2;
mergeSort(a, izq, mitad);
mergeSort(a, mitad+1, der);
fusion (a,izq, mitad+1, der);
}
}
en donde fusion obtiene en a[izq..der] la fusión ordenada de
a[izq..mitad] y a[mitad+1..der]. Su coste es proporcional a n.
T(n)= 2 T(n/2) + k1n
n>1
T(n) = k2
n 1
(n log2 n)
c. public static void <T extends Comparable<T>> insDir(T[] a,
int izq,int der)
{ if (izq<der)
{ insDir(a,izq,der-1);
insertar(a[der],a,izq,der-1);
}
}
T(n)= T(n-1) + k1
n>1
T(n) = k2
n 1
(n)
en donde insertar inserta ordenadamente a[der] entre a[izq..der-1]
dejando a[izq..der] ordenado. Su coste es proporcional a n si a[der] es
menor que todos los elementos que le proceden, y de un paso de programa si es
mayor o igual.
8. Se debe escribir una nueva versión del algoritmo de ordenación por quicksort de un array
a[izq..der], izq≤0, der<a.length, cuyos elementos sean de algún tipo E
EDA, ITIS/ITIG, ETSInf, UPV. A. Casanova. Grupo 2D
6
Comparable, de modo que la partición actúe con “pivote ancho”, es decir, que disponga
consecutivos todos los elementos iguales al pivote x:
<x
=x
>x
Para ello se sugiere tomar como pivote x, por ejemplo, el elemento a[izq], e ir
avanzando la partición con el siguiente esquema
izq
i
<x
j
=x
k
?
der
>x
y partiendo del estado inicial
i izq
x
der
k
j
?
k
/** Intercambio de a[i1] y a[i2], i1, i2 en el rango de a*/
private static <E>void intercambia(E[] a,int i1,int i2)
{ E aux= a[i1];
a[i1]=a[i2];
a[i2]=aux;
}
/** Ordenación por quicksort (con pivote ancho) de a[ini..fin],
* 0<=ini, fin<a.length
*/
public static <E extends Comparable<E>>void quicksort(E[] a,
int izq,int der)
{ if (izq<der)
{ E x=a[izq];
int i=izq-1, j=izq+1, k=der;
while(j<=k)
{ if (a[j].compareTo(x)>0)
{ intercambia(a,j,k); k--;}
else if (a[j].compareTo(x)==0)j++;
else {intercambia(a,j,i+1); i++; j++;}
}
// 0<=izq, i<der<a.length,
// talla de a[izq..i] menor que talla de a[izq..der]
quicksort(a,izq,i);
// 0<=izq<j, der<a.length
EDA, ITIS/ITIG, ETSInf, UPV. A. Casanova. Grupo 2D
7
// talla de a[j..der] menor que talla de a[izq..der]
quicksort(a,j,der);
}
}
Cabe notar que si todos los elementos de a[izq..der] son iguales, entonces el coste de
su ordenación resulta
(n), siendo n=der-izq+1, dado que se realiza una sola partición, y
dos subllamadas recursivas de talla 0.
9. Escríbase una versión del método recursivo de selección del k-ésimo elemento de un array
visto en clase, que siga la misma estrategia eficiente, pero que evite el consumo de pila
asociado a la recursión.
/** Retorna el k-ésimo elemento de a, 0<=k<a.length */
public static <E extends Comparable<E>> E seleccionIter(E[] a,
int k)
{int posPivote=0; boolean encontrado=false;
int izq=0, der=a.length-1;
while( izq<der && !encontrado)
{
posPivote=particion(a,izq,der,izq);
if (posPivote==k) encontrado=true;
else if (posPivote>k) der=posPivote-1;
else izq=posPivote+1;
}
return a[posPivote];
}
EDA, ITIS/ITIG, ETSInf, UPV. A. Casanova. Grupo 2D
8
Descargar