Algoritmos e Estruturas de Dados em Swift: do Iniciante ao Profissional
Swift é uma linguagem de programação poderosa e intuitiva da Apple, usada para desenvolver aplicativos para iOS, macOS, watchOS e tvOS. Compreender algoritmos e estruturas de dados é a base que diferencia um desenvolvedor experiente de um iniciante. Neste artigo, vamos explorar os conceitos principais com exemplos práticos em Swift.
1. Estruturas de Dados Básicas em Swift
A biblioteca padrão do Swift fornece várias estruturas integradas que estão na base de qualquer aplicativo.
Arrays (Array)
Coleção ordenada de elementos do mesmo tipo. Suporta acesso aleatório por índice.
var numbers: [Int] = [10, 20, 30, 40, 50]numbers.append(60)numbers.insert(5, at: 0)print(numbers[2]) // Saída: 30Dicionários (Dictionary)
Coleção de pares "chave-valor" para busca rápida de dados por uma chave única.
var userScores: [String: Int] = ["Alice": 95, "Bob": 87]userScores["Charlie"] = 92if let score = userScores["Alice"] { print("Pontuação da Alice: \\(score)")}Conjuntos (Set)
Coleção não ordenada de elementos únicos. Ideal para verificar existência ou remover duplicatas.
let fruits: Set = ["Maçã", "Banana", "Laranja", "Maçã"]print(fruits.count) // Saída: 3 (duplicata removida)2. Implementação de Pilha e Fila em Swift
Pilha e fila são estruturas de dados clássicas que frequentemente são implementadas sobre arrays.
Pilha (Stack) — LIFO (Last In, First Out)
Os elementos são adicionados e removidos de uma mesma extremidade.
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()!) // Saída: 3Fila (Queue) — FIFO (First In, First Out)
Os elementos são adicionados ao final e removidos do início.
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("Primeiro")queue.enqueue("Segundo")print(queue.dequeue()!) // Saída: Primeiro3. Algoritmos de Ordenação e Busca
Vamos considerar dois algoritmos fundamentais que são úteis em projetos reais.
Quick Sort (Ordenação Rápida)
Algoritmo eficiente de "dividir para conquistar" com complexidade média 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)) // Saída: [1, 1, 2, 3, 6, 8, 10]Binary Search (Busca Binária)
Funciona apenas em arrays ordenados. Complexidade 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