-
Notifications
You must be signed in to change notification settings - Fork 1.5k
/
BucketSorter.cs
107 lines (93 loc) · 3.44 KB
/
BucketSorter.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
using System;
using System.Collections.Generic;
using System.Linq;
namespace Algorithms.Sorters.Integer;
/// <summary>
/// Class that implements bucket sort algorithm.
/// </summary>
public class BucketSorter : IIntegerSorter
{
private const int NumOfDigitsInBase10 = 10;
/// <summary>
/// Sorts array elements using BucketSort Algorithm.
/// </summary>
/// <param name="array">Array to sort.</param>
public void Sort(int[] array)
{
if (array.Length <= 1)
{
return;
}
// store maximum number of digits in numbers to sort
var totalDigits = NumberOfDigits(array);
// bucket array where numbers will be placed
var buckets = new int[NumOfDigitsInBase10, array.Length + 1];
// go through all digit places and sort each number
// according to digit place value
for (var pass = 1; pass <= totalDigits; pass++)
{
DistributeElements(array, buckets, pass); // distribution pass
CollectElements(array, buckets); // gathering pass
if (pass != totalDigits)
{
EmptyBucket(buckets); // set size of buckets to 0
}
}
}
/// <summary>
/// Determines the number of digits in the largest number.
/// </summary>
/// <param name="array">Input array.</param>
/// <returns>Number of digits.</returns>
private static int NumberOfDigits(IEnumerable<int> array) => (int)Math.Floor(Math.Log10(array.Max()) + 1);
/// <summary>
/// To distribute elements into buckets based on specified digit.
/// </summary>
/// <param name="data">Input array.</param>
/// <param name="buckets">Array of buckets.</param>
/// <param name="digit">Digit.</param>
private static void DistributeElements(IEnumerable<int> data, int[,] buckets, int digit)
{
// determine the divisor used to get specific digit
var divisor = (int)Math.Pow(10, digit);
foreach (var element in data)
{
// bucketNumber example for hundreds digit:
// ( 1234 % 1000 ) / 100 --> 2
var bucketNumber = NumOfDigitsInBase10 * (element % divisor) / divisor;
// retrieve value in pail[ bucketNumber , 0 ] to
// determine the location in row to store element
var elementNumber = ++buckets[bucketNumber, 0]; // location in bucket to place element
buckets[bucketNumber, elementNumber] = element;
}
}
/// <summary>
/// Return elements to original array.
/// </summary>
/// <param name="data">Input array.</param>
/// <param name="buckets">Array of buckets.</param>
private static void CollectElements(IList<int> data, int[,] buckets)
{
var subscript = 0; // initialize location in data
// loop over buckets
for (var i = 0; i < NumOfDigitsInBase10; i++)
{
// loop over elements in each bucket
for (var j = 1; j <= buckets[i, 0]; j++)
{
data[subscript++] = buckets[i, j]; // add element to array
}
}
}
/// <summary>
/// Sets size of all buckets to zero.
/// </summary>
/// <param name="buckets">Array of buckets.</param>
private static void EmptyBucket(int[,] buckets)
{
for (var i = 0; i < NumOfDigitsInBase10; i++)
{
buckets[i, 0] = 0; // set size of bucket to 0
}
}
}