98
TÉCNICAS DE DISEÑO DE ALGORITMOS
Pivote nos puede ayudar: tras su ejecución ha modificado el vector de forma que los elementos anteriores a la posición l que nos devuelve son todos menores o iguales que a[l], y los posteriores a l son mayores que a[l]. La idea es pues invocar repetidamente a la función Pivote hasta que la posición l coincida con la que buscamos (k). Con este procedimiento no es necesario realizar ninguna ordenación explícita: PROCEDURE Kesimo(VAR a:vector;prim,ult,k:CARDINAL):INTEGER; VAR l:CARDINAL; BEGIN IF prim<ult THEN l:=Pivote(a,a[prim],prim,ult); IF l>(prim+k-1) THEN RETURN Kesimo(a,prim,l-1,k) END; IF l<(prim+k-1) THEN RETURN Kesimo(a,l+1,ult,k-l+prim-1) END; RETURN a[l] ELSE RETURN a[ult] END END Kesimo;
Con este método conseguimos resolver el problema, y tiene un orden de complejidad lineal para la mayoría de los casos, lo cual es mejor de lo conseguido hasta ahora. Sin embargo, por estar basado en Quicksort, este método va a heredar sus casos conflictivos: cuando el vector está ya ordenado o cuando todos los elementos del vector son iguales. En ambos casos nuestro procedimiento resulta ineficiente, pues su complejidad es cuadrática. ¿Podemos corregir de alguna forma estos casos extremos? Nuestra siguiente idea es obvia tras haber realizado el problema 2.8. Podríamos usar la función Pivote2 para eliminar el caso en que todos los elementos son iguales, con lo que obtendríamos: PROCEDURE Kesimo2(VAR a:vector;prim,ult,k:CARDINAL):INTEGER; VAR i,d:CARDINAL; BEGIN IF prim<ult THEN Pivote2(a,a[prim],prim,ult,i,d); IF (prim+k-1)<i THEN RETURN Kesimo2(a,prim,i-1,k) END; IF d<=(prim+k-1) THEN RETURN Kesimo2(a,d,ult,k-d+prim) END; RETURN a[i] ELSE RETURN a[ult] END END Kesimo2;
Sin embargo, esta función deja pendiente el caso en que el vector esté ordenado (de forma creciente o decreciente), pues escogemos como pivote el