1
1
using System ;
2
2
using System . Collections . Generic ;
3
+ using Algorithms . Sorters . Utils ;
3
4
4
5
namespace Algorithms . Sorters . Comparison ;
5
6
@@ -54,7 +55,7 @@ private class TimChunk<Tc>
54
55
public int Wins { get ; set ; }
55
56
}
56
57
57
- public TimSorter ( TimSorterSettings settings )
58
+ public TimSorter ( TimSorterSettings settings , IComparer < T > comparer )
58
59
{
59
60
initMinGallop = minGallop ;
60
61
runBase = new int [ 85 ] ;
@@ -64,6 +65,8 @@ public TimSorter(TimSorterSettings settings)
64
65
65
66
minGallop = settings . MinGallop ;
66
67
minMerge = settings . MinMerge ;
68
+
69
+ this . comparer = comparer ?? Comparer < T > . Default ;
67
70
}
68
71
69
72
/// <summary>
@@ -163,15 +166,6 @@ private static void ReverseRange(T[] array, int start, int end)
163
166
}
164
167
}
165
168
166
- /// <summary>
167
- /// Left shift a value, preventing a roll over to negative numbers.
168
- /// </summary>
169
- /// <param name="shiftable">int value to left shift.</param>
170
- /// <returns>Left shifted value, bound to 2,147,483,647.</returns>
171
- private static int BoundLeftShift ( int shiftable ) => ( shiftable << 1 ) < 0
172
- ? ( shiftable << 1 ) + 1
173
- : int . MaxValue ;
174
-
175
169
/// <summary>
176
170
/// Check the chunks before getting in to a merge to make sure there's something to actually do.
177
171
/// </summary>
@@ -270,105 +264,6 @@ private int CountRunAndMakeAscending(T[] array, int start)
270
264
return runHi - start ;
271
265
}
272
266
273
- /// <summary>
274
- /// Find the position in the array that a key should fit to the left of where it currently sits.
275
- /// </summary>
276
- /// <param name="array">Array to search.</param>
277
- /// <param name="key">Key to place in the array.</param>
278
- /// <param name="i">Base index for the key.</param>
279
- /// <param name="len">Length of the chunk to run through.</param>
280
- /// <param name="hint">Initial starting position to start from.</param>
281
- /// <returns>Offset for the key's location.</returns>
282
- private int GallopLeft ( T [ ] array , T key , int i , int len , int hint )
283
- {
284
- var ( offset , lastOfs ) = comparer . Compare ( key , array [ i + hint ] ) > 0
285
- ? RightRun ( array , key , i , len , hint , 0 )
286
- : LeftRun ( array , key , i , hint , 1 ) ;
287
-
288
- return FinalOffset ( array , key , i , offset , lastOfs , 1 ) ;
289
- }
290
-
291
- /// <summary>
292
- /// Find the position in the array that a key should fit to the right of where it currently sits.
293
- /// </summary>
294
- /// <param name="array">Array to search.</param>
295
- /// <param name="key">Key to place in the array.</param>
296
- /// <param name="i">Base index for the key.</param>
297
- /// <param name="len">Length of the chunk to run through.</param>
298
- /// <param name="hint">Initial starting position to start from.</param>
299
- /// <returns>Offset for the key's location.</returns>
300
- private int GallopRight ( T [ ] array , T key , int i , int len , int hint )
301
- {
302
- var ( offset , lastOfs ) = comparer . Compare ( key , array [ i + hint ] ) < 0
303
- ? LeftRun ( array , key , i , hint , 0 )
304
- : RightRun ( array , key , i , len , hint , - 1 ) ;
305
-
306
- return FinalOffset ( array , key , i , offset , lastOfs , 0 ) ;
307
- }
308
-
309
- private ( int offset , int lastOfs ) LeftRun ( T [ ] array , T key , int i , int hint , int lt )
310
- {
311
- var maxOfs = hint + 1 ;
312
- var ( offset , tmp ) = ( 1 , 0 ) ;
313
-
314
- while ( offset < maxOfs && comparer . Compare ( key , array [ i + hint - offset ] ) < lt )
315
- {
316
- tmp = offset ;
317
- offset = BoundLeftShift ( offset ) ;
318
- }
319
-
320
- if ( offset > maxOfs )
321
- {
322
- offset = maxOfs ;
323
- }
324
-
325
- var lastOfs = hint - offset ;
326
- offset = hint - tmp ;
327
-
328
- return ( offset , lastOfs ) ;
329
- }
330
-
331
- private ( int offset , int lastOfs ) RightRun ( T [ ] array , T key , int i , int len , int hint , int gt )
332
- {
333
- var ( offset , lastOfs ) = ( 1 , 0 ) ;
334
- var maxOfs = len - hint ;
335
- while ( offset < maxOfs && comparer . Compare ( key , array [ i + hint + offset ] ) > gt )
336
- {
337
- lastOfs = offset ;
338
- offset = BoundLeftShift ( offset ) ;
339
- }
340
-
341
- if ( offset > maxOfs )
342
- {
343
- offset = maxOfs ;
344
- }
345
-
346
- offset += hint ;
347
- lastOfs += hint ;
348
-
349
- return ( offset , lastOfs ) ;
350
- }
351
-
352
- private int FinalOffset ( T [ ] array , T key , int i , int offset , int lastOfs , int lt )
353
- {
354
- lastOfs ++ ;
355
- while ( lastOfs < offset )
356
- {
357
- var m = lastOfs + ( int ) ( ( uint ) ( offset - lastOfs ) >> 1 ) ;
358
-
359
- if ( comparer . Compare ( key , array [ i + m ] ) < lt )
360
- {
361
- offset = m ;
362
- }
363
- else
364
- {
365
- lastOfs = m + 1 ;
366
- }
367
- }
368
-
369
- return offset ;
370
- }
371
-
372
267
/// <summary>
373
268
/// Sorts the specified portion of the specified array using a binary
374
269
/// insertion sort. It requires O(n log n) compares, but O(n^2) data movement.
@@ -470,7 +365,7 @@ private void MergeAt(T[] array, int index)
470
365
471
366
stackSize -- ;
472
367
473
- var k = GallopRight ( array , array [ baseB ] , baseA , lenA , 0 ) ;
368
+ var k = GallopingStrategy < T > . GallopRight ( array , array [ baseB ] , baseA , lenA , comparer ) ;
474
369
475
370
baseA += k ;
476
371
lenA -= k ;
@@ -480,7 +375,7 @@ private void MergeAt(T[] array, int index)
480
375
return ;
481
376
}
482
377
483
- lenB = GallopLeft ( array , array [ baseA + lenA - 1 ] , baseB , lenB , lenB - 1 ) ;
378
+ lenB = GallopingStrategy < T > . GallopLeft ( array , array [ baseA + lenA - 1 ] , baseB , lenB , comparer ) ;
484
379
485
380
if ( lenB <= 0 )
486
381
{
@@ -595,7 +490,7 @@ private bool StableMerge(TimChunk<T> left, TimChunk<T> right, ref int dest, int
595
490
596
491
private bool GallopMerge ( TimChunk < T > left , TimChunk < T > right , ref int dest )
597
492
{
598
- left . Wins = GallopRight ( left . Array , right . Array [ right . Index ] , left . Index , left . Remaining , 0 ) ;
493
+ left . Wins = GallopingStrategy < T > . GallopRight ( left . Array , right . Array [ right . Index ] , left . Index , left . Remaining , comparer ) ;
599
494
if ( left . Wins != 0 )
600
495
{
601
496
Array . Copy ( left . Array , left . Index , right . Array , dest , left . Wins ) ;
@@ -614,7 +509,7 @@ private bool GallopMerge(TimChunk<T> left, TimChunk<T> right, ref int dest)
614
509
return true ;
615
510
}
616
511
617
- right . Wins = GallopLeft ( right . Array , left . Array [ left . Index ] , right . Index , right . Remaining , 0 ) ;
512
+ right . Wins = GallopingStrategy < T > . GallopLeft ( right . Array , left . Array [ left . Index ] , right . Index , right . Remaining , comparer ) ;
618
513
if ( right . Wins != 0 )
619
514
{
620
515
Array . Copy ( right . Array , right . Index , right . Array , dest , right . Wins ) ;
0 commit comments