Algoritmos y estructuras de datos en Swift: de principiante a profesional
Swift es un lenguaje de programación potente e intuitivo de Apple, utilizado para desarrollar aplicaciones para iOS, macOS, watchOS y tvOS. Comprender los algoritmos y las estructuras de datos es la base que distingue a un desarrollador experimentado de un principiante. En este artículo, analizaremos los conceptos clave con ejemplos prácticos en Swift.
1. Estructuras de datos básicas en Swift
La biblioteca estándar de Swift proporciona varias estructuras integradas que forman la base de cualquier aplicación.
Arrays (Array)
Colección ordenada de elementos del mismo tipo. Admite acceso aleatorio por índice.
var numbers: [Int] = [10, 20, 30, 40, 50]numbers.append(60)numbers.insert(5, at: 0)print(numbers[2]) // Salida: 30Diccionarios (Dictionary)
Colección de pares «clave-valor» para la búsqueda rápida de datos mediante una clave única.
var userScores: [String: Int] = ["Alice": 95, "Bob": 87]userScores["Charlie"] = 92if let score = userScores["Alice"] { print("Alice's score: \\(score)")}Conjuntos (Set)
Colección no ordenada de elementos únicos. Ideal para verificar la presencia o eliminar duplicados.
let fruits: Set = ["Apple", "Banana", "Orange", "Apple"]print(fruits.count) // Salida: 3 (duplicado eliminado)2. Implementación de pila y cola en Swift
La pila y la cola son estructuras de datos clásicas que a menudo se implementan sobre arrays.
Pila (Stack) — LIFO (Last In, First Out)
Los elementos se añaden y eliminan desde un mismo extremo.
struct Stack<T> { private var elements: [T] = [] mutating func push(_ value: T) { elements.append(value) } mutating func pop() -> T? { return elements.popLast() } func peek() -> T? { return elements.last }}
var stack = Stack<Int>()stack.push(1)stack.push(2)stack.push(3)print(stack.pop()!) // Salida: 3Cola (Queue) — FIFO (First In, First Out)
Los elementos se añaden al final y se eliminan del principio.
struct Queue<T> { private var elements: [T] = [] mutating func enqueue(_ value: T) { elements.append(value) } mutating func dequeue() -> T? { return elements.isEmpty ? nil : elements.removeFirst() }}
var queue = Queue<String>()queue.enqueue("First")queue.enqueue("Second")print(queue.dequeue()!) // Salida: First3. Algoritmos de ordenamiento y búsqueda
Consideremos dos algoritmos fundamentales que son útiles en proyectos reales.
Ordenamiento rápido (Quick Sort)
Algoritmo eficiente de «divide y vencerás» con complejidad promedio O(n log n).
func quickSort(_ array: [Int]) -> [Int] { guard array.count > 1 else { return array } let pivot = array[array.count / 2] let less = array.filter { $0 < pivot } let equal = array.filter { $0 == pivot } let greater = array.filter { $0 > pivot } return quickSort(less) + equal + quickSort(greater)}
let unsorted = [3, 6, 8, 10, 1, 2, 1]print(quickSort(unsorted)) // Salida: [1, 1, 2, 3, 6, 8, 10]Búsqueda binaria (Binary Search)
Solo funciona en un array ordenado. Complejidad O(log n).
func binarySearch(_ array: [Int], target: Int) -> Int? { var low = 0 var high = array.count - 1 while low <= high { let mid = (low + high) / 2 if array[mid] == target { return mid } else if array[mid] < target { low = mid + 1 } else { high = mid - 1 } } return nil}
let sortedArray = [1, 3, 5, 7, 9, 11]if let index = binarySearch(sortedArray, target: 7) { p