Add heap sort.

This commit is contained in:
Oleksii Trekhleb 2018-04-14 10:29:36 +03:00
parent 053b365f24
commit 36bbfed6a1
9 changed files with 143 additions and 38 deletions

View File

@ -34,6 +34,7 @@
* [Bubble Sort](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sorting/bubble-sort)
* [Selection Sort](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sorting/selection-sort)
* [Insertion Sort](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sorting/insertion-sort)
* [Heap Sort](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sorting/heap-sort)
## Running Tests

View File

@ -7,6 +7,12 @@ import {
SortTester,
} from '../../SortTester';
// Complexity constants.
const SORTED_ARRAY_VISITING_COUNT = 20;
const NOT_SORTED_ARRAY_VISITING_COUNT = 280;
const REVERSE_SORTED_ARRAY_VISITING_COUNT = 400;
const EQUAL_ARRAY_VISITING_COUNT = 20;
describe('BubbleSort', () => {
it('should sort array', () => {
SortTester.testSort(BubbleSort);
@ -21,42 +27,34 @@ describe('BubbleSort', () => {
});
it('should visit EQUAL array element specified number of times', () => {
const expectedNumberOfVisits = 20;
SortTester.testAlgorithmTimeComplexity(
BubbleSort,
equalArr,
expectedNumberOfVisits,
EQUAL_ARRAY_VISITING_COUNT,
);
});
it('should visit SORTED array element specified number of times', () => {
const expectedNumberOfVisits = 20;
SortTester.testAlgorithmTimeComplexity(
BubbleSort,
sortedArr,
expectedNumberOfVisits,
SORTED_ARRAY_VISITING_COUNT,
);
});
it('should visit NOT SORTED array element specified number of times', () => {
const expectedNumberOfVisits = 280;
SortTester.testAlgorithmTimeComplexity(
BubbleSort,
notSortedArr,
expectedNumberOfVisits,
NOT_SORTED_ARRAY_VISITING_COUNT,
);
});
it('should visit REVERSE SORTED array element specified number of times', () => {
const expectedNumberOfVisits = 400;
SortTester.testAlgorithmTimeComplexity(
BubbleSort,
reverseArr,
expectedNumberOfVisits,
REVERSE_SORTED_ARRAY_VISITING_COUNT,
);
});
});

View File

@ -0,0 +1,30 @@
import Sort from '../Sort';
import MinHeap from '../../../data-structures/heap/MinHeap';
export default class HeapSort extends Sort {
sort(originalArray) {
const sortedArray = [];
const minHeap = new MinHeap(this.callbacks.compareCallback);
// Insert all array elements to the heap.
originalArray.forEach((element) => {
// Call visiting callback.
this.callbacks.visitingCallback(element);
minHeap.add(element);
});
// Now we have min heap with minimal element always on top.
// Let's poll that minimal element one by one and thus form the sorted array.
while (!minHeap.isEmpty()) {
const nextMinElement = minHeap.poll();
// Call visiting callback.
this.callbacks.visitingCallback(nextMinElement);
sortedArray.push(nextMinElement);
}
return sortedArray;
}
}

View File

@ -0,0 +1,18 @@
# Heap Sort
Heapsort is a comparison-based sorting algorithm.
Heapsort can be thought of as an improved selection
sort: like that algorithm, it divides its input into
a sorted and an unsorted region, and it iteratively
shrinks the unsorted region by extracting the largest
element and moving that to the sorted region. The
improvement consists of the use of a heap data structure
rather than a linear-time search to find the maximum.
![Algorithm Visualization](https://upload.wikimedia.org/wikipedia/commons/1/1b/Sorting_heapsort_anim.gif)
![Algorithm Visualization](https://upload.wikimedia.org/wikipedia/commons/4/4d/Heapsort-example.gif)
## References
[Wikipedia](https://en.wikipedia.org/wiki/Heapsort)

View File

@ -0,0 +1,56 @@
import HeapSort from '../HeapSort';
import {
equalArr,
notSortedArr,
reverseArr,
sortedArr,
SortTester,
} from '../../SortTester';
// Complexity constants.
const SORTED_ARRAY_VISITING_COUNT = 40;
const NOT_SORTED_ARRAY_VISITING_COUNT = 40;
const REVERSE_SORTED_ARRAY_VISITING_COUNT = 40;
const EQUAL_ARRAY_VISITING_COUNT = 40;
describe('HeapSort', () => {
it('should sort array', () => {
SortTester.testSort(HeapSort);
});
it('should sort array with custom comparator', () => {
SortTester.testSortWithCustomComparator(HeapSort);
});
it('should visit EQUAL array element specified number of times', () => {
SortTester.testAlgorithmTimeComplexity(
HeapSort,
equalArr,
EQUAL_ARRAY_VISITING_COUNT,
);
});
it('should visit SORTED array element specified number of times', () => {
SortTester.testAlgorithmTimeComplexity(
HeapSort,
sortedArr,
SORTED_ARRAY_VISITING_COUNT,
);
});
it('should visit NOT SORTED array element specified number of times', () => {
SortTester.testAlgorithmTimeComplexity(
HeapSort,
notSortedArr,
NOT_SORTED_ARRAY_VISITING_COUNT,
);
});
it('should visit REVERSE SORTED array element specified number of times', () => {
SortTester.testAlgorithmTimeComplexity(
HeapSort,
reverseArr,
REVERSE_SORTED_ARRAY_VISITING_COUNT,
);
});
});

View File

@ -7,6 +7,12 @@ import {
SortTester,
} from '../../SortTester';
// Complexity constants.
const SORTED_ARRAY_VISITING_COUNT = 20;
const NOT_SORTED_ARRAY_VISITING_COUNT = 101;
const REVERSE_SORTED_ARRAY_VISITING_COUNT = 210;
const EQUAL_ARRAY_VISITING_COUNT = 20;
describe('InsertionSort', () => {
it('should sort array', () => {
SortTester.testSort(InsertionSort);
@ -21,42 +27,34 @@ describe('InsertionSort', () => {
});
it('should visit EQUAL array element specified number of times', () => {
const expectedNumberOfVisits = 20;
SortTester.testAlgorithmTimeComplexity(
InsertionSort,
equalArr,
expectedNumberOfVisits,
EQUAL_ARRAY_VISITING_COUNT,
);
});
it('should visit SORTED array element specified number of times', () => {
const expectedNumberOfVisits = 20;
SortTester.testAlgorithmTimeComplexity(
InsertionSort,
sortedArr,
expectedNumberOfVisits,
SORTED_ARRAY_VISITING_COUNT,
);
});
it('should visit NOT SORTED array element specified number of times', () => {
const expectedNumberOfVisits = 101;
SortTester.testAlgorithmTimeComplexity(
InsertionSort,
notSortedArr,
expectedNumberOfVisits,
NOT_SORTED_ARRAY_VISITING_COUNT,
);
});
it('should visit REVERSE SORTED array element specified number of times', () => {
const expectedNumberOfVisits = 210;
SortTester.testAlgorithmTimeComplexity(
InsertionSort,
reverseArr,
expectedNumberOfVisits,
REVERSE_SORTED_ARRAY_VISITING_COUNT,
);
});
});

View File

@ -7,6 +7,12 @@ import {
SortTester,
} from '../../SortTester';
// Complexity constants.
const SORTED_ARRAY_VISITING_COUNT = 209;
const NOT_SORTED_ARRAY_VISITING_COUNT = 209;
const REVERSE_SORTED_ARRAY_VISITING_COUNT = 209;
const EQUAL_ARRAY_VISITING_COUNT = 209;
describe('SelectionSort', () => {
it('should sort array', () => {
SortTester.testSort(SelectionSort);
@ -17,42 +23,34 @@ describe('SelectionSort', () => {
});
it('should visit EQUAL array element specified number of times', () => {
const expectedNumberOfVisits = 209;
SortTester.testAlgorithmTimeComplexity(
SelectionSort,
equalArr,
expectedNumberOfVisits,
EQUAL_ARRAY_VISITING_COUNT,
);
});
it('should visit SORTED array element specified number of times', () => {
const expectedNumberOfVisits = 209;
SortTester.testAlgorithmTimeComplexity(
SelectionSort,
sortedArr,
expectedNumberOfVisits,
SORTED_ARRAY_VISITING_COUNT,
);
});
it('should visit NOT SORTED array element specified number of times', () => {
const expectedNumberOfVisits = 209;
SortTester.testAlgorithmTimeComplexity(
SelectionSort,
notSortedArr,
expectedNumberOfVisits,
NOT_SORTED_ARRAY_VISITING_COUNT,
);
});
it('should visit REVERSE SORTED array element specified number of times', () => {
const expectedNumberOfVisits = 209;
SortTester.testAlgorithmTimeComplexity(
SelectionSort,
reverseArr,
expectedNumberOfVisits,
REVERSE_SORTED_ARRAY_VISITING_COUNT,
);
});
});

View File

@ -1,10 +1,10 @@
import Comparator from '../../utils/comparator/Comparator';
export default class MinHeap {
constructor() {
constructor(comparatorFunction) {
// Array representation of the heap.
this.heapContainer = [];
this.compare = new Comparator();
this.compare = new Comparator(comparatorFunction);
}
static getLeftChildIndex(parentIndex) {
@ -120,6 +120,10 @@ export default class MinHeap {
}
}
isEmpty() {
return !this.heapContainer.length;
}
toString() {
return this.heapContainer.toString();
}

View File

@ -6,12 +6,14 @@ describe('MinHeap', () => {
expect(minHeap).toBeDefined();
expect(minHeap.peek()).toBeNull();
expect(minHeap.isEmpty()).toBeTruthy();
});
it('should add items to the heap and heapify it up', () => {
const minHeap = new MinHeap();
minHeap.add(5);
expect(minHeap.isEmpty()).toBeFalsy();
expect(minHeap.peek()).toBe(5);
expect(minHeap.toString()).toBe('5');