github.com/egonelbre/exp@v0.0.0-20240430123955-ed1d3aa93911/sorts/dpsort/sort.go (about)

     1  //
     2  // based on http://codeblab.com/wp-content/uploads/2009/09/DualPivotQuicksort.pdf
     3  //
     4  
     5  package dpsort
     6  
     7  import "sort"
     8  
     9  const insertionSortThreshold = 27
    10  
    11  func dataequal(data sort.Interface, i, k int) bool {
    12      return !(data.Less(i, k) || data.Less(k, i))
    13  }
    14  
    15  func insertionSort(data sort.Interface, lo, hi int) {
    16      for i := lo + 1; i <= hi; i++ {
    17          for k := i; k > lo && data.Less(k, k-1); k-- {
    18              data.Swap(k, k-1)
    19          }
    20      }
    21  }
    22  
    23  func Sort(data sort.Interface) {
    24      sortp(data, 0, data.Len()-1, 3)
    25  }
    26  
    27  func sortp(data sort.Interface, left, right int, div int) {
    28      n := right - left
    29      if n == 0 {
    30          return
    31      } else if n < insertionSortThreshold {
    32          insertionSort(data, left, right)
    33          return
    34      }
    35  
    36      third := n / div
    37      // "medians"
    38      m1 := left + third
    39      m2 := right - third
    40      if m1 <= left {
    41          m1 = left + 1
    42      }
    43      if m2 >= right {
    44          m2 = right - 1
    45      }
    46  
    47      if data.Less(m1, m2) {
    48          data.Swap(m1, left)
    49          data.Swap(m2, right)
    50      } else {
    51          data.Swap(m1, right)
    52          data.Swap(m2, left)
    53      }
    54  
    55      // pointers
    56      less := left + 1
    57      great := right - 1
    58      // sorting
    59      for k := less; k <= great; k++ {
    60          if data.Less(k, left) {
    61              data.Swap(k, less)
    62              less++
    63          } else if data.Less(right, k) {
    64              for k < great && data.Less(right, great) {
    65                  great--
    66              }
    67              data.Swap(k, great)
    68              great--
    69              if data.Less(k, left) {
    70                  data.Swap(k, less)
    71                  less++
    72              }
    73          }
    74      }
    75  
    76      // swaps
    77      dist := great - less
    78      if dist < 13 {
    79          div++
    80      }
    81  
    82      data.Swap(less-1, left)
    83      data.Swap(great+1, right)
    84  
    85      // subarrays
    86      sortp(data, left, less-2, div)
    87      sortp(data, great+2, right, div)
    88  
    89      // equal elements
    90      if dist > n-13 && !dataequal(data, left, right) {
    91          for k := less; k <= great; k++ {
    92              if dataequal(data, k, left) {
    93                  data.Swap(k, less)
    94                  less++
    95              } else if dataequal(data, k, right) {
    96                  data.Swap(k, great)
    97                  great--
    98                  if dataequal(data, k, left) {
    99                      data.Swap(k, less)
   100                      less++
   101                  }
   102              }
   103          }
   104      }
   105      // subarray
   106      if data.Less(left, right) {
   107          sortp(data, less, great, div)
   108      }
   109  }