An open API service indexing awesome lists of open source software.

https://github.com/mew-sh/pqueue

A high-performance Go library that provides intelligent priority queue operations and adaptive sorting algorithms
https://github.com/mew-sh/pqueue

algorithm go golang

Last synced: about 2 months ago
JSON representation

A high-performance Go library that provides intelligent priority queue operations and adaptive sorting algorithms

Awesome Lists containing this project

README

          

# PQueue - Intelligent Priority Queue and Sorting Library

[![Go Version](https://img.shields.io/badge/Go-1.24+-blue.svg)](https://golang.org)
[![GoDoc](https://pkg.go.dev/badge/github.com/mew-sh/pqueue.svg)](https://pkg.go.dev/github.com/mew-sh/pqueue)
[![Go Report Card](https://goreportcard.com/badge/github.com/mew-sh/pqueue)](https://goreportcard.com/report/github.com/mew-sh/pqueue)
[![License](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)

PQueue is a high-performance Go library that provides intelligent priority queue operations and adaptive sorting algorithms. It automatically selects the optimal sorting algorithm based on data characteristics, ensuring maximum performance across different scenarios.

## Features

- 🧠 **Intelligent Algorithm Selection**: Automatically chooses the best sorting algorithm based on data type, size, and patterns
- 🚀 **High Performance**: Optimized implementations of multiple sorting algorithms
- 🔧 **Generic Support**: Works with any comparable type using Go generics
- 📊 **Priority Queue Operations**: Push, pop, peek operations with automatic ordering
- 🎯 **Multiple Data Types**: Built-in support for integers, floats, strings, and custom types
- 📈 **Comprehensive Testing**: Extensive test suite with benchmarks

## Quick Start

```go
package main

import (
"fmt"
"github.com/mew-sh/pqueue"
)

func main() {
// Example as requested
a := []int{6, 5, 4, 9, 2, 7, 1, 8}
p := pqueue.NewInts(a)

// Pop minimum element
min, _ := p.Pop()
fmt.Printf("Popped: %d\n", min) // Output: 1

// Sort remaining elements
p.Sort()
fmt.Printf("Sorted: %v\n", p.ToSlice()) // Output: [2 4 5 6 7 8 9]
}
```

## Supported Data Types

PQueue provides comprehensive support for all Go data types through intelligent type inference and optimized algorithms:

### Basic Types
- **Integers**: `int`, `int8`, `int16`, `int32`, `int64`, `uint`, `uint8`, `uint16`, `uint32`, `uint64`
- **Floating Point**: `float32`, `float64`
- **Strings**: `string`
- **Byte Slices**: `[]byte`
- **Rune Slices**: `[]rune`

### Complex Types
- **Slices**: `[]T` (slice of any type)
- **Arrays**: `[N]T` (fixed-size arrays)
- **Structs**: Custom struct types with comparison functions
- **Pointers**: `*T` (with nil-safe comparisons)
- **Maps**: `map[K]V` (with custom comparison logic)
- **Interfaces**: Interface types
- **Channels**: `chan T`
- **Functions**: `func` types

### Constructor Functions

```go
// Basic types
intQueue := pqueue.NewInts([]int{3, 1, 4, 1, 5})
floatQueue := pqueue.NewFloats([]float64{3.14, 2.71, 1.41})
stringQueue := pqueue.NewStrings([]string{"zebra", "apple", "banana"})

// Complex types
byteQueue := pqueue.NewBytes([][]byte{[]byte("hello"), []byte("world")})
runeQueue := pqueue.NewRunes([][]rune{[]rune("世界"), []rune("hello")})

// Generic constructor for any type
customQueue := pqueue.New(data, func(a, b CustomType) bool {
return a.Field < b.Field
})

// For comparable types
comparableQueue := pqueue.NewComparable(data, lessFunc)
```

## Algorithm Selection Strategy

The library automatically selects the optimal algorithm based on data characteristics:

| Scenario | Optimization Algorithm | Use Case |
|----------|------------------------|----------|
| Very Small Arrays (≤16) | Insertion Sort | Minimal overhead for tiny datasets |
| Nearly Sorted Data | Insertion Sort | Exploits existing order |
| Small Integer Range | Counting Sort | Linear time for bounded integers |
| Large Integer Data | Radix Sort | Non-comparative sorting |
| Large General Data | Introsort | Hybrid approach with guaranteed O(n log n) |
| Real-world Data | Timsort | Adaptive to real-world patterns |
| Distributed/Parallel | Merge Sort | Stable and parallelizable |

## API Reference

### Creating Priority Queues

```go
// For integers
pq := pqueue.NewInts([]int{3, 1, 4, 1, 5})

// For floats
pq := pqueue.NewFloats([]float64{3.14, 2.71, 1.41})

// For strings
pq := pqueue.NewStrings([]string{"apple", "banana", "cherry"})

// For custom types with custom comparison
pq := pqueue.New(data, func(a, b MyType) bool { return a.Value < b.Value })
```

### Basic Operations

```go
// Priority Queue Operations
size := pq.Size() // Get number of elements
isEmpty := pq.IsEmpty() // Check if empty
pq.Push(item) // Add element
item, err := pq.Pop() // Remove and return minimum
item, err := pq.Peek() // Get minimum without removing

// Sorting Operations
pq.Sort() // Auto-select best algorithm
pq.SortWithStrategy(pqueue.QuickStrategy) // Use specific algorithm
data := pq.ToSlice() // Get sorted copy
```

### Available Sorting Strategies

```go
type SortStrategy int

const (
AutoStrategy // Automatic selection (default)
RadixStrategy // Radix sort (integers only)
CountingStrategy // Counting sort (small range integers)
InsertionStrategy // Insertion sort (small/nearly sorted data)
TimsortStrategy // Timsort (adaptive merge sort)
IntrosortStrategy // Introsort (quick + heap + insertion)
MergeStrategy // Merge sort (stable, parallelizable)
QuickStrategy // Quick sort (general purpose)
)
```

## Performance Examples

### Automatic Algorithm Selection

```go
// Small data → Insertion Sort
smallData := []int{3, 1, 4, 1, 5}
pq := pqueue.NewInts(smallData)
pq.Sort() // Uses insertion sort automatically

// Nearly sorted → Insertion Sort
nearlySorted := []int{1, 2, 3, 5, 4, 6, 7}
pq2 := pqueue.NewInts(nearlySorted)
pq2.Sort() // Detects pattern, uses insertion sort

// Large dataset → Introsort
largeData := make([]int, 10000)
// ... populate with random data
pq3 := pqueue.NewInts(largeData)
pq3.Sort() // Uses introsort for guaranteed performance
```

### Specific Algorithm Usage

```go
data := []int{170, 45, 75, 90, 2, 802, 24, 66}
pq := pqueue.NewInts(data)

// Force specific algorithms
pq.SortWithStrategy(pqueue.RadixStrategy) // Good for integers
pq.SortWithStrategy(pqueue.MergeStrategy) // Stable sort
pq.SortWithStrategy(pqueue.CountingStrategy) // Small range integers
```

## Benchmarks

Performance comparison on 5000 random integers:

```
Auto Selection: 245.2µs
Quick Sort: 312.8µs
Merge Sort: 387.1µs
Introsort: 251.4µs
Timsort: 298.7µs
```

*Auto selection chooses the optimal algorithm, often outperforming manual selection.*

## Installation

```bash
go mod init your-project
go get github.com/mew-sh/pqueue
```

## Advanced Usage

### Custom Types

```go
type Person struct {
Name string
Age int
}

people := []Person{
{"Alice", 30},
{"Bob", 25},
{"Charlie", 35},
}

// Sort by age
pq := pqueue.New(people, func(a, b Person) bool {
return a.Age < b.Age
})

pq.Sort()
sorted := pq.ToSlice() // Sorted by age
```

### Multiple Criteria Sorting

```go
// Sort by multiple criteria
pq := pqueue.New(people, func(a, b Person) bool {
if a.Age == b.Age {
return a.Name < b.Name
}
return a.Age < b.Age
})
```

## Testing

Run the comprehensive test suite:

```bash
go test ./... # Run all tests
go test -bench=. # Run benchmarks
go test -v # Verbose output
go test -race # Race condition detection
```

## Examples

See the [example](example/main.go) directory for comprehensive usage examples including:

- Basic priority queue operations
- Automatic algorithm selection
- Performance comparisons
- Different data types
- Custom comparison functions

Run the example:

```bash
go run example/main.go
```

## Data Type Examples

```go
// 1. Numeric Types
integers := []int{6, 5, 4, 9, 2, 7, 1, 8}
intQueue := pqueue.NewInts(integers)
intQueue.Sort()
fmt.Println(intQueue.ToSlice()) // [1 2 4 5 6 7 8 9]

floats := []float64{3.14, 2.71, 1.41, 1.73}
floatQueue := pqueue.NewFloats(floats)
floatQueue.Sort()
fmt.Println(floatQueue.ToSlice()) // [1.41 1.73 2.71 3.14]

// 2. String Types
strings := []string{"zebra", "apple", "banana"}
stringQueue := pqueue.NewStrings(strings)
stringQueue.Sort()
fmt.Println(stringQueue.ToSlice()) // [apple banana zebra]

// Unicode strings with runes
words := [][]rune{[]rune("世界"), []rune("hello"), []rune("αβγ")}
runeQueue := pqueue.NewRunes(words)
runeQueue.Sort()

// Byte slices
byteSlices := [][]byte{[]byte("zebra"), []byte("apple")}
byteQueue := pqueue.NewBytes(byteSlices)
byteQueue.Sort()

// 3. Custom Struct Types
type Person struct {
Name string
Age int
}

people := []Person{
{Name: "Alice", Age: 30},
{Name: "Bob", Age: 25},
{Name: "Charlie", Age: 35},
}

// Sort by age, then by name
personQueue := pqueue.New(people, func(a, b Person) bool {
if a.Age != b.Age {
return a.Age < b.Age
}
return a.Name < b.Name
})
personQueue.Sort()

// 4. Pointer Types
values := []int{5, 2, 8, 1, 9}
ptrs := make([]*int, len(values))
for i := range values {
ptrs[i] = &values[i]
}

ptrQueue := pqueue.New(ptrs, func(a, b *int) bool {
if a == nil || b == nil {
return a == nil && b != nil // nil values first
}
return *a < *b
})
ptrQueue.Sort()

// 5. Slice Types (2D arrays)
slicesOfInts := [][]int{
{3, 2, 1},
{1, 2, 3},
{2, 1, 3},
}

sliceQueue := pqueue.New(slicesOfInts, func(a, b []int) bool {
// Custom comparison: by sum, then lexicographically
sumA, sumB := sum(a), sum(b)
if sumA != sumB {
return sumA < sumB
}
for i := 0; i < len(a) && i < len(b); i++ {
if a[i] != b[i] {
return a[i] < b[i]
}
}
return len(a) < len(b)
})
sliceQueue.Sort()

// 6. Interface Types
type Comparable interface {
CompareTo(other interface{}) int
}

// For types implementing Comparable interface
comparableQueue := pqueue.NewWithComparable([]ComparableType{...})
```

## Algorithm Details

### Insertion Sort
- **Best Case**: O(n) for nearly sorted data
- **Average/Worst**: O(n²)
- **Use**: Small arrays (≤16 elements), nearly sorted data

### Quick Sort
- **Average**: O(n log n)
- **Worst**: O(n²)
- **Use**: General purpose, good cache performance

### Merge Sort
- **All Cases**: O(n log n)
- **Use**: Stable sorting, parallel processing
- **Space**: O(n)

### Introsort
- **All Cases**: O(n log n) guaranteed
- **Use**: Large datasets, unknown data patterns
- **Features**: Hybrid of quicksort, heapsort, and insertion sort

### Timsort
- **Best**: O(n) for real-world data
- **Average/Worst**: O(n log n)
- **Use**: Real-world data with existing patterns

### Radix Sort
- **Complexity**: O(d × n) where d is number of digits
- **Use**: Integers, strings with fixed-length keys
- **Space**: O(n + k)

### Counting Sort
- **Complexity**: O(n + k) where k is range
- **Use**: Small range integers
- **Space**: O(k)

## License

This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.

## Acknowledgments

- Inspired by the intelligent sorting strategies used in production systems
- Algorithm implementations based on proven computer science research
- Performance optimizations derived from real-world usage patterns