Algorithms Magazine Programaci贸n e Innovaci贸n
EDITORIAL El análisis de algoritmos es una parte importante de la Teoría de complejidad computacional más amplia, que provee estimaciones teóricas para los recursos que necesita cualquier algoritmo que resuelva un problema computacional dado. Estas estimaciones resultan ser bastante útiles en la búsqueda de algoritmos eficientes. A la hora de realizar un análisis teórico de algoritmos es común calcular su complejidad en un sentido asintótico, es decir, para un tamaño de entrada suficientemente grande. La cota superior asintótica, y las notaciones omega (cota inferior) y theta (caso promedio) se usan con esa finalidad. Por ejemplo, la búsqueda binaria decimos que se ejecuta en una cantidad de pasos proporcional a un logaritmo, en O(log(n)), coloquialmente "en tiempo logarítmico". Normalmente las estimaciones asintóticas se utilizan porque diferentes implementaciones del mismo algoritmo no tienen por qué tener la misma eficiencia. No obstante la eficiencia de dos implementaciones "razonables" cualesquiera de un algoritmo dado están relacionadas por una constante multiplicativa llamada constante oculta. La medida exacta (no asintótica) de la eficiencia a veces puede ser computada pero para ello suele hacer falta aceptar supuestos acerca de la implementación concreta del algoritmo, llamada modelo de computación. Un modelo de computación puede definirse en términos de un ordenador abstracto, como la Máquina de Turing, y/o postulando que ciertas operaciones se ejecutan en una unidad de tiempo. Por ejemplo, si al conjunto ordenado al que aplicamos una búsqueda binaria tiene 'n' elementos, y podemos garantizar que una única búsqueda binaria puede realizarse en un tiempo unitario, entonces se requieren como mucho log2 N + 1 unidades de tiempo para devolver una respuesta.
CONTENIDO • Haga clic para modificar el estilo de texto del patrón – Segundo nivel – Tercer nivel • Cuarto nivel – Quinto nivel
PUBLICIDAD
PILAS • ¿Qué es una pila? Una pila es una estructura de datos de acceso restrictivo a sus elementos. Se puede entender como una pila de libros que se amontonan de abajo hacia arriba. En principio no hay libros; después ponemos uno, y otro encima de éste, y así sucesivamente. Posteriormente los solemos retirar empezando desde la cima de la pila de libros, es decir, desde el último que pusimos, y terminaríamos por retirar el primero que pusimos, posiblemente ya cubierto de polvo. En los programas estas estructuras suelen ser fundamentales. La recursividad se simula en un computador con la ayuda de una pila. Asimismo muchos algoritmos emplean las pilas como estructura de datos fundamental, por ejemplo para mantener una lista de tareas pendientes que se van acumulando. Las pilas ofrecen dos operaciones fundamentales, que son apilar y desapilar sobre la cima. El uso que se les de a las pilas es independiente de su implementación interna. Es decir, se hace un encapsulamiento. Por eso se considera a la pila como un tipo abstracto de datos. Es una estructra de tipo LIFO (Last In First Out), es decir, último en entrar, primero en salir. A continuación se expone la implementación de pilas mediante arrays y mediante listas enlazadas. En ambos casos se cubren cuatro operaciones básicas: Inicializar, Apilar, Desapilar, y Vacía (nos indica si la pila está vacía). Las claves que contendrán serán simplemente números enteros, aunque esto puede cambiarse a voluntad y no supone ningún inconveniente.
PILAS Implementación mediante array Esta implementación es estática, es decir, da un tamaño máximo fijo a la pila, y si se sobrepasa dicho límite se produce un error. La comprobación de apilado en una pila llena o desapilado en una pila vacía no se han hecho, pero sí las funciones de comprobación, que el lector puede modificar según las necesidades de su programa.
- Declaración:
struct tpila { int cima; int elementos[MAX_PILA]; }; Nota: MAX_PILA debe ser mayor o igual que 1.
- Procedimiento de Creación:
void crear(struct tpila *pila) { pila->cima = -1; }
PILAS - Función que devuelve verdadero si la pila está vacía:
int vacia(struct tpila *pila) { return (pila->cima == -1); }
- Función que devuelve verdadero si la pila está llena:
int llena(struct tpila *pila) { return (pila->cima == MAX_PILA); }
- Procedimiento de apilado:
void apilar(struct tpila *pila, int elem) { pila->elementos[++pila->cima] = elem; }
PILAS - Procedimiento de desapilado:
void desapilar(struct tpila *pila, int *elem) { *elem = pila->elementos[pila->cima--]; }
Programa de prueba:
#include <stdio.h>
int main(void) { struct tpila pila; int elem;
crear(&pila); if (vacia(&pila)) printf("\nPila vacia."); if (llena(&pila)) printf("\nPila llena."); apilar(&pila, 1); desapilar(&pila, &elem); return 0; }
PILAS Importancia de Las Pilas Las pilas se utilizan en muchas aplicaciones que utilizamos con frecuencia. Por ejemplo, la gestión de ventanas en Windows (cuando cerramos una ventana siempre recuperamos la que teníamos detrás). Otro ejemplo es la evaluación general de cualquier expresión matemática para evitar tener que calcular el número de variables temporales que hacen falta.
Y en la pr贸xima edici贸n de Algorithms Magazine te traemos: