O Push_swap é um projeto de algoritmos de alta eficiência desenvolvido como parte do currículo da 42. O objetivo principal é ordenar uma pilha de inteiros (Pilha A) utilizando um conjunto restrito de instruções e uma pilha auxiliar (Pilha B), minimizando o custo computacional (número de operações).
Este projeto implementa uma versão otimizada do Radix Sort (ordenação por base) utilizando operações bit a bit, precedido por uma etapa de Indexação (Coordinate Compression).
O projeto utiliza uma Lista Duplamente Encadeada para representar as pilhas. Esta escolha permite acesso eficiente (O(1)) tanto ao topo quanto à base da pilha, facilitando as operações de rotação (rotate e reverse rotate).
Definição da estrutura em includes/push_swap.h:
typedef struct s_stack
{
int num; // O valor inteiro original
int pos; // Índice simplificado (rank) após indexação
struct s_stack *next; // Ponteiro para o próximo elemento (abaixo)
struct s_stack *prev; // Ponteiro para o elemento anterior (acima)
} t_stack;Para otimizar a ordenação e permitir o uso eficiente do Radix Sort independentemente da magnitude dos números de entrada (incluindo números negativos), é realizada uma etapa de pré-processamento chamada Indexação ou Coordinate Compression.
- A lista de entrada é percorrida.
- Para cada número, conta-se quantos elementos na lista são menores que ele.
- Este contador define o campo
pos(rank). - O resultado é uma lista normalizada de
0aN-1.
Isso garante que o Radix Sort trabalhe sempre com inteiros positivos e contíguos, eliminando a necessidade de tratar números negativos ou grandes lacunas entre valores.
O programa seleciona dinamicamente a estratégia de ordenação baseada no tamanho da entrada (N).
Para entradas pequenas, o overhead do Radix Sort não justifica seu uso. São aplicados algoritmos ad-hoc:
- N = 2: Swap simples se necessário.
- N = 3: Lógica de permutação otimizada (máximo 2 operações).
- N = 4 ou 5:
- Identifica o(s) menor(es) elemento(s) baseado no índice (
pos). - Move o(s) menor(es) para o topo da Pilha A (usando
raourrapara otimizar a distância). - Empurra para a Pilha B (
pb). - Ordena os 3 restantes.
- Retorna elementos da Pilha B para A (
pa).
- Identifica o(s) menor(es) elemento(s) baseado no índice (
Para grandes conjuntos, implementa-se o LSD (Least Significant Digit) Radix Sort em base binária.
- Complexidade de Tempo:
O(N * k), ondeké o número de bits do maior índice (log₂N). - Complexidade de Espaço:
O(N).
Funcionamento:
O algoritmo itera bit a bit, do menos significativo (LSB) ao mais significativo (MSB), sobre o campo pos:
- Para cada bit
j(de 0 atémax_bits):- Percorre todos os elementos da Pilha A.
- Se o bit
jdo índice (pos) for0: empurra para a Pilha B (pb). - Se o bit
jdo índice (pos) for1: rotaciona a Pilha A (ra), mantendo-o na pilha.
- Após percorrer a Pilha A, todos os elementos da Pilha B são retornados para A (
pa). - O processo se repete para o próximo bit.
- Ao final, a pilha está ordenada.
- Compilador C (GCC ou Clang)
- Make
O projeto utiliza um Makefile para gerenciamento.
# Compilar o executável
make
# Recompilar do zero
make re
# Limpar objetos
make clean
# Limpar objetos e executável
make fcleanO executável push_swap recebe uma lista de inteiros como argumentos.
./push_swap <lista_de_numeros>Exemplos:
./push_swap 4 67 3 87 23
./push_swap "4 67 3 87 23"A saída é a sequência de instruções necessárias para ordenar a pilha.
As operações permitidas para manipular as pilhas são:
| Código | Operação | Descrição |
|---|---|---|
sa |
Swap A | Troca os dois primeiros elementos do topo da pilha A. |
sb |
Swap B | Troca os dois primeiros elementos do topo da pilha B. |
ss |
Swap Both | sa e sb simultaneamente. |
pa |
Push A | Pega o primeiro elemento de B e coloca no topo de A. |
pb |
Push B | Pega o primeiro elemento de A e coloca no topo de B. |
ra |
Rotate A | Desloca todos os elementos de A uma posição acima (o primeiro vira o último). |
rb |
Rotate B | Desloca todos os elementos de B uma posição acima. |
rr |
Rotate Both | ra e rb simultaneamente. |
rra |
Rev. Rotate A | Desloca todos os elementos de A uma posição abaixo (o último vira o primeiro). |
rrb |
Rev. Rotate B | Desloca todos os elementos de B uma posição abaixo. |
rrr |
Rev. Rotate Both | rra e rrb simultaneamente. |
O programa realiza verificações robustas na entrada:
- Argumentos não numéricos.
- Inteiros maiores que
MAX_INTou menores queMIN_INT. - Números duplicados.
Em caso de qualquer erro, o programa exibe Error na saída de erro padrão (stderr) e encerra a execução.
Documentação gerada para o projeto Push_swap da 42.