Fix CountingSort for negative numbers (#100)

This commit is contained in:
Nicolas DUBIEN
2018-07-22 17:03:13 +02:00
committed by Oleksii Trekhleb
parent eec7f2f917
commit 3be02b5519
2 changed files with 14 additions and 6 deletions

View File

@ -5,8 +5,9 @@ export default class CountingSort extends Sort {
* @param {number[]} originalArray * @param {number[]} originalArray
* @param {number} [biggestElement] * @param {number} [biggestElement]
*/ */
sort(originalArray, biggestElement = 0) { sort(originalArray, smallestElement = 0, biggestElement = 0) {
// Detect biggest element in array in order to build number bucket array later. // Detect biggest element in array in order to build number bucket array later.
let detectedSmallestElement = smallestElement;
let detectedBiggestElement = biggestElement; let detectedBiggestElement = biggestElement;
if (!detectedBiggestElement) { if (!detectedBiggestElement) {
originalArray.forEach((element) => { originalArray.forEach((element) => {
@ -16,17 +17,20 @@ export default class CountingSort extends Sort {
if (this.comparator.greaterThan(element, detectedBiggestElement)) { if (this.comparator.greaterThan(element, detectedBiggestElement)) {
detectedBiggestElement = element; detectedBiggestElement = element;
} }
if (this.comparator.greaterThan(detectedSmallestElement, element)) {
detectedSmallestElement = element;
}
}); });
} }
// Init buckets array. // Init buckets array.
// This array will hold frequency of each number from originalArray. // This array will hold frequency of each number from originalArray.
const buckets = Array(detectedBiggestElement + 1).fill(0); const buckets = Array(detectedBiggestElement - detectedSmallestElement + 1).fill(0);
originalArray.forEach((element) => { originalArray.forEach((element) => {
// Visit element. // Visit element.
this.callbacks.visitingCallback(element); this.callbacks.visitingCallback(element);
buckets[element] += 1; buckets[element - detectedSmallestElement] += 1;
}); });
// Add previous frequencies to the current one for each number in bucket // Add previous frequencies to the current one for each number in bucket
@ -53,13 +57,13 @@ export default class CountingSort extends Sort {
this.callbacks.visitingCallback(element); this.callbacks.visitingCallback(element);
// Get correct position of this element in sorted array. // Get correct position of this element in sorted array.
const elementSortedPosition = buckets[element]; const elementSortedPosition = buckets[element - detectedSmallestElement];
// Put element into correct position in sorted array. // Put element into correct position in sorted array.
sortedArray[elementSortedPosition] = element; sortedArray[elementSortedPosition] = element;
// Increase position of current element in the bucket for future correct placements. // Increase position of current element in the bucket for future correct placements.
buckets[element] += 1; buckets[element - detectedSmallestElement] += 1;
} }
// Return sorted array. // Return sorted array.

View File

@ -18,6 +18,10 @@ describe('CountingSort', () => {
SortTester.testSort(CountingSort); SortTester.testSort(CountingSort);
}); });
it('should sort negative numbers', () => {
SortTester.testNegativeNumbersSort(CountingSort);
});
it('should allow to use specify maximum integer value in array to make sorting faster', () => { it('should allow to use specify maximum integer value in array to make sorting faster', () => {
const visitingCallback = jest.fn(); const visitingCallback = jest.fn();
const sorter = new CountingSort({ visitingCallback }); const sorter = new CountingSort({ visitingCallback });
@ -27,7 +31,7 @@ describe('CountingSort', () => {
return element > accumulator ? element : accumulator; return element > accumulator ? element : accumulator;
}, 0); }, 0);
const sortedArray = sorter.sort(notSortedArr, biggestElement); const sortedArray = sorter.sort(notSortedArr, 0, biggestElement);
expect(sortedArray).toEqual(sortedArr); expect(sortedArray).toEqual(sortedArr);
// Normally visitingCallback is being called 60 times but in this case // Normally visitingCallback is being called 60 times but in this case