mirror of
https://github.moeyy.xyz/https://github.com/trekhleb/javascript-algorithms.git
synced 2024-11-10 11:09:43 +08:00
Add BubbleSort.
This commit is contained in:
parent
852093265e
commit
0224afbc42
@ -30,6 +30,8 @@
|
||||
* Graph
|
||||
* [Depth-First Search (DFS)](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/graph/depth-first-search)
|
||||
* [Breadth-First Search (BFS)](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/graph/breadth-first-search)
|
||||
* Sorting
|
||||
* [Bubble Sort](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sorting/bubble-sort)
|
||||
|
||||
## Running Tests
|
||||
|
||||
|
34
src/algorithms/sorting/Sort.js
Normal file
34
src/algorithms/sorting/Sort.js
Normal file
@ -0,0 +1,34 @@
|
||||
import Comparator from '../../utils/comparator/Comparator';
|
||||
|
||||
/**
|
||||
* @typedef {Object} SorterCallbacks
|
||||
* @property {function(a: *, b: *)} compareCallback - If provided then all elements comparisons
|
||||
* will be done through this callback.
|
||||
* @property {function(a: *)} visitingCallback - If provided it will be called each time the sorting
|
||||
* function is visiting the next element.
|
||||
*/
|
||||
|
||||
export default class Sort {
|
||||
constructor(rawCallbacks) {
|
||||
this.callbacks = Sort.initSortingCallbacks(rawCallbacks);
|
||||
this.comparator = new Comparator(this.callbacks.compareCallback);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {SorterCallbacks} rawCallbacks
|
||||
* @returns {SorterCallbacks}
|
||||
*/
|
||||
static initSortingCallbacks(rawCallbacks) {
|
||||
const callbacks = rawCallbacks || {};
|
||||
const stubCallback = () => {};
|
||||
|
||||
callbacks.compareCallback = callbacks.compareCallback || undefined;
|
||||
callbacks.visitingCallback = callbacks.visitingCallback || stubCallback;
|
||||
|
||||
return callbacks;
|
||||
}
|
||||
|
||||
sort() {
|
||||
throw new Error('sort method must be implemented');
|
||||
}
|
||||
}
|
37
src/algorithms/sorting/SortTester.js
Normal file
37
src/algorithms/sorting/SortTester.js
Normal file
@ -0,0 +1,37 @@
|
||||
export const sortedArray = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
|
||||
export const notSortedArray = [10, 5, 30, -1, 0, 0, 1, 2, -3, 2];
|
||||
export const equalArray = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1];
|
||||
|
||||
export class SortTester {
|
||||
static testSort(SortingClass) {
|
||||
const sorter = new SortingClass();
|
||||
|
||||
expect(sorter.sort([])).toEqual([]);
|
||||
expect(sorter.sort([1])).toEqual([1]);
|
||||
expect(sorter.sort([1, 2])).toEqual([1, 2]);
|
||||
expect(sorter.sort([2, 1])).toEqual([1, 2]);
|
||||
expect(sorter.sort([1, 1, 1])).toEqual([1, 1, 1]);
|
||||
expect(sorter.sort(sortedArray)).toEqual([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
|
||||
expect(sorter.sort(notSortedArray)).toEqual([-3, -1, 0, 0, 1, 2, 2, 5, 10, 30]);
|
||||
expect(sorter.sort(equalArray)).toEqual([1, 1, 1, 1, 1, 1, 1, 1, 1, 1]);
|
||||
}
|
||||
|
||||
static testSortWithCustomComparator(SortingClass) {
|
||||
const callbacks = {
|
||||
compareCallback: (a, b) => {
|
||||
if (a.length === b.length) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return a.length < b.length ? -1 : 1;
|
||||
},
|
||||
};
|
||||
|
||||
const sorter = new SortingClass(callbacks);
|
||||
|
||||
expect(sorter.sort([''])).toEqual(['']);
|
||||
expect(sorter.sort(['a'])).toEqual(['a']);
|
||||
expect(sorter.sort(['aa', 'a'])).toEqual(['a', 'aa']);
|
||||
expect(sorter.sort(['bb', 'aa', 'c'])).toEqual(['c', 'bb', 'aa']);
|
||||
}
|
||||
}
|
12
src/algorithms/sorting/__test__/Sort.test.js
Normal file
12
src/algorithms/sorting/__test__/Sort.test.js
Normal file
@ -0,0 +1,12 @@
|
||||
import Sort from '../Sort';
|
||||
|
||||
describe('Sort', () => {
|
||||
it('should throw an error when trying to call Sort.sort() method directly', () => {
|
||||
function doForbiddenSort() {
|
||||
const sorter = new Sort();
|
||||
sorter.sort();
|
||||
}
|
||||
|
||||
expect(doForbiddenSort).toThrow();
|
||||
});
|
||||
});
|
23
src/algorithms/sorting/bubble-sort/BubbleSort.js
Normal file
23
src/algorithms/sorting/bubble-sort/BubbleSort.js
Normal file
@ -0,0 +1,23 @@
|
||||
import Sort from '../Sort';
|
||||
|
||||
export default class BubbleSort extends Sort {
|
||||
sort(initialArray) {
|
||||
const array = initialArray;
|
||||
|
||||
for (let i = 0; i < array.length; i += 1) {
|
||||
for (let j = 0; j < array.length - 1; j += 1) {
|
||||
// Call visiting callback.
|
||||
this.callbacks.visitingCallback(array[j]);
|
||||
|
||||
// Swap elements if they are in wrong order.
|
||||
if (this.comparator.lessThen(array[j + 1], array[j])) {
|
||||
const tmp = array[j + 1];
|
||||
array[j + 1] = array[j];
|
||||
array[j] = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
}
|
8
src/algorithms/sorting/bubble-sort/README.md
Normal file
8
src/algorithms/sorting/bubble-sort/README.md
Normal file
@ -0,0 +1,8 @@
|
||||
# Bubble Sort
|
||||
|
||||
Bubble sort, sometimes referred to as sinking sort, is a
|
||||
simple sorting algorithm that repeatedly steps through
|
||||
the list to be sorted, compares each pair of adjacent
|
||||
items and swaps them if they are in the wrong order.
|
||||
The pass through the list is repeated until no swaps
|
||||
are needed, which indicates that the list is sorted.
|
@ -0,0 +1,45 @@
|
||||
import BubbleSort from '../BubbleSort';
|
||||
import { equalArray, notSortedArray, sortedArray, SortTester } from '../../SortTester';
|
||||
|
||||
describe('bubbleSort', () => {
|
||||
it('should sort array', () => {
|
||||
SortTester.testSort(BubbleSort);
|
||||
});
|
||||
|
||||
it('should sort array with custom comparator', () => {
|
||||
SortTester.testSortWithCustomComparator(BubbleSort);
|
||||
});
|
||||
|
||||
it('should visit sorted array element specified number of times', () => {
|
||||
const visitingCallback = jest.fn();
|
||||
|
||||
const callbacks = { visitingCallback };
|
||||
const sorter = new BubbleSort(callbacks);
|
||||
|
||||
sorter.sort(sortedArray);
|
||||
|
||||
expect(visitingCallback).toHaveBeenCalledTimes(90);
|
||||
});
|
||||
|
||||
it('should visit not-sorted array element specified number of times', () => {
|
||||
const visitingCallback = jest.fn();
|
||||
|
||||
const callbacks = { visitingCallback };
|
||||
const sorter = new BubbleSort(callbacks);
|
||||
|
||||
sorter.sort(notSortedArray);
|
||||
|
||||
expect(visitingCallback).toHaveBeenCalledTimes(90);
|
||||
});
|
||||
|
||||
it('should visit equal array element specified number of times', () => {
|
||||
const visitingCallback = jest.fn();
|
||||
|
||||
const callbacks = { visitingCallback };
|
||||
const sorter = new BubbleSort(callbacks);
|
||||
|
||||
sorter.sort(equalArray);
|
||||
|
||||
expect(visitingCallback).toHaveBeenCalledTimes(90);
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue
Block a user