Recursão e Quick Sort

Sumário

Neste post, vou explicar dois conceitos importantes da ciência da computação: recursão e quick sort. Preciso explicar recursão antes de explicar o quick sort, porque o quick sort usa recursão para ordenar o array.

Recursão

Recursão é uma técnica da ciência da computação em que uma função chama a si mesma. Essa técnica é usada para resolver problemas que podem ser divididos em problemas menores do mesmo tipo.

Este é um exemplo de função recursiva que calcula o fatorial de um número:


func factorial(n int) int {
	if n == 0 {
		return 1
	}
	return n * factorial(n-1)
}

Neste exemplo, a função factorial chama a si mesma com um número menor até chegar ao caso base. O caso base é quando n é igual a 0, situação em que a função retorna 1.

É importante reforçar o caso base: sem ele, teríamos um loop infinito, e você pode testar isso com o código abaixo


func factorial(n int) int {
	return n * factorial(n-1)
}

Você pode usar ctrl+c para cancelar.

Quick Sort

Enfim, agora vamos falar do quick sort.

O quick sort é um algoritmo de ordenação que usa recursão para ordenar um array. Ele usa a estratégia de Dividir para Conquistar para ordenar o array. Mas o que seria essa estratégia?

Dividir para Conquistar é uma técnica da ciência da computação em que um problema é dividido em problemas menores do mesmo tipo.

Por exemplo, digamos que temos um array:

arr := []int{100, 5, 3, 6, 2, 10}

Primeiro, pegamos o elemento pivô, que é o primeiro elemento do array:


pivot := arr[0]

Com o pivô, dividimos o array em dois: um com os elementos menores que o pivô e outro com os elementos maiores que ele:


var left []int
var right []int

for i := 1; i < len(arr); i++ {
	if arr[i] < pivot {
		left = append(left, arr[i])
	} else {
		right = append(right, arr[i])
	}
}

E aqui usamos recursão para ordenar os arrays da esquerda e da direita:


left = quickSort(left)
right = quickSort(right)

Por fim, concatenamos o array da esquerda, o pivô e o array da direita:


return append(append(left, pivot), right...)

Deixei de propósito para o final para dizer que não podemos esquecer o caso base.

O caso base é quando o array tem só um elemento, situação em que retornamos o próprio array:


if len(arr) < 2 {
	return arr
}

Quando o array tem só um elemento, retornamos o array porque ele já está ordenado.

Agora podemos criar a função quickSort:


func quickSort(arr []int) []int {
	if len(arr) < 2 {
		return arr
	}

	pivot := arr[0]

	var left []int
	var right []int

	for i := 1; i < len(arr); i++ {
		if arr[i] < pivot {
			left = append(left, arr[i])
		} else {
			right = append(right, arr[i])
		}
	}

	left = quickSort(left)
	right = quickSort(right)

	return append(append(left, pivot), right...)
}

Agora podemos testar a função:


func main() {
	arr := []int{100, 5, 3, 6, 2, 10}
	fmt.Println(quickSort(arr))
}

Ao rodar o código acima, você vai ver o array ordenado:


[2 3 5 6 10 100]

É isso! Espero que você tenha gostado deste post. Se tiver alguma dúvida, me conte nos comentários abaixo.

Conclusão

Neste post, expliquei dois conceitos importantes da ciência da computação: recursão e quick sort. Espero ter conseguido explicar de forma simples, para que a maioria das pessoas entenda, principalmente quem tem dificuldade ou até medo de algoritmos!

Abraços.