Introdução a Algoritmos e Estruturas de Dados em C#
Algoritmos e estruturas de dados são a base sobre a qual qualquer software de qualidade é construído. No ecossistema .NET e na linguagem C#, entender esses conceitos permite não apenas escrever código mais eficiente, mas também escolher com sabedoria as ferramentas da rica biblioteca padrão (BCL — Base Class Library). A escolha da estrutura de dados afeta a velocidade da aplicação, o consumo de memória e, em última análise, a experiência do usuário.
Neste artigo, vamos analisar as principais estruturas de dados e algoritmos que todo desenvolvedor C# deve conhecer. Abordaremos sua implementação, características de desempenho (notação Big O) e exemplos práticos de código. O artigo é adequado tanto para iniciantes quanto para programadores experientes que desejam sistematizar seus conhecimentos.
Principais Estruturas de Dados em C#
Arrays e Listas (Array vs List<T>)
Array é uma estrutura de dados fixa que armazena elementos do mesmo tipo em uma área contígua de memória. O acesso por índice ocorre em O(1), mas a inserção e remoção de elementos (exceto no final) exigem O(n) devido ao deslocamento.
int[] numbers = new int[5] { 10, 20, 30, 40, 50 };Console.WriteLine(numbers[2]); // 30List<T> é um array dinâmico. Ele aumenta automaticamente sua capacidade ao adicionar elementos. Internamente, usa um array, portanto a velocidade de acesso por índice também é O(1). No entanto, a inserção no meio ou no início é O(n).
List<string> names = new List<string>() { "Anna", "Boris" };names.Add("Victor");names.Insert(1, "Gleb"); // O(n)Console.WriteLine(names[0]); // AnnaPilha e Fila (Stack<T> e Queue<T>)
Stack<T> (pilha) funciona com o princípio LIFO (Last In, First Out). É usado para algoritmos de travessia, análise de expressões e gerenciamento de chamadas.
Stack<int> stack = new Stack<int>();stack.Push(1);stack.Push(2);stack.Push(3);int top = stack.Pop(); // 3Queue<T> (fila) funciona com o princípio FIFO (First In, First Out). É aplicado em sistemas de processamento de tarefas e bufferização de dados.
Queue<string> queue = new Queue<string>();queue.Enqueue("Tarefa 1");queue.Enqueue("Tarefa 2");string next = queue.Dequeue(); // "Tarefa 1"Ambas as estruturas são implementadas com base em um array (buffer circular) e fornecem operações de inserção e remoção em O(1) em média.
Dicionário (Dictionary<TKey, TValue>)
Dictionary<TKey, TValue> é uma tabela hash. Ela fornece busca, inserção e remoção de elementos por chave em O(1) em média (com uma boa função hash). Esta é uma das estruturas de dados mais usadas em C#.
Dictionary<string, int> ages = new Dictionary<string, int>();ages["Alice"] = 30;ages["Bob"] = 25;
if (ages.ContainsKey("Alice")){ Console.WriteLine(ages["Alice"]); // 30}Importante: As chaves em um Dictionary devem ser únicas e implementar a interface IEquatable<T> ou ter GetHashCode() e Equals() corretamente sobrescritos.
Lista Ligada (LinkedList<T>)
LinkedList<T> é uma lista duplamente ligada. Ao contrário de List, a inserção e remoção no meio da lista são feitas em O(1) (se você tiver uma referência ao nó). No entanto, o acesso por índice é O(n). É usado com menos frequência, mas é indispensável para filas de acesso bidirecional e caches LRU.
LinkedList<int> list = new LinkedList<int>();list.AddLast(1);list.AddLast(2);list.AddFirst(0);
LinkedListNode<int> node = list.Find(1);list.AddAfter(node, 10); // O(1)Algoritmos de Ordenação e Busca em C#
QuickSort
QuickSort —