mirror of
https://github.moeyy.xyz/https://github.com/trekhleb/javascript-algorithms.git
synced 2024-09-20 15:53:02 +08:00
Add heap sort.
This commit is contained in:
parent
053b365f24
commit
36bbfed6a1
@ -34,6 +34,7 @@
|
|||||||
* [Bubble Sort](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sorting/bubble-sort)
|
* [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)
|
* [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)
|
* [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
|
## Running Tests
|
||||||
|
|
||||||
|
@ -7,6 +7,12 @@ import {
|
|||||||
SortTester,
|
SortTester,
|
||||||
} from '../../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', () => {
|
describe('BubbleSort', () => {
|
||||||
it('should sort array', () => {
|
it('should sort array', () => {
|
||||||
SortTester.testSort(BubbleSort);
|
SortTester.testSort(BubbleSort);
|
||||||
@ -21,42 +27,34 @@ describe('BubbleSort', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should visit EQUAL array element specified number of times', () => {
|
it('should visit EQUAL array element specified number of times', () => {
|
||||||
const expectedNumberOfVisits = 20;
|
|
||||||
|
|
||||||
SortTester.testAlgorithmTimeComplexity(
|
SortTester.testAlgorithmTimeComplexity(
|
||||||
BubbleSort,
|
BubbleSort,
|
||||||
equalArr,
|
equalArr,
|
||||||
expectedNumberOfVisits,
|
EQUAL_ARRAY_VISITING_COUNT,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should visit SORTED array element specified number of times', () => {
|
it('should visit SORTED array element specified number of times', () => {
|
||||||
const expectedNumberOfVisits = 20;
|
|
||||||
|
|
||||||
SortTester.testAlgorithmTimeComplexity(
|
SortTester.testAlgorithmTimeComplexity(
|
||||||
BubbleSort,
|
BubbleSort,
|
||||||
sortedArr,
|
sortedArr,
|
||||||
expectedNumberOfVisits,
|
SORTED_ARRAY_VISITING_COUNT,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should visit NOT SORTED array element specified number of times', () => {
|
it('should visit NOT SORTED array element specified number of times', () => {
|
||||||
const expectedNumberOfVisits = 280;
|
|
||||||
|
|
||||||
SortTester.testAlgorithmTimeComplexity(
|
SortTester.testAlgorithmTimeComplexity(
|
||||||
BubbleSort,
|
BubbleSort,
|
||||||
notSortedArr,
|
notSortedArr,
|
||||||
expectedNumberOfVisits,
|
NOT_SORTED_ARRAY_VISITING_COUNT,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should visit REVERSE SORTED array element specified number of times', () => {
|
it('should visit REVERSE SORTED array element specified number of times', () => {
|
||||||
const expectedNumberOfVisits = 400;
|
|
||||||
|
|
||||||
SortTester.testAlgorithmTimeComplexity(
|
SortTester.testAlgorithmTimeComplexity(
|
||||||
BubbleSort,
|
BubbleSort,
|
||||||
reverseArr,
|
reverseArr,
|
||||||
expectedNumberOfVisits,
|
REVERSE_SORTED_ARRAY_VISITING_COUNT,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
30
src/algorithms/sorting/heap-sort/HeapSort.js
Normal file
30
src/algorithms/sorting/heap-sort/HeapSort.js
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
18
src/algorithms/sorting/heap-sort/README.md
Normal file
18
src/algorithms/sorting/heap-sort/README.md
Normal 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)
|
56
src/algorithms/sorting/heap-sort/__test__/HeapSort.test.js
Normal file
56
src/algorithms/sorting/heap-sort/__test__/HeapSort.test.js
Normal 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,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
@ -7,6 +7,12 @@ import {
|
|||||||
SortTester,
|
SortTester,
|
||||||
} from '../../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', () => {
|
describe('InsertionSort', () => {
|
||||||
it('should sort array', () => {
|
it('should sort array', () => {
|
||||||
SortTester.testSort(InsertionSort);
|
SortTester.testSort(InsertionSort);
|
||||||
@ -21,42 +27,34 @@ describe('InsertionSort', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should visit EQUAL array element specified number of times', () => {
|
it('should visit EQUAL array element specified number of times', () => {
|
||||||
const expectedNumberOfVisits = 20;
|
|
||||||
|
|
||||||
SortTester.testAlgorithmTimeComplexity(
|
SortTester.testAlgorithmTimeComplexity(
|
||||||
InsertionSort,
|
InsertionSort,
|
||||||
equalArr,
|
equalArr,
|
||||||
expectedNumberOfVisits,
|
EQUAL_ARRAY_VISITING_COUNT,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should visit SORTED array element specified number of times', () => {
|
it('should visit SORTED array element specified number of times', () => {
|
||||||
const expectedNumberOfVisits = 20;
|
|
||||||
|
|
||||||
SortTester.testAlgorithmTimeComplexity(
|
SortTester.testAlgorithmTimeComplexity(
|
||||||
InsertionSort,
|
InsertionSort,
|
||||||
sortedArr,
|
sortedArr,
|
||||||
expectedNumberOfVisits,
|
SORTED_ARRAY_VISITING_COUNT,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should visit NOT SORTED array element specified number of times', () => {
|
it('should visit NOT SORTED array element specified number of times', () => {
|
||||||
const expectedNumberOfVisits = 101;
|
|
||||||
|
|
||||||
SortTester.testAlgorithmTimeComplexity(
|
SortTester.testAlgorithmTimeComplexity(
|
||||||
InsertionSort,
|
InsertionSort,
|
||||||
notSortedArr,
|
notSortedArr,
|
||||||
expectedNumberOfVisits,
|
NOT_SORTED_ARRAY_VISITING_COUNT,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should visit REVERSE SORTED array element specified number of times', () => {
|
it('should visit REVERSE SORTED array element specified number of times', () => {
|
||||||
const expectedNumberOfVisits = 210;
|
|
||||||
|
|
||||||
SortTester.testAlgorithmTimeComplexity(
|
SortTester.testAlgorithmTimeComplexity(
|
||||||
InsertionSort,
|
InsertionSort,
|
||||||
reverseArr,
|
reverseArr,
|
||||||
expectedNumberOfVisits,
|
REVERSE_SORTED_ARRAY_VISITING_COUNT,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -7,6 +7,12 @@ import {
|
|||||||
SortTester,
|
SortTester,
|
||||||
} from '../../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', () => {
|
describe('SelectionSort', () => {
|
||||||
it('should sort array', () => {
|
it('should sort array', () => {
|
||||||
SortTester.testSort(SelectionSort);
|
SortTester.testSort(SelectionSort);
|
||||||
@ -17,42 +23,34 @@ describe('SelectionSort', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should visit EQUAL array element specified number of times', () => {
|
it('should visit EQUAL array element specified number of times', () => {
|
||||||
const expectedNumberOfVisits = 209;
|
|
||||||
|
|
||||||
SortTester.testAlgorithmTimeComplexity(
|
SortTester.testAlgorithmTimeComplexity(
|
||||||
SelectionSort,
|
SelectionSort,
|
||||||
equalArr,
|
equalArr,
|
||||||
expectedNumberOfVisits,
|
EQUAL_ARRAY_VISITING_COUNT,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should visit SORTED array element specified number of times', () => {
|
it('should visit SORTED array element specified number of times', () => {
|
||||||
const expectedNumberOfVisits = 209;
|
|
||||||
|
|
||||||
SortTester.testAlgorithmTimeComplexity(
|
SortTester.testAlgorithmTimeComplexity(
|
||||||
SelectionSort,
|
SelectionSort,
|
||||||
sortedArr,
|
sortedArr,
|
||||||
expectedNumberOfVisits,
|
SORTED_ARRAY_VISITING_COUNT,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should visit NOT SORTED array element specified number of times', () => {
|
it('should visit NOT SORTED array element specified number of times', () => {
|
||||||
const expectedNumberOfVisits = 209;
|
|
||||||
|
|
||||||
SortTester.testAlgorithmTimeComplexity(
|
SortTester.testAlgorithmTimeComplexity(
|
||||||
SelectionSort,
|
SelectionSort,
|
||||||
notSortedArr,
|
notSortedArr,
|
||||||
expectedNumberOfVisits,
|
NOT_SORTED_ARRAY_VISITING_COUNT,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should visit REVERSE SORTED array element specified number of times', () => {
|
it('should visit REVERSE SORTED array element specified number of times', () => {
|
||||||
const expectedNumberOfVisits = 209;
|
|
||||||
|
|
||||||
SortTester.testAlgorithmTimeComplexity(
|
SortTester.testAlgorithmTimeComplexity(
|
||||||
SelectionSort,
|
SelectionSort,
|
||||||
reverseArr,
|
reverseArr,
|
||||||
expectedNumberOfVisits,
|
REVERSE_SORTED_ARRAY_VISITING_COUNT,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import Comparator from '../../utils/comparator/Comparator';
|
import Comparator from '../../utils/comparator/Comparator';
|
||||||
|
|
||||||
export default class MinHeap {
|
export default class MinHeap {
|
||||||
constructor() {
|
constructor(comparatorFunction) {
|
||||||
// Array representation of the heap.
|
// Array representation of the heap.
|
||||||
this.heapContainer = [];
|
this.heapContainer = [];
|
||||||
this.compare = new Comparator();
|
this.compare = new Comparator(comparatorFunction);
|
||||||
}
|
}
|
||||||
|
|
||||||
static getLeftChildIndex(parentIndex) {
|
static getLeftChildIndex(parentIndex) {
|
||||||
@ -120,6 +120,10 @@ export default class MinHeap {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isEmpty() {
|
||||||
|
return !this.heapContainer.length;
|
||||||
|
}
|
||||||
|
|
||||||
toString() {
|
toString() {
|
||||||
return this.heapContainer.toString();
|
return this.heapContainer.toString();
|
||||||
}
|
}
|
||||||
|
@ -6,12 +6,14 @@ describe('MinHeap', () => {
|
|||||||
|
|
||||||
expect(minHeap).toBeDefined();
|
expect(minHeap).toBeDefined();
|
||||||
expect(minHeap.peek()).toBeNull();
|
expect(minHeap.peek()).toBeNull();
|
||||||
|
expect(minHeap.isEmpty()).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should add items to the heap and heapify it up', () => {
|
it('should add items to the heap and heapify it up', () => {
|
||||||
const minHeap = new MinHeap();
|
const minHeap = new MinHeap();
|
||||||
|
|
||||||
minHeap.add(5);
|
minHeap.add(5);
|
||||||
|
expect(minHeap.isEmpty()).toBeFalsy();
|
||||||
expect(minHeap.peek()).toBe(5);
|
expect(minHeap.peek()).toBe(5);
|
||||||
expect(minHeap.toString()).toBe('5');
|
expect(minHeap.toString()).toBe('5');
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user