title: 插入排序
date: 2020-12-07 14:37:27

tags:

插入排序最坏效率:O(N2)
插入排序平均效率:O(N2)
插入排序最好效率:O(N)

插入排序的步骤如下。

1. 在第一轮里,暂时将索引1(第2格)的值移走,并用一个临时变量来保存它。这使得该索引处留下一个空隙,因为它不包含值。在之后的轮回,我们会移走后面索引的值。
2. 接着便是平移阶段,我们会拿空隙左侧的每一个值与临时变量的值进行比较。如果空隙左侧的值大于临时变量的值,则将该值右移一格。随着值右移,空隙会左移。如果遇到比临时变量小的值,或者空隙已经到了数组的最左端,就结束平移阶段。
3. 将临时移走的值插入当前空隙。
4. 重复第(1)至(3)步,直至数组完全有序。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
class InsertionSort extends Sort {
sort(originalArray) {
const array = [...originalArray];

// Go through all array elements...
for (let i = 1; i < array.length; i += 1) {
let currentIndex = i;

// Call visiting callback.
this.callbacks.visitingCallback(array[i]);

// Go and check if previous elements and greater then current one.
// If this is the case then swap that elements.
while (
array[currentIndex - 1] !== undefined
&& this.comparator.lessThan(array[currentIndex], array[currentIndex - 1])
) {
// Call visiting callback.
this.callbacks.visitingCallback(array[currentIndex - 1]);

// Swap the elements.
const tmp = array[currentIndex - 1];
array[currentIndex - 1] = array[currentIndex];
array[currentIndex] = tmp;

// Shift current index left.
currentIndex -= 1;
}
}

return array;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Sort {
constructor(originalCallbacks) {
this.callbacks = Sort.initSortingCallbacks(originalCallbacks);
this.comparator = new Comparator(this.callbacks.compareCallback);
}

/**
* @param {SorterCallbacks} originalCallbacks
* @returns {SorterCallbacks}
*/
static initSortingCallbacks(originalCallbacks) {
const callbacks = originalCallbacks || {};
const stubCallback = () => {};

callbacks.compareCallback = callbacks.compareCallback || undefined;
callbacks.visitingCallback = callbacks.visitingCallback || stubCallback;

return callbacks;
}

sort() {
throw new Error('sort method must be implemented');
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
class Comparator {
/**
* @param {function(a: *, b: *)} [compareFunction] - It may be custom compare function that, let's
* say may compare custom objects together.
*/
constructor(compareFunction) {
this.compare = compareFunction || Comparator.defaultCompareFunction;
}

/**
* Default comparison function. It just assumes that "a" and "b" are strings or numbers.
* @param {(string|number)} a
* @param {(string|number)} b
* @returns {number}
*/
static defaultCompareFunction(a, b) {
if (a === b) {
return 0;
}

return a < b ? -1 : 1;
}

/**
* Checks if two variables are equal.
* @param {*} a
* @param {*} b
* @return {boolean}
*/
equal(a, b) {
return this.compare(a, b) === 0;
}

/**
* Checks if variable "a" is less than "b".
* @param {*} a
* @param {*} b
* @return {boolean}
*/
lessThan(a, b) {
return this.compare(a, b) < 0;
}

/**
* Checks if variable "a" is greater than "b".
* @param {*} a
* @param {*} b
* @return {boolean}
*/
greaterThan(a, b) {
return this.compare(a, b) > 0;
}

/**
* Checks if variable "a" is less than or equal to "b".
* @param {*} a
* @param {*} b
* @return {boolean}
*/
lessThanOrEqual(a, b) {
return this.lessThan(a, b) || this.equal(a, b);
}

/**
* Checks if variable "a" is greater than or equal to "b".
* @param {*} a
* @param {*} b
* @return {boolean}
*/
greaterThanOrEqual(a, b) {
return this.greaterThan(a, b) || this.equal(a, b);
}

/**
* Reverses the comparison order.
*/
reverse() {
const compareOriginal = this.compare;
this.compare = (a, b) => compareOriginal(b, a);
}
}