28 de dezembro de 2023
Algoritmo: Bubblesort
Algoritmos
Lógica
Bubble sort é um algoritmo muito simples para ordenação. Ele itera sobre uma lista comparando dois itens de cada vez. No caso de ordenação crescente, se o item da esquerda for maior que o da direita, eles trocam de lugar. A cada iteração completa pela lista, o maior número estará no final, e, portanto, não precisamos mais compará-lo. Então reiteremos sobre a mesma lista menos o último, e depois menos os dois últimos e depois menos os três, e… você entendeu. Em algum momento não vão sobrar itens para comparar e a lista estará ordenada.
Implementação
Uma maneira de implementar esse algoritmo na linguagem C pode ser assim:
1void bubble_sort(int numbers[], int length)
2{
3 for (int i = 0; i < length - 1; i++) // {1}
4 {
5 for (int j = 0; j < length - i - 1; j++) // {2}
6 {
7 if (numbers[j] > numbers[j + 1]) // {3}
8 {
9 swap(&numbers[j], &numbers[j + 1]); // {4}
10 }
11 }
12 }
13};
{1} Usaremos esse loop para ir “limitando” a execução das comparações. Cada vez que percorremos toda a lista, i é somado 1 e podemos usar i para limitar o tamanho percorrido no segundo loop {2}. Como demonstrado mais abaixo em “bubble_sort_experimental”, o maior elemento não ordenado da lista é colocado no final a cada iteração.
{3} Se o item que estamos comparando for maior que o seu próximo, ele está na posição errada. Então permutaremos suas posições {4}.
Executando
1#include <stdio.h>
2#include "src/bubble_sort.h"
3#include "utils/print_array.h"
4
5int main()
6{
7 int unsorted[] = {666, 1, 2, 3, 4, 5, 6};
8 int length = sizeof(unsorted) / sizeof(unsorted[0]);
9
10 bubble_sort(unsorted, length);
11 print_array(unsorted, length);
12}
Vamos visualizar o que acontece com o maior elemento quando ele está no começo da lista:
1void bubble_sort_experimental(int numbers[], int length)
2{
3 int first_item = numbers[0];
4 for (int i = 0; i < length - 1; i++)
5 {
6 printf("%d° iteration \\n", i + 1);
7 for (int j = 0; j < length - i - 1; j++)
8 {
9 if (numbers[j] > numbers[j + 1])
10 {
11 if (first_item == numbers[j])
12 {
13 printf("the first item %d swap position with %d \\n", first_item, numbers[j + 1]);
14 }
15 swap(&numbers[j], &numbers[j + 1]);
16 }
17 }
18 }
19};
Executando:
11° iteration
2the first item 666 swap position with 1
3the first item 666 swap position with 2
4the first item 666 swap position with 3
5the first item 666 swap position with 4
6the first item 666 swap position with 5
7the first item 666 swap position with 6
82° iteration
93° iteration
104° iteration
115° iteration
126° iteration
131 2 3 4 5 6 666
Ainda na primeira iteração, 666 foi para o final e podemos desconsiderá-lo.
Implementação recursiva
Podemos também fazer algo recursivo:
1void bubble_sort_recursive(int numbers[], int length)
2{
3 if (length < 1) // {1}
4 return;
5
6 for (int i = 0; i < length - 1; i++) // {2}
7 {
8 if (numbers[i] > numbers[i + 1])
9 {
10 swap(&numbers[i], &numbers[i + 1]);
11 }
12 }
13 bubble_sort_recursive(numbers, length - 1); // {3}
14};
{1} Se a lista está vazia não tem o que comparar.
{2} Nesse caso, é igual à primeira implementação: iterar, comparar e, se necessário, trocar de lugar.
{3} Por fim, passamos a mesma função para a lista menos o último elemento.
Tempo de execução
O seu tempo de execução para o pior caso é O(n²), porém funciona bem com listas parcialmente ordenadas.
Referência
T.H. Cormen, C.E. Leiserson, R.L. Rivest, C. Stein, Introduction to Algorithms, 3rd edition, MIT Press, 2009.