选择排序

选择排序最坏效率:O(N2)
选择排序平均效率:
选择排序最好效率:

选择排序的步骤如下。

1. 从左至右检查数组的每个格子,找出值最小的那个。在此过程中,我们会用一个变量来记住检查过的数字的最小值。如果一个格子中的数字比记录的最小值还要小,就把变量改成该格子的索引。
2. 知道哪个格子的值最小之后,将该格与本次检查的起点交换。第1次检查的起点是索引0,第2次是索引1,以此类推。
3. 重复第(1)(2)步,直至数组排好序。
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
class SelectionSort extends Sort {
sort(originalArray) {
// Clone original array to prevent its modification.
const array = [...originalArray];

for (let i = 0; i < array.length - 1; i += 1) {
let minIndex = i;

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

// Find minimum element in the rest of array.
for (let j = i + 1; j < array.length; j += 1) {
// Call visiting callback.
this.callbacks.visitingCallback(array[j]);

if (this.comparator.lessThan(array[j], array[minIndex])) {
minIndex = j;
}
}

// If new minimum element has been found then swap it with current i-th element.
if (minIndex !== i) {
[array[i], array[minIndex]] = [array[minIndex], array[i]];
}
}

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);
}
}