This project has been created as part of the 42 curriculum by eel-kerc, zqian.
- Description
- Team Collaboration
- Operations
- Concepts
- Project Structure
- Algorithm Justification
- Adaptive Strategy
- Instructions
- Resources
Push Swap is a sorting project where the goal is to sort data on a stack using a limited set of instructions and the fewest possible operations. It introduces the concepts of sorting algorithms and their complexity.
This project was developed in partnership, with responsibilities divided as follows:
| Area | Contributor | Responsibilities |
|---|---|---|
| Core & Storage | zqian | Input Parsing, Stack A/B Initialization, Data Structures. |
| Advanced Sorting | zqian | Chunk-Based Sorting ($O(n\sqrt{n})$), Radix Sort (Bitwise). |
| Mechanics & Analytics | eel-kerc | 11 Operations, Disorder Metric, Benchmark logic. |
| Recursive Algorithms | eel-kerc | Min Extraction, Recursive Merge Sort, Adaptive Strategy. |
| Verification | eel-kerc | Bonus Checker development. |
| Build System | Joint | Makefile architecture and project structure. |
| Top ↑ | Next ↓ |
The goal is to sort numbers into stack a in ascending order. Below is a summary of the 11 available operations:
| Type | Command | Description |
|---|---|---|
| Swap | sa / sb |
Swap the first two elements at the top of stack a or b. |
ss |
Execute sa and sb at the same time. |
|
| Push | pa / pb |
Move the top element from one stack to the top of the other. |
| Rotate | ra / rb |
Shift all elements up by one. The first becomes the last. |
rr |
Execute ra and rb at the same time. |
|
| Reverse Rotate | rra / rrb |
Shift all elements down by one. The last becomes the first. |
rrr |
Execute rra and rrb at the same time. |
| Concept | Description |
|---|---|
| Big O Notation | Mathematical notation that describes the limiting behavior of a function when the argument tends towards a particular value or infinity. |
| O(n²) | Quadratic complexity; performance drops significantly as input size increases (e.g., Bubble/Selection Sort). |
| O(n log n) | Log-linear complexity; efficient for sorting large datasets (e.g., Merge Sort). |
| O(n√n) | Complexity often achieved in chunk-based strategies by dividing data into square-root-sized blocks. |
| Bitwise Ops | Directly manipulating bits; crucial for non-comparison algorithms like Radix Sort. |
| Disorder Metric | A normalized value (0 to 1) based on adjacent pair comparisons (0 = sorted, 1 = reversed). |
| Component | Responsibility |
|---|---|
| Technical Implementation | Efficient operations using Doubly Linked Lists. |
| Input Parsing | Argument validation and robust error handling. |
| Initialization | Efficient data loading and index calculation for Stack A. |
| Algorithm Selection | Adaptive strategy choosing from Simple, Chunk, or Merge. |
| Bonus - Checker | Verification system for sorting results via stdin. |
| Benchmarking | Real-time performance analytics and disorder calculation. |
The sorting strategy is adaptively selected based on the number of elements and the complexity requirements.
| Case | Strategy | Code Logic | Why This Choice? |
|---|---|---|---|
| Simple (3-5) | Min Extraction | Scans min, optimal rotation (ra/rra), reduces to 3 for sort_three. |
Reaches theoretical minimum ops under strict 11-step limit. |
| Medium (Mid) | Chunk-Based | Divides into fixed thresholds (e.g., 5 or 11 chunks). Median-distance optimization. | High efficiency for 100-500 elements; easy to tune. |
| Complex (Large) | Recursive Merge | Recursive split/merge mirroring Merge Sort via stack operations. | High educational value in hierarchical data partitioning. |
| Special (Radix) | Bitwise Sort | Bit-by-bit (LSD to MSD) processing via bitwise checks and pushes. | Study of low-level data manipulation and non-comparison sorting. |
Our final implementation features a Custom Adaptive Algorithm that dynamically selects the best sorting method based on the input's Disorder Metric.
- Code Logic: The code calculates a
disorderscore (0 to 1) upon initialization. Anadaptiverouter then evaluates this score against predefined thresholds and calls the most suitable function (min_extraction,chunk_sort, ormerge_sort) to handle the specific stack configuration.
| Disorder Regime | Threshold | Strategy | Complexity Target |
|---|---|---|---|
| Low Disorder | d < 0.2 |
Optimized O(n²) pass / Small Chunking | O(n²) |
| Medium Disorder | 0.2 ≤ d < 0.5 |
Standard Chunk-Based Sorting | O(n√n) |
| High Disorder | d ≥ 0.5 |
Recursive Merge Sort or Large Chunking | O(n log n) |
- Low Disorder (< 0.2): When the stack is nearly sorted, complex partitioning is counterproductive. We use a linear or near-linear approach to minimize operation overhead.
-
Medium Disorder (0.2 - 0.5): Standard data distribution. The chunking method (5 chunks for
$n \le 100$ , 11 for$n \le 500$ ) provides the best performance. -
High Disorder (≥ 0.5): For highly reversed stacks, we pivot to advanced partitioning (Merge Sort or high-density chunking) to respect the
$O(n \log n)$ complexity.
Our checker must be compile with the rule bonus of the makefile to be used. Here is his algorithm :
-
Code Logic: The intialisation of the stacks work as the same of the original push_swap, as well as the error raises. When the stacks is initialized, it read from the stdout
read(0)with get_next_line and check if the operation is valid. -
Check Value: After the press of
Ctrl + D, the code stop doing the operations. It check if the stacks is well sorted and if the stack b is empty (the stack = NULL). -
Return Value: It can return four different value :
- Nothing, if there is no argument is given.
- Error\n, if there is wrong argument, int_max, dupplicate values - wrong operations given.
- KO\n, if there is good parsing and operations but it doesn't sort the stack a or stack b is not empty.
- OK\n, if there is good parsing, good operations and both stack a sorted and stack b empty.
Designed for Linux systems. Ensure you have a C compiler (gcc/clang) and make installed.
git clone GIT push_swap
cd push_swapThe project includes a Makefile with the following standard rules:
| Rule | Purpose |
|---|---|
make / all |
Compiles the mandatory part (push_swap). |
bonus |
Compiles the bonus checker program (checker). |
clean |
Removes all intermediate object files (.o). |
fclean |
Removes object files and generated executables. |
re |
Full re-compilation (fclean + all). |
# To build the mandatory part:
make
# To build the checker (bonus):
make bonusThe push_swap program takes a list of integers as arguments and outputs the shortest sequence of instructions to sort them.
# Using separate arguments
./push_swap 2 1 3 6 5 8
# Using a single quoted string
./push_swap "2 1 3 6 5 8"For small datasets, the algorithm is optimized to reach peak efficiency, consistently staying within the limits for a perfect score.
3 Elements (Total: 6 Permutations)
# Example with 3 numbers:
./push_swap --simple 3 1 2
| Operations | Count | Percentage |
|---|---|---|
| 0 | 1 | 16.7% |
| 1 | 3 | 50.0% |
| 2 | 2 | 33.3% |
| *Average: 1.17 ops | Max: 2 ops* |
5 Elements (Total: 120 Permutations)
# Example with 5 numbers:
./push_swap --simple 5 2 4 1 3| Operations | Count | Percentage |
|---|---|---|
| 0 | 1 | 0.8% |
| 3 | 2 | 1.7% |
| 4 | 1 | 0.8% |
| 5 | 6 | 5.0% |
| 6 | 19 | 15.8% |
| 7 | 30 | 25.0% |
| 8 | 30 | 25.0% |
| 9 | 20 | 16.7% |
| 10 | 9 | 7.5% |
| 11 | 2 | 1.7% |
| *Average: 7.47 ops | Max: 11 ops* |
The checker program verifies if the sequence of operations generated by push_swap correctly sorts the stack. You can pipe the output of push_swap into checker:
ARG="4 67 3 87 23"; ./push_swap $ARG | ./checker $ARGExpected Outputs:
| Output | Meaning |
|---|---|
OK |
The stack is sorted and Stack B is empty. |
KO |
The stack is not sorted correctly. |
Error |
Invalid input: non-integers, out of range, or duplicates. |
You can use the shuf utility (available on most Linux systems) to generate random datasets for testing performance:
# Test with 50 random numbers
shuf -i 0-9999 -n 50 > args.txt ; ./push_swap $(cat args.txt)
# Test with 100 random numbers
shuf -i 0-9999 -n 100 > args.txt ; ./push_swap $(cat args.txt)
# Test with 500 random numbers
shuf -i 0-9999 -n 500 > args.txt ; ./push_swap $(cat args.txt)The program includes a built-in benchmark mode to analyze sorting performance, including disorder metrics and operation breakdowns. Benchmark data is sent to stderr (file descriptor 2).
Run with benchmark enabled:
shuf -i 0-9999 -n 500 > args.txt ; ./push_swap --bench $(cat args.txt) 2> bench.txt | ./checker $(cat args.txt)
cat bench.txtExample Benchmark Output:
[bench] disorder: 49.93%
[bench] strategy: Adaptive / O(n√n)
[bench] total_ops: 7997
[bench] sa: 0 sb: 0 ss: 0 pa: 500 pb: 500
[bench] ra: 4840 rb: 1098 rr: 0 rra: 0 rrb: 1059 rrr: 0
Pipe operations to checker while saving benchmark:
ARG="4 67 3 87 23"; ./push_swap --bench --adaptive $ARG 2> bench.txt | ./checker $ARGThe program handles invalid inputs gracefully, displaying Error to standard error:
./push_swap --adaptive 0 one 2 3
# Output: Error
./push_swap --simple 3 2 3
# Output: Error (duplicate detected)- Push Swap In-Depth Video Guide
- Sorting Visualizer & Algorithm Explanation
- Radix Sort Visualization
- Insertion Sort Explained
- Selection Sort Explained
- Bubble Sort Explained
As part of the project requirements, here is a summary of how AI (ChatGPT) was utilized during development:
- Documentation & Structure: AI was used to organize and structure this
README.mdto ensure clarity and professional presentation. - Performance Testing: AI assisted in designing and executing comprehensive tests for small datasets (3 and 5 elements) to ensure peak efficiency.
- Technical Topics Explored:
- Algorithm Selection & Optimization: Researching efficient sorting strategies based on input size.
- Chunk-Based Sorting Logic: Understanding the conceptual mechanics and performance impact of chunk boundaries.
- Stack Structure Design: Designing robust data structures in C (e.g., doubly linked lists with metadata).
- Memory Management: Ensuring proper
mallocandfreehandling within complex structs. - Operation Logic: Sequencing stack operations (
sa,ra,pb, etc.) for maximum efficiency.
You may notice the ```bash tags in the instructions above. Here is a quick breakdown of the difference:
- Shell: A generic term for any program that provides a command-line interface to the operating system (e.g., the terminal window). It acts as a "shell" around the OS kernel.
- Bash (Bourne Again SHell): A specific implementation of a shell. It is the default on most Linux distributions.
- The Difference: Think of Shell as the category "Smartphone" and Bash as a specific model like "iPhone". Other shells include Zsh (default on macOS), Dash, and Fish. For this project, most commands will work identically across any modern shell.