Skip to content

Commit 028d666

Browse files
author
Isaac Ramirez
committed
- implement Insertion Sort algorithm
1 parent d77f6e2 commit 028d666

File tree

5 files changed

+274
-2
lines changed

5 files changed

+274
-2
lines changed

README.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,8 @@ _For a list similar to the book site see this [algorithms list](/docs/algorithms
6161

6262
**Algorithms:**
6363

64-
* [Selection Sort - p.249](/src/algorithms/selection-sort/selection-sort.js)
64+
* [Selection Sort - p. 249](/src/algorithms/selection-sort/selection-sort.js)
65+
* [Insertion Sort - p. 251](/src/algorithms/insertion-sort/insertion-sort.js)
6566

6667
**ADTs:**
6768

docs/algorithms-list.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ Every algorithm or ADT has a link pointing to the original Java implementation a
4747

4848
### Chapter 2. Sorting
4949

50-
* Insertion | js | java |
50+
* Insertion | [js](/src/algorithms/insertion-sort/insertion-sort.js) | [java](https://algs4.cs.princeton.edu/code/edu/princeton/cs/algs4/Insertion.java.html) |
5151
* InsertionX | js | java |
5252
* BinaryInsertion | js | java |
5353
* Selection | [js](/src/algorithms/selection-sort/selection-sort.js) | [java](https://algs4.cs.princeton.edu/code/edu/princeton/cs/algs4/Selection.java.html) |
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
const { StdIn } = require('../../libs')
2+
const Insertion = require('./insertion-sort')
3+
4+
/**
5+
* InsertionSortClient
6+
* @classdesc Insertion Sort Test Client.
7+
* @see p. 245, 251
8+
*/
9+
class InsertionSortClient {
10+
/**
11+
* Runs the Insertion Sort Algorithm
12+
* with the input provided.
13+
* @example <caption>Tiny Example</caption>
14+
* ```sh
15+
* $ node insertion-sort.client.js < ~/algs4-data/tiny.txt
16+
* A E E L M O P R S T X
17+
* ```
18+
* @example <caption>Words3 Example</caption>
19+
* ```sh
20+
* $ node insertion-sort.client.js < ~/algs4-data/words3.txt
21+
* all bad bed bug dad ... yes yet zoo
22+
* ```
23+
*/
24+
static main () {
25+
let array = []
26+
27+
// read all strings from standard input.
28+
StdIn.read()
29+
.on('line', line => {
30+
array = array.concat(line.split(' '))
31+
})
32+
.on('close', () => {
33+
Insertion.sort(array)
34+
35+
if (!Insertion.isSorted(array)) {
36+
throw new Error('array is NOT sorted')
37+
}
38+
39+
Insertion.show(array)
40+
})
41+
}
42+
}
43+
44+
// Execution
45+
// ==============================
46+
InsertionSortClient.main()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
const { StdOut } = require('../../libs')
2+
const { defaultComparator } = require('../../common')
3+
4+
/**
5+
* Insertion
6+
* @classdesc Insertion Sort Algorithm.
7+
* @see p. 245, 251
8+
* @see {@link https://algs4.cs.princeton.edu/code/edu/princeton/cs/algs4/Insertion.java.html}
9+
*/
10+
class Insertion {
11+
/**
12+
* Returns whether `a` is less than `b`
13+
* based on a comparing function.
14+
* @param {*} a Comparable object `a`
15+
* @param {*} b Comparable object `b`
16+
* @param {function} comparator A comparing function that
17+
* returns -1 when `a` is less than `b`,
18+
* returns 1 when `a` is greater than `b` or
19+
* returns 0 when `a` is equal to `b`.
20+
*/
21+
static less (a, b, comparator = defaultComparator) {
22+
return comparator(a, b) < 0
23+
}
24+
25+
/**
26+
* Interchanges the values located in indexes `i` and `j`
27+
* for the given `array`.
28+
* @param {[*]} array Array of values.
29+
* @param {number} i Index 1
30+
* @param {number} j Index 2
31+
*/
32+
static exchange (array, i, j) {
33+
const temp = array[i]
34+
35+
array[i] = array[j]
36+
array[j] = temp
37+
}
38+
39+
/**
40+
* Returns `true` if the provided array is sorted,
41+
* `false` otherwise.
42+
* @param {[*]} array Array of values
43+
* @param {function} comparator A comparing function that
44+
* returns -1 when `a` is less than `b`,
45+
* returns 1 when `a` is greater than `b` or
46+
* returns 0 when `a` is equal to `b`.
47+
*/
48+
static isSorted (array, comparator = defaultComparator) {
49+
for (let i = 1; i < array.length; i++) {
50+
if (this.less(array[i], array[i - 1], comparator)) {
51+
return false
52+
}
53+
}
54+
55+
return true
56+
}
57+
58+
/**
59+
* A function that prints to the StdOut
60+
* the contents of the `array` provided.
61+
* @param {[*]} array Array of values.
62+
*/
63+
static show (array) {
64+
StdOut.println(array.join(' '))
65+
}
66+
67+
/**
68+
* Sorts the `array` using the Insertion Sort algorithm.
69+
* @param {[*]} array Array of values.
70+
* @param {*} comparator A comparing function that
71+
* returns -1 when `a` is less than `b`,
72+
* returns 1 when `a` is greater than `b` or
73+
* returns 0 when `a` is equal to `b`.
74+
*/
75+
static sort (array, comparator = defaultComparator) {
76+
const n = array.length
77+
78+
for (let i = 1; i < n; i++) {
79+
for (let j = i; j > 0 && this.less(array[j], array[j - 1], comparator); j--) {
80+
this.exchange(array, j, j - 1)
81+
}
82+
}
83+
}
84+
}
85+
86+
module.exports = Insertion
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
const Insertion = require('./insertion-sort')
2+
const { newArrayOf } = require('../../utils')
3+
const { StdRandom } = require('../../libs')
4+
const { defaultComparator: comparator } = require('../../common')
5+
6+
describe('Unit Tests: Insertion Sort Algorithm', () => {
7+
beforeEach(() => {
8+
this.orderedArray = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
9+
this.reversedArray = [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
10+
this.unorderedArray = [0, 9, 5, 2, 1, 8, 7, 6, 4, 3]
11+
this.allEqualArray = [9, 9, 9, 9, 9, 9, 9, 9, 9, 9]
12+
})
13+
14+
describe('static less method', () => {
15+
it('should return true if a is less than b', () => {
16+
const a = 1
17+
const b = 2
18+
19+
expect(Insertion.less(a, b, comparator)).toBe(true)
20+
})
21+
22+
it('should return false if a is greater than b', () => {
23+
const a = 2
24+
const b = 1
25+
26+
expect(Insertion.less(a, b, comparator)).toBe(false)
27+
})
28+
29+
it('should return false if a is equal to b', () => {
30+
const a = 1
31+
const b = 1
32+
33+
expect(Insertion.less(a, b, comparator)).toBe(false)
34+
})
35+
36+
it('should have a defaultComparator function', () => {
37+
expect(Insertion.less(1, 10)).toBe(true)
38+
expect(Insertion.less(1, 1)).toBe(false)
39+
expect(Insertion.less(10, 1)).toBe(false)
40+
})
41+
})
42+
43+
describe('static exchange method', () => {
44+
it('should interchange the values of the two given indexes in the array', () => {
45+
const array = [5, 6, 7]
46+
const expectedArray = [7, 6, 5]
47+
48+
Insertion.exchange(array, 0, 2)
49+
50+
expect(array).toEqual(expectedArray)
51+
})
52+
})
53+
54+
describe('static isSorted method', () => {
55+
it('should return true if an array is sorted', () => {
56+
expect(Insertion.isSorted(this.orderedArray)).toBe(true)
57+
expect(Insertion.isSorted(this.allEqualArray)).toBe(true)
58+
})
59+
60+
it('should return false if the array is not sorted', () => {
61+
expect(Insertion.isSorted(this.unorderedArray)).toBe(false)
62+
expect(Insertion.isSorted(this.reversedArray)).toBe(false)
63+
})
64+
65+
it('should accept a comparator function', () => {
66+
const orderedArray = ['A', 'B', 'C']
67+
const unorderedArray = ['Z', 'X', 'Y']
68+
69+
expect(Insertion.isSorted(orderedArray, comparator)).toBe(true)
70+
expect(Insertion.isSorted(unorderedArray, comparator)).toBe(false)
71+
})
72+
73+
it('should return true for a sorted big array', () => {
74+
const n = 1000000 // a million!
75+
const array = newArrayOf(n, i => i) // from 0 to 999999
76+
77+
expect(Insertion.isSorted(array)).toBeTrue()
78+
})
79+
80+
it('should return false for a random big array', () => {
81+
const n = 1000000 // a million!
82+
const array = newArrayOf(n, i => i) // from 0 to 999999
83+
array[array.length - 1] = 0 // change last number to be 0
84+
85+
expect(Insertion.isSorted(array)).toBeFalse()
86+
})
87+
})
88+
89+
describe('static show method', () => {
90+
it('should be a function', () => {
91+
// I could test the call to StdOut, but I don't want to.
92+
expect(Insertion.show).toBeInstanceOf(Function)
93+
})
94+
})
95+
96+
describe('static sort method', () => {
97+
it('should sort a unordered array', () => {
98+
const expectedArray = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
99+
100+
Insertion.sort(this.unorderedArray)
101+
102+
expect(this.unorderedArray).toEqual(expectedArray)
103+
})
104+
105+
it('should sort an ordered array', () => {
106+
const expectedArray = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
107+
108+
Insertion.sort(this.orderedArray)
109+
110+
expect(this.orderedArray).toEqual(expectedArray)
111+
})
112+
113+
it('should sort a reversed array', () => {
114+
const expectedArray = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
115+
116+
Insertion.sort(this.reversedArray)
117+
118+
expect(this.reversedArray).toEqual(expectedArray)
119+
})
120+
121+
it('should sort an array with all the values to be equal', () => {
122+
const expectedArray = [9, 9, 9, 9, 9, 9, 9, 9, 9, 9]
123+
124+
Insertion.sort(this.allEqualArray)
125+
126+
expect(this.allEqualArray).toEqual(expectedArray)
127+
})
128+
129+
it('should sort a small random array', () => {
130+
// considering that Insertion Sort is slow...
131+
const n = 1000 // a thousand
132+
const array = newArrayOf(n, () => StdRandom.uniform(n))
133+
134+
Insertion.sort(array)
135+
136+
expect(Insertion.isSorted(array)).toBeTrue()
137+
})
138+
})
139+
})

0 commit comments

Comments
 (0)