Skip to content

Commit e347c21

Browse files
Bucket Sort: .NET 10, corrected bucket formula and bubble sort, copy-per-call benchmark (#2371)
Targets net10.0 with BenchmarkDotNet 0.15.8 and MSTest 4.5.2. SortArray now scales each value's distance from the minimum to the bucket count with long arithmetic and checks the base case first; BubbleSort compares neighbours; SortArrayOptimized uses a long range and a nullable node. The benchmark moves to BucketSortBenchmarks, copies its input per call and adds an Array.Sort baseline. New edge-case, full-range and random tests.
1 parent 3271518 commit e347c21

6 files changed

Lines changed: 254 additions & 160 deletions

File tree

‎csharp-algorithms/BucketSort/BucketSort/BucketSort.csproj‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@
22

33
<PropertyGroup>
44
<OutputType>Exe</OutputType>
5-
<TargetFramework>net6.0</TargetFramework>
5+
<TargetFramework>net10.0</TargetFramework>
66
<ImplicitUsings>enable</ImplicitUsings>
77
<Nullable>enable</Nullable>
88
</PropertyGroup>
99

1010
<ItemGroup>
11-
<PackageReference Include="BenchmarkDotNet" Version="0.13.1" />
11+
<PackageReference Include="BenchmarkDotNet" Version="0.15.8" />
1212
</ItemGroup>
1313

1414
</Project>
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
using BenchmarkDotNet.Attributes;
2+
3+
namespace BucketSort;
4+
5+
public class BucketSortBenchmarks
6+
{
7+
private readonly BucketSortMethods _sorter = new();
8+
private int[] _source = [];
9+
private int[] _work = [];
10+
11+
[Params(200, 2_000, 20_000)]
12+
public int Size { get; set; }
13+
14+
[Params("Random", "Sorted")]
15+
public string Input { get; set; } = "Random";
16+
17+
[GlobalSetup]
18+
public void Setup()
19+
{
20+
_source = Input == "Random"
21+
? BucketSortMethods.CreateRandomArray(Size)
22+
: BucketSortMethods.CreateSortedArray(Size);
23+
_work = new int[Size];
24+
}
25+
26+
[Benchmark]
27+
public int[] SortArray()
28+
{
29+
_source.CopyTo(_work, 0);
30+
31+
return _sorter.SortArray(_work);
32+
}
33+
34+
[Benchmark]
35+
public int[] SortArrayOptimized()
36+
{
37+
_source.CopyTo(_work, 0);
38+
39+
return _sorter.SortArrayOptimized(_work);
40+
}
41+
42+
[Benchmark(Baseline = true)]
43+
public int[] ArraySort()
44+
{
45+
_source.CopyTo(_work, 0);
46+
Array.Sort(_work);
47+
48+
return _work;
49+
}
50+
}
Lines changed: 97 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -1,155 +1,142 @@
1-
using BenchmarkDotNet.Attributes;
1+
namespace BucketSort;
22

3-
namespace BucketSort
3+
public class BucketSortMethods
44
{
5-
public class BucketSortMethods
5+
public int[] SortArray(int[] array)
66
{
7-
public IEnumerable<object[]> SampleArrays()
7+
if (array.Length <= 1)
88
{
9-
yield return new object[] { CreateRandomArray(200), "Small Unsorted" };
10-
yield return new object[] { CreateRandomArray(2000), "Medium Unsorted" };
11-
yield return new object[] { CreateRandomArray(20000), "Large Unsorted" };
12-
yield return new object[] { CreateSortedArray(200), "Small Sorted" };
13-
yield return new object[] { CreateSortedArray(2000), "Medium Sorted" };
14-
yield return new object[] { CreateSortedArray(20000), "Large Sorted" };
9+
return array;
1510
}
1611

17-
[Benchmark]
18-
[ArgumentsSource(nameof(SampleArrays))]
19-
public int[] SortArray(int[] array, string arrayName)
20-
{
21-
List<int> sortedList = new List<int>();
22-
var minValue = array[0];
23-
var maxValue = array[0];
24-
25-
if (array == null || array.Length <= 1)
26-
{
27-
return array;
28-
}
12+
List<int> sortedList = [];
13+
var minValue = array[0];
14+
var maxValue = array[0];
2915

30-
for (int i = 1; i < array.Length; i++)
31-
{
32-
if (array[i] > maxValue)
33-
maxValue = array[i];
34-
if (array[i] < minValue)
35-
minValue = array[i];
36-
}
16+
for (int i = 1; i < array.Length; i++)
17+
{
18+
if (array[i] > maxValue)
19+
maxValue = array[i];
20+
if (array[i] < minValue)
21+
minValue = array[i];
22+
}
3723

38-
var numberOfBuckets = maxValue - minValue + 1;
39-
List<int>[] bucket = new List<int>[numberOfBuckets];
24+
var numberOfBuckets = array.Length;
25+
var range = (long)maxValue - minValue + 1;
26+
List<int>[] bucket = new List<int>[numberOfBuckets];
4027

41-
for (int i = 0; i < numberOfBuckets; i++)
42-
{
43-
bucket[i] = new List<int>();
44-
}
45-
46-
for (int i = 0; i < array.Length; i++)
47-
{
48-
var selectedBucket = (array[i] / numberOfBuckets);
49-
bucket[selectedBucket].Add(array[i]);
50-
}
28+
for (int i = 0; i < numberOfBuckets; i++)
29+
{
30+
bucket[i] = [];
31+
}
5132

52-
for (int i = 0; i < numberOfBuckets; i++)
53-
{
54-
int[] temp = BubbleSort(bucket[i]);
55-
sortedList.AddRange(temp);
56-
}
33+
for (int i = 0; i < array.Length; i++)
34+
{
35+
var selectedBucket = (int)((array[i] - (long)minValue) * numberOfBuckets / range);
36+
bucket[selectedBucket].Add(array[i]);
37+
}
5738

58-
return sortedList.ToArray();
39+
for (int i = 0; i < numberOfBuckets; i++)
40+
{
41+
int[] temp = BubbleSort(bucket[i]);
42+
sortedList.AddRange(temp);
5943
}
6044

61-
public static int[] BubbleSort(List<int> listInput)
45+
return sortedList.ToArray();
46+
}
47+
48+
public static int[] BubbleSort(List<int> listInput)
49+
{
50+
for (int i = 0; i < listInput.Count - 1; i++)
6251
{
63-
for (int i = 0; i < listInput.Count; i++)
52+
for (int j = 0; j < listInput.Count - i - 1; j++)
6453
{
65-
for (int j = 0; j < listInput.Count; j++)
54+
if (listInput[j] > listInput[j + 1])
6655
{
67-
if (listInput[i] < listInput[j])
68-
{
69-
var temp = listInput[i];
70-
listInput[i] = listInput[j];
71-
listInput[j] = temp;
72-
}
56+
var temp = listInput[j];
57+
listInput[j] = listInput[j + 1];
58+
listInput[j + 1] = temp;
7359
}
7460
}
75-
return listInput.ToArray();
7661
}
7762

63+
return listInput.ToArray();
64+
}
7865

79-
[Benchmark]
80-
[ArgumentsSource(nameof(SampleArrays))]
81-
public int[] SortArrayOptimized(int[] array, string arrayName)
66+
public int[] SortArrayOptimized(int[] array)
67+
{
68+
if (array.Length <= 1)
8269
{
83-
if (array == null || array.Length <= 1)
84-
{
85-
return array;
86-
}
70+
return array;
71+
}
8772

88-
int maxValue = array[0];
89-
int minValue = array[0];
73+
int maxValue = array[0];
74+
int minValue = array[0];
9075

91-
for (int i = 1; i < array.Length; i++)
76+
for (int i = 1; i < array.Length; i++)
77+
{
78+
if (array[i] > maxValue)
9279
{
93-
if (array[i] > maxValue)
94-
{
95-
maxValue = array[i];
96-
}
80+
maxValue = array[i];
81+
}
9782

98-
if (array[i] < minValue)
99-
{
100-
minValue = array[i];
101-
}
83+
if (array[i] < minValue)
84+
{
85+
minValue = array[i];
10286
}
87+
}
10388

104-
LinkedList<int>[] bucket = new LinkedList<int>[maxValue - minValue + 1];
89+
var range = (long)maxValue - minValue + 1;
90+
LinkedList<int>[] bucket = new LinkedList<int>[range];
10591

106-
for (int i = 0; i < array.Length; i++)
92+
for (int i = 0; i < array.Length; i++)
93+
{
94+
if (bucket[array[i] - minValue] == null)
10795
{
108-
if (bucket[array[i] - minValue] == null)
109-
{
110-
bucket[array[i] - minValue] = new LinkedList<int>();
111-
}
112-
113-
bucket[array[i] - minValue].AddLast(array[i]);
96+
bucket[array[i] - minValue] = new LinkedList<int>();
11497
}
11598

116-
var index = 0;
117-
for (int i = 0; i < bucket.Length; i++)
99+
bucket[array[i] - minValue].AddLast(array[i]);
100+
}
101+
102+
var index = 0;
103+
104+
for (int i = 0; i < bucket.Length; i++)
105+
{
106+
if (bucket[i] != null)
118107
{
119-
if (bucket[i] != null)
108+
LinkedListNode<int>? node = bucket[i].First;
109+
110+
while (node != null)
120111
{
121-
LinkedListNode<int> node = bucket[i].First;
122-
123-
while (node != null)
124-
{
125-
array[index] = node.Value;
126-
node = node.Next;
127-
index++;
128-
}
112+
array[index] = node.Value;
113+
node = node.Next;
114+
index++;
129115
}
130116
}
131-
return array;
132117
}
133118

134-
public static int[] CreateRandomArray(int size)
135-
{
136-
var array = new int[size];
137-
var rand = new Random();
119+
return array;
120+
}
138121

139-
for (int i = 0; i < size; i++)
140-
array[i] = rand.Next(1, size);
122+
public static int[] CreateRandomArray(int size)
123+
{
124+
var array = new int[size];
125+
var rand = new Random();
141126

142-
return array;
143-
}
127+
for (int i = 0; i < size; i++)
128+
array[i] = rand.Next(1, size);
144129

145-
public static int[] CreateSortedArray(int size)
146-
{
147-
var array = new int[size];
130+
return array;
131+
}
148132

149-
for (int i = 0; i < size; i++)
150-
array[i] = i;
133+
public static int[] CreateSortedArray(int size)
134+
{
135+
var array = new int[size];
151136

152-
return array;
153-
}
137+
for (int i = 0; i < size; i++)
138+
array[i] = i;
139+
140+
return array;
154141
}
155142
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
using BenchmarkDotNet.Running;
22
using BucketSort;
33

4-
var summary = BenchmarkRunner.Run<BucketSortMethods>();
4+
BenchmarkRunner.Run<BucketSortBenchmarks>(args: args);

‎csharp-algorithms/BucketSort/BucketSortTests/BucketSortTests.csproj‎

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,22 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
4-
<TargetFramework>net6.0</TargetFramework>
4+
<TargetFramework>net10.0</TargetFramework>
5+
<ImplicitUsings>enable</ImplicitUsings>
56
<Nullable>enable</Nullable>
67

78
<IsPackable>false</IsPackable>
89
</PropertyGroup>
910

1011
<ItemGroup>
11-
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0" />
12-
<PackageReference Include="MSTest.TestAdapter" Version="2.2.7" />
13-
<PackageReference Include="MSTest.TestFramework" Version="2.2.7" />
14-
<PackageReference Include="coverlet.collector" Version="3.1.0" />
12+
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.11.0" />
13+
<PackageReference Include="MSTest.TestAdapter" Version="4.5.2" />
14+
<PackageReference Include="MSTest.TestFramework" Version="4.5.2" />
15+
<PackageReference Include="coverlet.collector" Version="10.1.0" />
16+
</ItemGroup>
17+
18+
<ItemGroup>
19+
<Using Include="Microsoft.VisualStudio.TestTools.UnitTesting" />
1520
</ItemGroup>
1621

1722
<ItemGroup>

0 commit comments

Comments
 (0)