Python ofrece herramientas poderosas como generadores y capacidades recursivas que permiten resolver problemas algorítmicos de manera elegante. A continuación, se presentan diversas implementaciones prácticas de conceptos fundamentales de la ciencia de la computación utilizando este lenguaje.
Recreando la función range con Generadores
El uso de generadores permite optimizar el consumo de memoria al no cargar secuencias completas. Podemos replicar el comportamiento de range() utilizando la palabra clave yield.
def generador_rango(inicio, fin=None, salto=1):
# Ajuste de parámetros si solo se recibe un argumento
if fin is None:
fin = inicio
inicio = 0
actual = inicio
while actual < fin:
yield actual
actual += salto
# Ejemplo de uso
for valor in generador_rango(2, 12, 2):
print(valor)
Algoritmo de Búsqueda Binaria
La búsqueda binaria es eficiente para localizar elementos en colecciones previamente ordenadas, dividiando el espacio de búsqueda a la mitad en cada iteración.
def localizar_valor(coleccion, objetivo):
coleccion.sort()
def buscar(sub_lista, valor):
if not sub_lista:
return "Elemento no encontrado"
punto_medio = len(sub_lista) // 2
if valor == sub_lista[punto_medio]:
return "¡Elemento localizado!"
elif valor > sub_lista[punto_medio]:
return buscar(sub_lista[punto_medio + 1:], valor)
else:
return buscar(sub_lista[:punto_medio], valor)
return buscar(coleccion, objetivo)
numeros = [10, 45, 2, 8, 100, 34, 56]
print(localizar_valor(numeros, 34))
Análisis de Evaluación Perezosa en Ganeradores
Un reto común en entrevistas técnicas es entender cuándo se evalúa las variables dentro de una expresión generadora.
def sumar(a, b):
return a + b
def producir_base():
for x in range(4):
yield x
it = producir_base()
for factor in [1, 10]:
it = (sumar(factor, item) for item in it)
# ¿Cuál es el resultado final?
# Debido a la evaluación perezosa, 'factor' se toma en su último estado (10)
resultado = list(it)
print(resultado) # Salida: [20, 21, 22, 23]
Monitoreo de Archivos en Tiempo Real
Similar al comando tail -f en sistemas Unix, podemos leer continuamente el final de un archivo de registro (log).
import time
def seguir_log(ruta):
with open(ruta, 'rb') as archivo:
# Desplazarse al final del archivo
archivo.seek(0, 2)
while True:
linea = archivo.readline()
if not linea:
time.sleep(0.1)
continue
print(linea.decode('utf-8').strip())
# seguir_log('servidor.log')
Contador de Frecuencia de Palabras
Utilizando diccionarios, podemos mapear la ocurrencia de términos en una cadena de texto de forma sencilla.
texto = "python es potente python es versatil"
palabras = texto.split()
frecuencias = {}
for p in palabras:
frecuencias[p] = frecuencias.get(p, 0) + 1
print(frecuencias)
Simulación de Pilas (Stack) y Colas (Queue)
Aunque Python tiene módulos específicos, las listas permiten entender la lógica LIFO (Last-In, First-Out) y FIFO (First-In, First-Out).
# Lógica de Cola (FIFO)
cola = []
cola.append("A")
cola.append("B")
print(cola.pop(0)) # Salida: A
# Lógica de Pila (LIFO)
pila = []
pila.append("X")
pila.append("Y")
print(pila.pop()) # Salida: Y
Ejercicios de Recursividad
La recursividad es fundamental para resolver problemas que pueden desglosarse en subproblemas idénticos.
1. Factorial
def calcular_factorial(n):
if n <= 1:
return 1
return n * calcular_factorial(n - 1)
2. Sucesión de Fibonacci
def obtener_fibonacci(n):
if n == 0: return 0
if n == 1: return 1
return obtener_fibonacci(n - 1) + obtener_fibonacci(n - 2)
3. Inversión de Cadenas
def invertir_texto(cadena):
if len(cadena) <= 1:
return cadena
return cadena[-1] + invertir_texto(cadena[1:-1]) + cadena[0]