7
7
8
8
'use strict' ;
9
9
10
+ /**
11
+ * 交换数组中两元素位置
12
+ * @param : i, j: 待交换的两元素下标
13
+ */
14
+ Array . prototype . swap = function ( i , j ) {
15
+ const temp = this [ i ] ;
16
+ this [ i ] = this [ j ] ;
17
+ this [ j ] = temp ;
18
+ }
19
+
10
20
/**
11
21
* 冒泡排序
12
22
* @param : <Array> target数组
13
23
* @description : 冒泡排序,更贴切的形容应该是沉底排序,每一轮内循环就是最大数沉底了。
14
24
*/
15
25
module . exports . bubbleSort = function bubbleSort ( target ) {
16
- var temp ;
17
26
for ( var j = target . length ; j > 0 ; j -- ) {
18
27
for ( var i = 0 ; i < j - 1 ; i ++ ) {
19
28
if ( target [ i ] > target [ i + 1 ] ) {
20
- temp = target [ i ] ;
21
- target [ i ] = target [ i + 1 ] ;
22
- target [ i + 1 ] = temp ;
29
+ target . swap ( i , i + 1 ) ;
23
30
}
24
31
}
25
32
}
@@ -37,9 +44,7 @@ module.exports.selectSort = function selectSort(target) {
37
44
for ( var i = 1 ; i < j ; i ++ ) {
38
45
maxIndex = target [ maxIndex ] > target [ i ] ? maxIndex : i ;
39
46
}
40
- var temp = target [ j - 1 ] ;
41
- target [ j - 1 ] = target [ maxIndex ] ;
42
- target [ maxIndex ] = temp ;
47
+ target . swap ( maxIndex , j - 1 ) ;
43
48
}
44
49
return target ;
45
50
} ;
@@ -124,31 +129,30 @@ module.exports.quickSort = function quickSort(target) {
124
129
* @param : <Array> target
125
130
* @description : 上面的快排每次都开辟一个数组,浪费空间。常规做法是两边查找到中间,两两交换位置
126
131
*/
127
- module . exports . inPlaceQuickSort = function inPlaceQuickSort ( target ) {
128
- function _inPlaceQuickSort ( target , left , right ) {
129
- // 先定义递归终止条件
130
- if ( left >= right ) { return target ; }
131
-
132
- var base = target [ left ] ;
133
- var i = left ;
134
- var j = right ;
135
- while ( i < j ) {
136
- while ( i < j && target [ j ] >= base ) {
137
- j -- ;
138
- }
139
- target [ i ] = target [ j ] ;
140
- while ( i < j && target [ i ] <= base ) {
141
- i ++ ;
142
- }
143
- target [ j ] = target [ i ] ;
132
+ function _inPlaceQuickSort ( target , left , right ) {
133
+ // 先定义递归终止条件
134
+ if ( left >= right ) { return target ; }
135
+
136
+ var base = target [ left ] ;
137
+ var i = left ;
138
+ var j = right ;
139
+ while ( i < j ) {
140
+ while ( i < j && target [ j ] >= base ) {
141
+ j -- ;
144
142
}
145
- target [ i ] = base ;
146
- // 也可以利用函数副作用改变传入数组,但是用显式返回更清晰
147
- target = _inPlaceQuickSort ( target , left , i - 1 ) ;
148
- target = _inPlaceQuickSort ( target , i + 1 , right ) ;
149
- return target ;
143
+ target [ i ] = target [ j ] ;
144
+ while ( i < j && target [ i ] <= base ) {
145
+ i ++ ;
146
+ }
147
+ target [ j ] = target [ i ] ;
150
148
}
151
-
149
+ target [ i ] = base ;
150
+ // 函数副作用已经改变了传入数组,但是用显式返回看起来更清晰
151
+ target = _inPlaceQuickSort ( target , left , i - 1 ) ;
152
+ target = _inPlaceQuickSort ( target , i + 1 , right ) ;
153
+ return target ;
154
+ }
155
+ module . exports . inPlaceQuickSort = function inPlaceQuickSort ( target ) {
152
156
return _inPlaceQuickSort ( target , 0 , target . length - 1 )
153
157
} ;
154
158
@@ -185,4 +189,68 @@ module.exports.mergeSort = function mergeSort(target) {
185
189
return mergeSortedArray ( mergeSort ( left ) , mergeSort ( right ) ) ;
186
190
} ;
187
191
192
+ /**
193
+ * 堆排序
194
+ * @param : <Array> target
195
+ * @description : 通过构建大(小)根堆的方式进行排序,PS:使用函数副作用来进行原地排序
196
+ */
197
+ // 递归调整 i~j 层的大根堆
198
+ function adjustMaxHeap ( target , i , j ) {
199
+ let parent = i ;
200
+ let left = 2 * i + 1 ;
201
+ let right = 2 * i + 2 ;
188
202
203
+ // 比较父节点与左右叶子节点,取最大值的下标设为父节点下标
204
+ if ( left < j && target [ parent ] < target [ left ] ) {
205
+ parent = left ;
206
+ }
207
+ if ( right < j && target [ parent ] < target [ right ] ) {
208
+ parent = right ;
209
+ }
210
+ // 只有父节点发生改变才会破坏大根堆结构,此时才需要继续调整下级大根堆
211
+ if ( parent != i ) {
212
+ target . swap ( i , parent ) ;
213
+ adjustMaxHeap ( target , parent , j ) ;
214
+ }
215
+ }
216
+ // 构建大根堆就是不断调整最大堆的过程,只要从最后一个父节点往上调整到第一个父节点,就能构建出大根堆
217
+ // 从0开始的n层堆的结构:len = 2^n - 1,第n层全是叶子,所以第n-1层的最后一个父节点就是floor(len/2)-1
218
+ function buildMaxHeap ( target ) {
219
+ const len = target . length ;
220
+ for ( let i = Math . floor ( len / 2 ) - 1 ; i >= 0 ; i -- ) {
221
+ adjustMaxHeap ( target , i , len ) ;
222
+ }
223
+ }
224
+
225
+ function sortMaxHeap ( target ) {
226
+ for ( let i = target . length - 1 ; i > 0 ; i -- ) {
227
+ target . swap ( 0 , i ) ;
228
+ adjustMaxHeap ( target , 0 , i ) ;
229
+ }
230
+ }
231
+ // 先构建一个大根堆,然后从最后一个元素开始交换堆顶元素,每次交换都调整根堆,直到数组头则完成排序
232
+ module . exports . heapSort = function heapSort ( target ) {
233
+ buildMaxHeap ( target ) ;
234
+ sortMaxHeap ( target ) ;
235
+ return target ;
236
+ } ;
237
+
238
+ /**
239
+ * 堆排序提取部分记录
240
+ * 从大数据中提取最大(小)的n条记录,也可以用小(大)根堆来实现
241
+ * 先用数据集中前n条数据构造一个小根堆,然后将后面的数据依次通过这个小根堆:
242
+ * 比堆顶小的数据直接丢弃,比堆顶大则替换堆顶,然后调整根堆。最后输出小根堆的排序
243
+ */
244
+ module . exports . topSortViaHeap = function topSortViaHeap ( target ) {
245
+ const len = 10 ;
246
+ let ret = target . slice ( 0 , len ) ;
247
+ buildMaxHeap ( ret ) ;
248
+ for ( var i = len ; i < target . length ; i ++ ) {
249
+ if ( target [ i ] < ret [ 0 ] ) {
250
+ ret [ 0 ] = target [ i ] ;
251
+ adjustMaxHeap ( ret , 0 , ret . length ) ;
252
+ }
253
+ }
254
+ sortMaxHeap ( ret ) ;
255
+ return ret ;
256
+ }
0 commit comments