push_swap is a project that challenges you to sort a stack of integers using a limited set of operations, with the goal of minimizing the number of moves. The program takes a list of integers as arguments and outputs a series of instructions to sort them using two stacks (A and B) and a specific set of allowed operations (sa, sb, ss, pa, pb, ra, rb, rr, rra, rrb, rrr).
Through this project, I got some skills of algorithmic thinking, complexity analysis, and some knowledge about optimization techniques.
- Implement an efficient sorting algorithm for stack-based data structures
- Optimize the number of operations to achieve the best possible sorting efficiency
- Understand algorithm complexity and performance analysis
- Work with doubly-linked lists and stack operations
The program can use the following operations:
- sa (swap a) - Swap the first 2 elements at the top of stack A
- sb (swap b) - Swap the first 2 elements at the top of stack B
- ss - Execute
saandsbsimultaneously - pa (push a) - Take the first element at the top of b and put it at the top of a
- pb (push b) - Take the first element at the top of a and put it at the top of b
- ra (rotate a) - Shift up all elements of stack a by 1 (The first element becomes the last one)
- rb (rotate b) - Shift up all elements of stack b by 1 (The first element becomes the last one)
- rr - Execute
raandrbsimultaneously - rra (reverse rotate a) - Shift down all elements of stack a by 1 (The last element becomes the first one)
- rrb (reverse rotate b) - Shift down all elements of stack b by 1 (The last element becomes the first one)
- rrr - Execute
rraandrrbsimultaneously
My implementation uses an optimized sorting strategy:
- 2 elements: Simple swap if needed
- 3 elements: Identifies the highest value and positions it at the bottom, then swaps if needed to sort the remaining two elements
- 4-5 elements: Push smallest elements to stack B, sort remaining in A, then push back
The algorithm uses a cost-based approach with the following steps:
- Push to Stack B: Move elements from A to B (except 3 elements)
- Target Analysis: For each element in A, find its optimal target position in B
- Rotation Cost Calculation: Calculate the cost of moving each element
- Best Move Selection: Choose the element with the lowest total rotation cost
- Optimized Rotations: Use combined rotations (rr/rrr) when both stacks need rotation
- Final Sort: Sort remaining 3 elements in A, then push all back from B to A
- Final Rotation: Rotate stack A to place smallest element on top
- Median-based positioning: Determines whether to rotate up or down
- Combined rotations: Optimizes by rotating both stacks simultaneously when possible
- Target node selection: Intelligently pairs elements between stacks
- Cost analysis: Evaluates all possible moves to find the most efficient path
To compile the program, simply run:
makeThis creates the push_swap executable.
make- Compile the programmake clean- Remove object filesmake fclean- Remove object files and the executablemake re- Recompile everything from scratch
./push_swap [list of integers]# Sort 5 random numbers
./push_swap 3 2 5 1 4
# Sort with negative numbers
./push_swap -1 -5 0 3 2
# Sort with quoted string input
./push_swap "3 2 5 1 4"The program outputs the sequence of operations needed to sort the stack:
./push_swap 3 2 1
sa
rraThe program outputs "Error\n" to standard error for:
- Non-numeric arguments
- Numbers outside the integer range (INT_MIN to INT_MAX)
- Duplicate numbers
- Invalid input format
The project is organized with a modular approach:
- push_swap.c - Main program entry point and stack creation
- push_swap.h - Header file with structure definitions and function prototypes
- sorting.c - Sorting algorithms for small and large stacks
- operations_for_a.c - Operations analysis for stack A
- operations_for_b.c - Operations analysis for stack B
- commands_push.c - Push operations (pa, pb)
- commands_swap.c - Swap operations (sa, sb, ss)
- commands_rotate.c - Rotate operations (ra, rb, rr)
- commands_reverse_rotate.c - Reverse rotate operations (rra, rrb, rrr)
- rotation_operations.c - Rotation cost analysis and optimization
- push_swap_utils.c - Utility functions for stack manipulation
- utils_for_utils.c - Additional helper functions
- funct_continue.c - Continuation helper functions
- Libft/ - Custom C library for string manipulation and utilities
- ft_printf/ - Custom printf implementation for formatted output
typedef struct s_stack
{
int value; // The actual integer value
int index; // Position in the stack
int rotations; // Cost to move this element
int is_below_medium; // Flag for rotation direction
int is_best_move_choice;// Flag for optimal move
struct s_stack *target; // Target node in other stack
struct s_stack *next; // Next node in the stack
struct s_stack *previous; // Previous node in the stack
} t_stack;- Language: C
- Compiler: gcc
- Flags:
-Wall -Wextra -Werror - Norm: 42 Norminette
- Data Structure: Doubly-linked list (circular)
- Dependencies: libft, ft_printf
You can test the program with various inputs:
# Test with 3 random numbers (should be < 3 operations)
ARG="3 2 1"; ./push_swap $ARG
# Test with 5 random numbers (should be < 12 operations)
ARG="5 4 3 2 1"; ./push_swap $ARG | wc -l
# Test with 100 random numbers (should be < 700 operations for max grade)
ARG=$(shuf -i 1-100 -n 100 | tr '\n' ' '); ./push_swap $ARG | wc -l
# Test with 500 random numbers (should be < 5500 operations for max grade)
ARG=$(shuf -i 1-500 -n 500 | tr '\n' ' '); ./push_swap $ARG | wc -l
# Verify the sorting is correct
ARG="3 2 5 1 4"; ./push_swap $ARG | ./checker_linux $ARG- All functions follow the 42 Norminette coding standards
- Memory is properly managed with no leaks
- The algorithm is optimized to minimize the number of operations
- Handles edge cases (negative numbers, INT_MIN, INT_MAX, duplicates)
- The implementation uses a cost-based approach for optimal performance
- Combined rotations (rr/rrr) are used when both stacks need rotation
opopov - 42 School Student