Universal Radix Sort
A high-performance, generic Radix Sort implementation for Rust. This library provides a non-comparative sorting algorithm capable of sorting integers, floating-point numbers, and strings with O(n·k) time complexity.
Designed to outperform standard comparison-based sorts (like QuickSort or MergeSort, which are O(n log n)) when dealing with large datasets of numbers or fixed-length strings.
Table of Contents
- Features
- Installation
- Quick Start
- Performance & Complexity
- When to Use Radix Sort
- Technical Details
- API Documentation
- Safety & Edge Cases
- Benchmarking
- Contributing
- License
Features
| Feature | Description |
|---|---|
| Fast | Linear time complexity O(n·k) where k is the number of bytes/digits |
| Universal | Supports i8-i128, u8-u128, f32, f64, String, and &str |
| Safe | Handles NaN, Infinity, empty collections, and edge cases gracefully |
| Flexible | Supports ascending and descending order |
| Memory Efficient | Configurable options for in-place or allocated sorting |
| Zero Dependencies | Core functionality has no external dependencies |
| Stable Sort | Maintains relative order of equal elements |
Installation
Add this to your Cargo.toml:
[]
= "0.1.0"
Or install via cargo:
Quick Start
Sorting Integers
Handles signed integers correctly using bit manipulation to map them to an unsigned space.
use ;
Sorting Floating-Point Numbers
Handles floating-point intricacies (negative zero, denormalized numbers, NaN) via IEEE 754 bit-flipping logic.
use ;
Sorting Strings
Uses lexicographical ordering with MSD (Most Significant Digit) first strategy.
use ;
Descending Order
use ;
Return New Sorted Vector
use RadixSort;
Performance & Complexity
| Metric | Complexity | Description |
|---|---|---|
| Time | O(n·k) | Where n is array length and k is the number of passes (bytes) |
| Space | O(n) | Requires a temporary buffer of size n for stability |
Comparison with Standard Sorts
For large n, Radix Sort is generally faster than QuickSort O(n log n), provided that k (the size of the data type in bytes) is not excessively large compared to log n.
| Data Type | Passes (k) | Best For |
|---|---|---|
| Integers | 8 bytes (64-bit) | Large numeric datasets |
| Floats | 8 bytes (64-bit) | Scientific computing |
| Strings | Variable | Fixed-length or similar-length strings |
When to Use Radix Sort
Good For
| Scenario | Reason |
|---|---|
| Large datasets (> 1,000 elements) | Linear complexity beats O(n log n) |
| Fixed-width numeric types | Predictable number of passes |
| Stability required | Radix Sort is inherently stable |
| Known value ranges | Efficient byte extraction |
| Repeated sorting | Consistent performance |
Not Ideal For
| Scenario | Reason |
|---|---|
| Small datasets (< 100 elements) | Constant overhead outweighs benefits |
| Highly variable-length strings | k becomes unpredictable |
| Memory constrained | Requires O(n) temporary buffer |
| Custom comparators | Radix Sort uses natural ordering |
| Linked lists | Requires random access |
Break-Even Point
use estimate_break_even_point;
// Estimated minimum collection size for Radix Sort to be beneficial
let break_even = estimate_break_even_point; // 8 bytes (i64, f64)
// Returns: ~1000 elements
Technical Details
Integer Sorting
Uses an offset binary approach (flipping the sign bit) to correctly sort negative numbers before positives without branching comparisons:
// Transformation for signed integers
const SIGN_BIT: u64 = 1 << 63;
let transformed = ^ SIGN_BIT;
| Original | Transformed |
|---|---|
-9000 |
Small positive |
-1 |
Medium positive |
0 |
Middle value |
1 |
Large positive |
9000 |
Larger positive |
Floating-Point Sorting
Converts double to int bits using IEEE 754 transformation:
| Value Type | Transformation |
|---|---|
| Positive | Flip sign bit only |
| Negative | Flip ALL bits |
| NaN | Map to maximum key (sorted to end) |
| Infinity | Handled correctly per IEEE 754 |
// IEEE 754 transformation
if value.is_nan else if bits & 0x8000_0000_0000_0000 != 0 else
String Sorting
Decomposes strings into UTF-8 bytes and applies MSB (Most Significant Byte) first sorting strategy for correct lexicographical order:
- Uses 256 radix (UTF-8) instead of 65536 (UTF-16) for memory efficiency
- Handles variable-length strings with null-byte padding
- Early termination optimization for MSD-first mode
API Documentation
Core Types
| Type | Description |
|---|---|
RadixSort<T> |
Main sorting struct |
RadixDataType |
Data type configuration |
SortDirection |
Ascending/Descending |
ProcessingOrder |
LSB-first/MSB-first |
RadixSortable |
Trait for sortable types |
RadixError |
Error types |
Full Documentation
Visit docs.rs/universal_radix_sort for complete API documentation with examples.
Safety & Edge Cases
| Edge Case | Handling |
|---|---|
| NaN values | Consistently placed at the end |
| Infinity | Positive/Negative infinity handled per IEEE 754 |
| Negative zero | Treated equal to positive zero |
| Empty collections | Returns immediately without allocation |
| Single element | Returns immediately (already sorted) |
| Duplicates | Maintains stability (relative order preserved) |
| Empty strings | Sorted before non-empty strings |
Example: NaN Handling
use ;
let mut values = vec!;
let sorter = new;
sorter.sort.unwrap;
assert!; // NaN at the end
assert_eq!;
Benchmarking
Run Benchmarks
# Run all benchmarks
# Run specific benchmark group
# View HTML report
Benchmark Suite
The included benchmark suite compares Radix Sort against Rust's standard library sort:
- Integer Sorting:
i64with various dataset sizes - Float Sorting:
f64with NaN and Infinity handling - String Sorting: Variable-length strings
Performance Tips
- Use release mode for accurate benchmarks:
cargo bench --release - Run multiple times to average out system noise
- Close other applications to reduce CPU contention
- Monitor thermal throttling on laptops
Contributing
Contributions are welcome! Please follow these guidelines:
Getting Started
# Fork the repository
# Run tests
# Run benchmarks
Code Style
- Follow Rust API Guidelines
- Include documentation comments with examples
- Add tests for new functionality
- Run
cargo clippyandcargo fmtbefore submitting
Pull Request Checklist
- Tests pass (
cargo test) - Benchmarks run (
cargo bench) - Documentation updated
- Clippy warnings resolved
- Code formatted (
cargo fmt)