Skip to content

Commit e5d593a

Browse files
committed
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.
1 parent 9439ee2 commit e5d593a

File tree

3 files changed

+202
-3
lines changed

3 files changed

+202
-3
lines changed
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
using Algorithms.Sorters.Utils;
2+
using NUnit.Framework;
3+
using System.Collections.Generic;
4+
5+
namespace Algorithms.Tests.Sorters.Utils
6+
{
7+
[TestFixture]
8+
public class GallopingStrategyTests
9+
{
10+
private IComparer<int> comparer = Comparer<int>.Default;
11+
12+
[Test]
13+
public void GallopLeft_KeyPresent_ReturnsCorrectIndex()
14+
{
15+
var array = new[] { 1, 2, 3, 4, 5 };
16+
var index = GallopingStrategy<int>.GallopLeft(array, 3, 0, array.Length, comparer);
17+
Assert.That(index, Is.EqualTo(2));
18+
}
19+
20+
[Test]
21+
public void GallopLeft_KeyNotPresent_ReturnsCorrectIndex()
22+
{
23+
var array = new[] { 1, 2, 4, 5 };
24+
var index = GallopingStrategy<int>.GallopLeft(array, 3, 0, array.Length, comparer);
25+
Assert.That(index, Is.EqualTo(2));
26+
}
27+
28+
[Test]
29+
public void GallopLeft_KeyLessThanAll_ReturnsZero()
30+
{
31+
var array = new[] { 2, 3, 4, 5 };
32+
var index = GallopingStrategy<int>.GallopLeft(array, 1, 0, array.Length, comparer);
33+
Assert.That(index, Is.EqualTo(0));
34+
}
35+
36+
[Test]
37+
public void GallopLeft_KeyGreaterThanAll_ReturnsLength()
38+
{
39+
var array = new[] { 1, 2, 3, 4 };
40+
var index = GallopingStrategy<int>.GallopLeft(array, 5, 0, array.Length, comparer);
41+
Assert.That(index, Is.EqualTo(array.Length));
42+
}
43+
44+
[Test]
45+
public void GallopRight_KeyPresent_ReturnsCorrectIndex()
46+
{
47+
var array = new[] { 1, 2, 3, 4, 5 };
48+
var index = GallopingStrategy<int>.GallopRight(array, 3, 0, array.Length, comparer);
49+
Assert.That(index, Is.EqualTo(3));
50+
}
51+
52+
[Test]
53+
public void GallopRight_KeyNotPresent_ReturnsCorrectIndex()
54+
{
55+
var array = new[] { 1, 2, 4, 5 };
56+
var index = GallopingStrategy<int>.GallopRight(array, 3, 0, array.Length, comparer);
57+
Assert.That(index, Is.EqualTo(2));
58+
}
59+
60+
[Test]
61+
public void GallopRight_KeyLessThanAll_ReturnsZero()
62+
{
63+
var array = new[] { 2, 3, 4, 5 };
64+
var index = GallopingStrategy<int>.GallopRight(array, 1, 0, array.Length, comparer);
65+
Assert.That(index, Is.EqualTo(0));
66+
}
67+
68+
[Test]
69+
public void GallopRight_KeyGreaterThanAll_ReturnsLength()
70+
{
71+
var array = new[] { 1, 2, 3, 4 };
72+
var index = GallopingStrategy<int>.GallopRight(array, 5, 0, array.Length, comparer);
73+
Assert.That(index, Is.EqualTo(array.Length));
74+
}
75+
76+
[Test]
77+
public void GallopLeft_EmptyArray_ReturnsZero()
78+
{
79+
var array = new int[] { };
80+
var index = GallopingStrategy<int>.GallopLeft(array, 1, 0, array.Length, comparer);
81+
Assert.That(index, Is.EqualTo(0));
82+
}
83+
84+
[Test]
85+
public void GallopRight_EmptyArray_ReturnsZero()
86+
{
87+
var array = new int[] { };
88+
var index = GallopingStrategy<int>.GallopRight(array, 1, 0, array.Length, comparer);
89+
Assert.That(index, Is.EqualTo(0));
90+
}
91+
}
92+
}

Algorithms/Sorters/Comparison/TimSorter.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Collections.Generic;
3+
using Algorithms.Sorters.Utils;
34

45
namespace Algorithms.Sorters.Comparison;
56

@@ -470,7 +471,7 @@ private void MergeAt(T[] array, int index)
470471

471472
stackSize--;
472473

473-
var k = GallopRight(array, array[baseB], baseA, lenA, 0);
474+
var k = GallopingStrategy<T>.GallopRight(array, array[baseB], baseA, lenA, comparer);
474475

