This project has been created as part of the 42 curriculum by ebin-ahm.
This implementation of push_swap uses a hybrid strategy combining:
- Index normalization
- Chunk-based partitioning
- Greedy cost-based reinsertion
This approach efficiently handles large stacks while keeping the number of operations low.
The first step is converting all input values into sorted indices.
Instead of working with raw numbers, each value is assigned a rank based on its position in the sorted order.
Example:
Input numbers:
42 -5 100 7
Sorted values:
-5 7 42 100
Assigned indices:
2 0 3 1Working with indices allows the algorithm to operate on a clean range: 0 → smallest number n-1 → largest number
This simplifies comparisons and improves algorithm efficiency.
For large inputs, elements are pushed from Stack A to Stack B using a chunk strategy.
The chunk size is calculated dynamically:
chunk_size = (n * 91) / 100;For example, with an input size of 100, approximately 91 elements are pushed to Stack B, leaving the remaining elements in Stack A to form the initial sorted base.
Through experimentation with different chunk percentages, it was observed that pushing around 90–91% of the elements generally produces the best results for large inputs. Moving most elements to Stack B reduces the number of rotations required when scanning Stack A, allowing the algorithm to push elements more quickly and letting the greedy reinsertion phase handle the majority of the ordering.
However, when the input size is smaller (e.g., ≤ 100), using a slightly smaller chunk percentage tends to perform better. Keeping more elements in Stack A provides a stronger structural base for reinserting elements from Stack B, which reduces the number of rotations required during the greedy insertion phase.
As a result, the optimal chunk percentage depends on the input size: larger inputs benefit from larger chunk ratios, while smaller inputs perform better with more conservative chunk sizes.
While Stack A contains more than 3 elements:
-
Inspect the top element of Stack A
-
If its index is within the current chunk range → push to B (pb)
-
Otherwise → rotate A (ra)
Additionally, when pushing elements to B, smaller indices may be rotated (rb) to maintain a structure that improves reinsertion efficiency.
This step gradually moves most values into Stack B, leaving only a few elements in Stack A.
Once 3 elements remain in Stack A, they are sorted using a small deterministic routine.
Sorting 3 elements requires only a few operations:
- sa
- ra
- rra
This ensures Stack A is correctly ordered before reinserting elements from Stack B.
Next, elements from Stack B are inserted back into Stack A using a greedy cost model.
For each element in Stack B:
- Determine the target position in Stack A where it should be inserted.
- Compute the cost of moving that element:
- rotations required in Stack A
- rotations required in Stack B
- Choose the element with the lowest total cost.
- Execute the necessary rotations.
- Push the element back into Stack A (pa).
This greedy approach minimizes the number of operations required during reinsertion.
After all elements are moved back to Stack A, the stack may be correctly sorted but rotated.
The algorithm performs a final step:
- Rotate Stack A until the smallest index is at the top.
This guarantees that Stack A is fully sorted.
Expected Results for:
- No parameters = nothing to be displayed and return to prompt
./push_swap- Non integer parameters = display "Error" followed by a '\n'
./push_swap 2 1 N- Duplicate integer parameters = display "Error" followed by a '\n'
./push_swap 6 3 2 2 1max=0
for i in {1..10}; do
ARG=$(shuf -i 1-100 -n 100 | tr '\n' ' ')
moves=$(./push_swap $ARG | tee /tmp/moves | wc -l)
result=$(cat /tmp/moves | ./checker_linux $ARG)
[ "$moves" -gt "$max" ] && max=$moves
echo "Test $i -> $result | $moves moves"
done
echo "Worst: $max moves"max=0
for i in {1..100}; do
ARG=$(shuf -i 1-100 -n 100 | tr '\n' ' ')
m=$(./push_swap $ARG | wc -l | tr -d ' ')
if [ "$m" -gt "$max" ]; then
max=$m
fi
done
echo "worst(100) = $max"max=0
for i in {1..10}; do
ARG=$(shuf -i 1-500 -n 500 | tr '\n' ' ')
moves=$(./push_swap $ARG | tee /tmp/moves | wc -l)
result=$(cat /tmp/moves | ./checker_linux $ARG)
if [ "$moves" -gt "$max" ]; then
max=$moves
fi
echo "Test $i -> $result | $moves moves"
done
echo "Worst: $max moves"max=0
for i in {1..100}; do
ARG=$(shuf -i 1-500 -n 500 | tr '\n' ' ')
m=$(./push_swap $ARG | wc -l | tr -d ' ')
if [ "$m" -gt "$max" ]; then
max=$m
fi
done
echo "worst(500) = $max"