Introdução
Continuando essa série de publicações sobre estrutura de dados. Na publicação anterior falei que essa série de publicações faz parte das minhas anotações e estudos sobre o assunto dentro da disciplina do tecnólogo que faço. A disciplina é de Estrutura de Dados e vamos continuar aprofundando.
Neste próximo passo, vamos explorar sobre os algoritmos de ordenação. Vamos começar!
A importância da Ordenação
Antes de aprofundar especificamente em ordenação, gostaria de falar sobre o que é esse grupo de algoritmos. Na publicação anterior, comentei que:
Um conjunto de dados é um tipo abstrato de dados, estabelecendo uma relação, as funções e as operações que podem ser aplicados a estes dados.
Desta maneira, os algoritmos de ordenação são ferramentas onde os métodos de ordenação são funções e/ou operações a esse conjunto de dados que possuem técnicas diversas de ordenação para resolver uma mesma tarefa.
Podemos assumir então que ordenar os dados é uma operação essencial, pois se refere a organização de um conjunto de dados que pode facilitar a busca, a recuperação e a análise desses mesmos dados.
Explorando diferentes tipos de ordenação
Existem vários tipos de algoritmos de ordenação, cada um com suas próprias características e eficiência.
Não falarei de todos, falarei dos dois que seguem nessa tabela a seguir:
Algoritmo | Descrição | Complexidade Big O |
---|---|---|
Bubble Sort | Comparação e troca de elementos adjacentes. | O(n^2) |
Quick Sort | Algoritmo de divisão e conquista com escolha de pivô | O(n log n) |
e particionamento recursivo da lista. |
O motivo de não falar de outros como o Merge Sort, por exemplo, é devido ao texto ficar muito longo e quero dar mais o tom do texto que existe tanto quanto a técnica iterativa quanto recursiva.
Estas anotações não isentam o estudo de outros métodos de ordenação.
Bubble Sort
Os elementos vão se deslocando a cada iteração até a posição correta para ordenação da lista. É importante lembrar que como os elementos neste tipo de ordenação são constantemente trocados, há um alto custo com essa troca de elementos.
Um aspecto interessante do Bubble Sort é que sempre é necessário apenas uma iteração em toda a lista para que o maior item de uma lista seja deslocado para o final dela.
Pseudocódigo
Procedimento BubbleSort(lista) n <- tamanho da lista i, j, aux inteiro Para i de 0 até n-1 trocou <- Falso Para j de 0 até n-i-1 Se lista[j] > lista[j+1] Então // Troca os elementos de posição aux <- lista[j] lista[j] <- lista[j+1] lista[j+1] <- aux trocou <- Verdadeiro Fim Se Fim Para Se trocou = Falso Então // A lista está totalmente ordenada, podemos encerrar o loop Parar Fim Se Fim Para Fim Procedimento
Java
import java.util.Arrays; public class BubbleSort { public static void main(String[] args) { int[] lista = {26, 47, 38, 11, 95}; bubbleSort(lista); System.out.println("Lista ordenada: " + Arrays.toString(lista)); } public static void bubbleSort(int[] arr) { int n = arr.length; for (int i = 0; i < n - 1; i++) { for (int j = 0; j < n - i - 1; j++) { if (arr[j] > arr[j + 1]) { // Troca os elementos de posição int temp = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = temp; } } } } }
Typescript
function bubbleSort(arr: number[]): void { const n = arr.length; for (let i = 0; i < n - 1; i++) { for (let j = 0; j < n - i - 1; j++) { if (arr[j] > arr[j + 1]) { // Troca os elementos de posição const temp = arr[j]; arr[j] = arr[j+1]; arr[j+1] = temp; } } } } const lista = [26, 47, 38, 11, 95]; bubbleSort(lista); console.log("Lista ordenada:", lista);
Quick Sort
Este é um algoritmo de ordenação que utiliza a técnica de recursão para resolver problemas de ordenação. A ideia é baseada na ideia de Dividir e Conquistar:
- Dividir: Pega-se um problema M e divide-se em subproblemas menores de forma recursiva.
- Conquistar: Une as soluções dos subproblemas para obter a solução do problema maior P.
Pseudocódigo
Como visto no pseudocódigo abaixo, para desenvolver este algoritmo vamos precisar de duas funções:
- 1ª Função é a Partição: É quem vai produzir o pivô que vai deslocar os elementos que são menores para um lado, e maiores para o outro.
- 2ª Função é o Quick Sort: É quem vai empregar a técnica recursiva e fazer uso da ideia de Dividir e Conquistar falada acima.
quicksort(p inteiro, q inteiro, vetor[] inteiro) inicio_modulo Declarar x inteiro; se (p < q) então x <- particao(p, q, vetor); quicksort(p, x - 1, vetor); quicksort(x + 1, q, vetor); fimse; fimMódulo;
Java
import java.util.Arrays; public class QuickSort { public static void main(String[] args) { int[] lista = {26, 47, 38, 11, 95}; quickSort(lista, 0, lista.length - 1); System.out.println("Lista ordenada: " + Arrays.toString(lista)); } public static void quickSort(int[] arr, int low, int high) { if (low >= high) { return; } int idxPivo = partition(arr, low, high); quickSort(arr, low, idxPivo - 1); quickSort(arr, idxPivo + 1, high); } public static int partition(int[] arr, int low, int high) { int pivo = arr[high]; int idx = low - 1; for (int i = low; i < high; ++i) { if (arr[i] <= pivo) { idx++; int temp = arr[i]; arr[i] = arr[idx]; arr[idx] = temp; } } idx++; arr[high] = arr[idx]; arr[idx] = pivo; return idx; } }
Typescript
function qs(arr: number[], low: number, high: number): void { if (low >= high) { return; } const idxPivo = partition(arr, low, high); qs(arr, low, idxPivo - 1); qs(arr, idxPivo + 1, high); } function partition(arr: number[], low: number, high: number): number { const pivo = arr[high]; let idx = low -1; for(let i = low; i < high; ++i) { if(arr[i] <= pivo) { idx++; const temp = arr[i]; arr[i] = arr[idx]; arr[idx] = temp; } } idx++; arr[high] = arr[idx]; arr[idx] = pivo; return idx; } function quickSort(arr: number[]): void { qs(arr, 0, arr.length - 1); } const lista = [26, 47, 38, 11, 95]; quickSort(lista); console.log("Lista ordenada:", lista);
Praticando
Sempre após o estudo teórico de um assunto, a melhor maneira de concretizar o entendimento dos fundamentos é praticando com desafios de código. Retornando ao Codewars vamos buscar solucionar alguns desafios que tenham a ordenação como objetivo a ser alcançado.
7 kyu - Sort Numbers
Descrição do problema:
Complete a solução para que ela ordene a matriz de números passada como parâmetro. Se a função receber uma array vazia ou um valor nulo, ela deve retornar uma array vazia.
Por exemplo:
solution([1, 2, 10, 50, 5]); // should return [1, 2, 5, 10, 50] solution([]); // should return []
Solução:
Aqui, optei pelo uso do Bubble Sort, é um algoritmo mais simples de escrever, o custo computacional não é uma questão aqui e serve exatamente para o que eu quero fazer.
export function solution(nums: number[]): number[] { //A condição de contorno caso a função receba um array vazio ou nulo if (nums.length === 0 || nums === null) return []; //Operação exata do algoritmo de Bubble Sort comentado anteriormente for (let i = 0; i < nums.length; i++) { for (let j = 0; j < nums.length - i - 1; j++) { if (nums[j] > nums[j+1]) { //Trocar os elementos de posição const temp = nums[j]; nums[j] = nums[j+1]; nums[j+1] = temp; } } } return nums; }
Conclusão
Chegamos ao final desta segunda publicação desta série sobre Estrutura de Dados e Algoritmos. Lembrando que essa síntese de ideias fazem parte de anotações soltas e pessoais para o estudo da disciplina do tecnólogo, e aqui é uma forma de eu sintetizar essas ideias e poder compartilhar algo que estou aprendendo.
Se puder, vamos nos conectar no LinkedIn!
Até a próxima!
Top comments (0)