475476
baseA += k;
476477
lenA -= k;
@@ -480,7 +481,7 @@ private void MergeAt(T[] array, int index)
480481
return;
481482
}
482483

483-
lenB = GallopLeft(array, array[baseA + lenA - 1], baseB, lenB, lenB - 1);
484+
lenB = GallopingStrategy<T>.GallopLeft(array, array[baseA + lenA - 1], baseB, lenB, comparer);
484485

485486
if (lenB <= 0)
486487
{
@@ -614,7 +615,7 @@ private bool GallopMerge(TimChunk<T> left, TimChunk<T> right, ref int dest)
614615
return true;
615616
}
616617

617-
right.Wins = GallopLeft(right.Array, left.Array[left.Index], right.Index, right.Remaining, 0);
618+
right.Wins = GallopingStrategy<T>.GallopLeft(right.Array, left.Array[left.Index], right.Index, right.Remaining, comparer);
618619
if (right.Wins != 0)
619620
{
620621
Array.Copy(right.Array, right.Index, right.Array, dest, right.Wins);
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using System.Threading.Tasks;
6+
7+
namespace Algorithms.Sorters.Utils
8+
{
9+
public static class GallopingStrategy<T>
10+
{
11+
public static int GallopLeft(T[] array, T key, int baseIndex, int length, IComparer<T> comparer)
12+
{
13+
if (array.Length == 0)
14+
{
15+
return 0;
16+
}
17+
18+
var (offset, lastOfs) = comparer.Compare(key, array[baseIndex]) > 0
19+
? RightRun(array, key, baseIndex, length, 0, comparer)
20+
: LeftRun(array, key, baseIndex, 0, comparer);
21+
22+
return FinalOffset(array, key, baseIndex, offset, lastOfs, 1, comparer);
23+
}
24+
25+
public static int GallopRight(T[] array, T key, int baseIndex, int length, IComparer<T> comparer)
26+
{
27+
if (array.Length == 0)
28+
{
29+
return 0;
30+
}
31+
32+
var (offset, lastOfs) = comparer.Compare(key, array[baseIndex]) < 0
33+
? LeftRun(array, key, baseIndex, length, comparer)
34+
: RightRun(array, key, baseIndex, length, 0, comparer);
35+
36+
return FinalOffset(array, key, baseIndex, offset, lastOfs, 0, comparer);
37+
}
38+
39+
private static (int offset, int lastOfs) LeftRun(T[] array, T key, int baseIndex, int hint, IComparer<T> comparer)
40+
{
41+
var maxOfs = hint + 1;
42+
var (offset, tmp) = (1, 0);
43+
44+
while (offset < maxOfs && comparer.Compare(key, array[baseIndex + hint - offset]) < 0)
45+
{
46+
tmp = offset;
47+
offset = BoundLeftShift(offset);
48+
}
49+
50+
if (offset > maxOfs)
51+
{
52+
offset = maxOfs;
53+
}
54+
55+
var lastOfs = hint - offset;
56+
offset = hint - tmp;
57+
58+
return (offset, lastOfs);
59+
}
60+
61+
private static (int offset, int lastOfs) RightRun(T[] array, T key, int baseIndex, int len, int hint, IComparer<T> comparer)
62+
{
63+
var (offset, lastOfs) = (1, 0);
64+
var maxOfs = len - hint;
65+
while (offset < maxOfs && comparer.Compare(key, array[baseIndex + hint + offset]) > 0)
66+
{
67+
lastOfs = offset;
68+
offset = BoundLeftShift(offset);
69+
}
70+
71+
if (offset > maxOfs)
72+
{
73+
offset = maxOfs;
74+
}
75+
76+
offset += hint;
77+
lastOfs += hint;
78+
79+
return (offset, lastOfs);
80+
}
81+
82+
private static int FinalOffset(T[] array, T key, int baseIndex, int offset, int lastOfs, int lt, IComparer<T> comparer)
83+
{
84+
lastOfs++;
85+
while (lastOfs < offset)
86+
{
87+
var m = lastOfs + (int)((uint)(offset - lastOfs) >> 1);
88+
89+
if (comparer.Compare(key, array[baseIndex + m]) < lt)
90+
{
91+
offset = m;
92+
}
93+
else
94+
{
95+
lastOfs = m + 1;
96+
}
97+
}
98+
99+
return offset;
100+
}
101+
102+
private static int BoundLeftShift(int shiftable) => (shiftable << 1) < 0
103+
? (shiftable << 1) + 1
104+
: int.MaxValue;
105+
}
106+
}

0 commit comments

Comments
 (0)