-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Extract galloping methods into static GallopingStrategy class
- Moved galloping logic (GallopLeft, GallopRight, LeftRun, RightRun, FinalOffset) from TimSorter to a new GallopingStrategy static class. - Simplified the code by removing the interface and making all methods static since there's no need for instance-specific behavior. - The refactored GallopingStrategy class now encapsulates galloping functionality, improving modularity and testability. - Updated TimSorter to use GallopingStrategy for gallop operations, enhancing code clarity and separation of concerns.
- Loading branch information
Showing
3 changed files
with
202 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
using Algorithms.Sorters.Utils; | ||
using NUnit.Framework; | ||
using System.Collections.Generic; | ||
|
||
namespace Algorithms.Tests.Sorters.Utils | ||
{ | ||
[TestFixture] | ||
public class GallopingStrategyTests | ||
{ | ||
private IComparer<int> comparer = Comparer<int>.Default; | ||
|
||
[Test] | ||
public void GallopLeft_KeyPresent_ReturnsCorrectIndex() | ||
{ | ||
var array = new[] { 1, 2, 3, 4, 5 }; | ||
var index = GallopingStrategy<int>.GallopLeft(array, 3, 0, array.Length, comparer); | ||
Assert.That(index, Is.EqualTo(2)); | ||
} | ||
|
||
[Test] | ||
public void GallopLeft_KeyNotPresent_ReturnsCorrectIndex() | ||
{ | ||
var array = new[] { 1, 2, 4, 5 }; | ||
var index = GallopingStrategy<int>.GallopLeft(array, 3, 0, array.Length, comparer); | ||
Assert.That(index, Is.EqualTo(2)); | ||
} | ||
|
||
[Test] | ||
public void GallopLeft_KeyLessThanAll_ReturnsZero() | ||
{ | ||
var array = new[] { 2, 3, 4, 5 }; | ||
var index = GallopingStrategy<int>.GallopLeft(array, 1, 0, array.Length, comparer); | ||
Assert.That(index, Is.EqualTo(0)); | ||
} | ||
|
||
[Test] | ||
public void GallopLeft_KeyGreaterThanAll_ReturnsLength() | ||
{ | ||
var array = new[] { 1, 2, 3, 4 }; | ||
var index = GallopingStrategy<int>.GallopLeft(array, 5, 0, array.Length, comparer); | ||
Assert.That(index, Is.EqualTo(array.Length)); | ||
} | ||
|
||
[Test] | ||
public void GallopRight_KeyPresent_ReturnsCorrectIndex() | ||
{ | ||
var array = new[] { 1, 2, 3, 4, 5 }; | ||
var index = GallopingStrategy<int>.GallopRight(array, 3, 0, array.Length, comparer); | ||
Assert.That(index, Is.EqualTo(3)); | ||
} | ||
|
||
[Test] | ||
public void GallopRight_KeyNotPresent_ReturnsCorrectIndex() | ||
{ | ||
var array = new[] { 1, 2, 4, 5 }; | ||
var index = GallopingStrategy<int>.GallopRight(array, 3, 0, array.Length, comparer); | ||
Assert.That(index, Is.EqualTo(2)); | ||
} | ||
|
||
[Test] | ||
public void GallopRight_KeyLessThanAll_ReturnsZero() | ||
{ | ||
var array = new[] { 2, 3, 4, 5 }; | ||
var index = GallopingStrategy<int>.GallopRight(array, 1, 0, array.Length, comparer); | ||
Assert.That(index, Is.EqualTo(0)); | ||
} | ||
|
||
[Test] | ||
public void GallopRight_KeyGreaterThanAll_ReturnsLength() | ||
{ | ||
var array = new[] { 1, 2, 3, 4 }; | ||
var index = GallopingStrategy<int>.GallopRight(array, 5, 0, array.Length, comparer); | ||
Assert.That(index, Is.EqualTo(array.Length)); | ||
} | ||
|
||
[Test] | ||
public void GallopLeft_EmptyArray_ReturnsZero() | ||
{ | ||
var array = new int[] { }; | ||
var index = GallopingStrategy<int>.GallopLeft(array, 1, 0, array.Length, comparer); | ||
Assert.That(index, Is.EqualTo(0)); | ||
} | ||
|
||
[Test] | ||
public void GallopRight_EmptyArray_ReturnsZero() | ||
{ | ||
var array = new int[] { }; | ||
var index = GallopingStrategy<int>.GallopRight(array, 1, 0, array.Length, comparer); | ||
Assert.That(index, Is.EqualTo(0)); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Text; | ||
using System.Threading.Tasks; | ||
|
||
namespace Algorithms.Sorters.Utils | ||
{ | ||
public static class GallopingStrategy<T> | ||
{ | ||
public static int GallopLeft(T[] array, T key, int baseIndex, int length, IComparer<T> comparer) | ||
{ | ||
if (array.Length == 0) | ||
{ | ||
return 0; | ||
} | ||
|
||
var (offset, lastOfs) = comparer.Compare(key, array[baseIndex]) > 0 | ||
? RightRun(array, key, baseIndex, length, 0, comparer) | ||
: LeftRun(array, key, baseIndex, 0, comparer); | ||
|
||
return FinalOffset(array, key, baseIndex, offset, lastOfs, 1, comparer); | ||
} | ||
|
||
public static int GallopRight(T[] array, T key, int baseIndex, int length, IComparer<T> comparer) | ||
{ | ||
if (array.Length == 0) | ||
{ | ||
return 0; | ||
} | ||
|
||
var (offset, lastOfs) = comparer.Compare(key, array[baseIndex]) < 0 | ||
? LeftRun(array, key, baseIndex, length, comparer) | ||
: RightRun(array, key, baseIndex, length, 0, comparer); | ||
|
||
return FinalOffset(array, key, baseIndex, offset, lastOfs, 0, comparer); | ||
} | ||
|
||
private static (int offset, int lastOfs) LeftRun(T[] array, T key, int baseIndex, int hint, IComparer<T> comparer) | ||
{ | ||
var maxOfs = hint + 1; | ||
var (offset, tmp) = (1, 0); | ||
|
||
while (offset < maxOfs && comparer.Compare(key, array[baseIndex + hint - offset]) < 0) | ||
{ | ||
tmp = offset; | ||
offset = BoundLeftShift(offset); | ||
} | ||
|
||
if (offset > maxOfs) | ||
{ | ||
offset = maxOfs; | ||
} | ||
|
||
var lastOfs = hint - offset; | ||
offset = hint - tmp; | ||
|
||
return (offset, lastOfs); | ||
} | ||
|
||
private static (int offset, int lastOfs) RightRun(T[] array, T key, int baseIndex, int len, int hint, IComparer<T> comparer) | ||
{ | ||
var (offset, lastOfs) = (1, 0); | ||
var maxOfs = len - hint; | ||
while (offset < maxOfs && comparer.Compare(key, array[baseIndex + hint + offset]) > 0) | ||
{ | ||
lastOfs = offset; | ||
offset = BoundLeftShift(offset); | ||
} | ||
|
||
if (offset > maxOfs) | ||
{ | ||
offset = maxOfs; | ||
} | ||
|
||
offset += hint; | ||
lastOfs += hint; | ||
|
||
return (offset, lastOfs); | ||
} | ||
|
||
private static int FinalOffset(T[] array, T key, int baseIndex, int offset, int lastOfs, int lt, IComparer<T> comparer) | ||
{ | ||
lastOfs++; | ||
while (lastOfs < offset) | ||
{ | ||
var m = lastOfs + (int)((uint)(offset - lastOfs) >> 1); | ||
|
||
if (comparer.Compare(key, array[baseIndex + m]) < lt) | ||
{ | ||
offset = m; | ||
} | ||
else | ||
{ | ||
lastOfs = m + 1; | ||
} | ||
} | ||
|
||
return offset; | ||
} | ||
|
||
private static int BoundLeftShift(int shiftable) => (shiftable << 1) < 0 | ||
? (shiftable << 1) + 1 | ||
: int.MaxValue; | ||
} | ||
} |