github.com/primecitizens/pcz/std@v0.2.1/algo/sort/sort.go (about)

     1  // SPDX-License-Identifier: Apache-2.0
     2  // Copyright 2023 The Prime Citizens
     3  //
     4  // Copyright 2022 The Go Authors. All rights reserved.
     5  // Use of this source code is governed by a BSD-style
     6  // license that can be found in the LICENSE file.
     7  
     8  package sort
     9  
    10  import (
    11  	"github.com/primecitizens/pcz/std/core/bits"
    12  	"github.com/primecitizens/pcz/std/core/cmp"
    13  	"github.com/primecitizens/pcz/std/core/iter"
    14  	"github.com/primecitizens/pcz/std/core/mark"
    15  )
    16  
    17  // An implementation of Interface can be sorted by the routines in this package.
    18  // The methods refer to elements of the underlying collection by integer index.
    19  type Interface interface {
    20  	// A sortable collection must have finite elements.
    21  	iter.Finite
    22  
    23  	// Less reports whether the element with index i
    24  	// must sort before the element with index j.
    25  	//
    26  	// If both Less(i, j) and Less(j, i) are false,
    27  	// then the elements at index i and j are considered equal.
    28  	// Ascend may place equal elements in any order in the final result,
    29  	// while Stable preserves the original input order of equal elements.
    30  	//
    31  	// Less must describe a transitive ordering:
    32  	//  - if both Less(i, j) and Less(j, k) are true, then Less(i, k) must be true as well.
    33  	//  - if both Less(i, j) and Less(j, k) are false, then Less(i, k) must be false as well.
    34  	//
    35  	// Note that floating-point comparison (the < operator on float32 or float64 values)
    36  	// is not a transitive ordering when not-a-number (NaN) values are involved.
    37  	// See Float64Slice.Less for a correct implementation for floating-point values.
    38  	Less(i, j int) bool
    39  
    40  	// Swap swaps the elements with indexes i and j.
    41  	Swap(i, j int)
    42  }
    43  
    44  // Ascend sorts data in ascending order as determined by the Less method.
    45  //
    46  // It makes one call to data.Len to determine n and O(n*log(n)) calls to
    47  // data.Less and data.Swap. The sort is not guaranteed to be stable.
    48  func Ascend[T Interface](data T) {
    49  	n := data.Len()
    50  	if n <= 1 {
    51  		return
    52  	}
    53  
    54  	pdqsort(data, 0, n, bits.Len(uint(n)))
    55  }
    56  
    57  // StableAscend sorts data in ascending order as determined by the Less method,
    58  // while keeping the original order of equal elements.
    59  //
    60  // It makes one call to data.Len to determine n, O(n*log(n)) calls to
    61  // data.Less and O(n*log(n)*log(n)) calls to data.Swap.
    62  func StableAscend[T Interface](data T) {
    63  	stable(data, data.Len())
    64  }
    65  
    66  // IsAscend reports whether data is sorted in ascending order.
    67  func IsAscend[T Interface](data T) bool {
    68  	n := data.Len()
    69  	for i := n - 1; i > 0; i-- {
    70  		if data.Less(i, i-1) {
    71  			return false
    72  		}
    73  	}
    74  	return true
    75  }
    76  
    77  func SliceAscend[T any](data []T, cmp func(data []T, i, j int) bool) {
    78  	x := SliceSorter[T]{
    79  		Data:     data,
    80  		LessFunc: cmp,
    81  	}
    82  
    83  	Ascend(mark.NoEscape(&x))
    84  }
    85  
    86  func SliceStableAscend[T any](data []T, cmp func(data []T, i, j int) bool) {
    87  	x := SliceSorter[T]{
    88  		Data:     data,
    89  		LessFunc: cmp,
    90  	}
    91  
    92  	stable(mark.NoEscape(&x), len(data))
    93  }
    94  
    95  func SliceIsAscend[T any](data []T, cmp func(data []T, i, j int) bool) bool {
    96  	x := SliceSorter[T]{
    97  		Data:     data,
    98  		LessFunc: cmp,
    99  	}
   100  
   101  	return IsAscend(mark.NoEscape(&x))
   102  }
   103  
   104  func BuiltinAscend[T cmp.FOrdered](data []T) {
   105  	SliceAscend(data, BuiltinLessFunc[T])
   106  }
   107  
   108  func BuiltinIsAscend[T cmp.FOrdered](data []T) bool {
   109  	return SliceIsAscend(data, BuiltinLessFunc[T])
   110  }