1
+ import ArrayTracer from '../../components/DataStructures/Array/Array1DTracer' ;
2
+ import MaskTracer from '../../components/DataStructures/Mask/MaskTracer' ;
3
+ import { areExpanded } from './collapseChunkPlugin' ;
4
+
5
+ const BITS = 2 ;
6
+
7
+ const SRS_BOOKMARKS = {
8
+ radix_sort : 1 ,
9
+ max_number : 2 ,
10
+ counting_sort_for_loop : 3 ,
11
+ counting_sort : 4 ,
12
+ count_nums : 5 ,
13
+ cumulative_sum : 6 ,
14
+ populate_array : 7 ,
15
+ populate_for_loop : 8 ,
16
+ insert_into_array : 9 ,
17
+ copy : 10 ,
18
+ done : 11 ,
19
+ add_to_count : 12 ,
20
+ add_count_for_loop : 13 ,
21
+ cum_sum_for_loop : 14 ,
22
+ add_cum_sum : 15 ,
23
+ } ;
24
+
25
+ const isCountExpanded = ( ) => {
26
+ return areExpanded ( [ "Countingsort" ] ) ;
27
+ } ;
28
+
29
+ const highlight = ( array , index , isPrimaryColor = true ) => {
30
+ if ( isPrimaryColor ) {
31
+ array . select ( index ) ;
32
+ } else {
33
+ array . patch ( index ) ;
34
+ }
35
+ } ;
36
+
37
+ const unhighlight = ( array , index , isPrimaryColor = true ) => {
38
+ if ( isPrimaryColor ) {
39
+ array . deselect ( index ) ;
40
+ } else {
41
+ array . depatch ( index ) ;
42
+ }
43
+ } ;
44
+
45
+ const updateMask = ( vis , index , bits ) => {
46
+ const mask = ( ( 1 << bits ) - 1 ) << ( index * bits ) ;
47
+ const indexes = [ ] ;
48
+
49
+ for ( let i = 0 ; i < vis . mask . maxBits ; i ++ ) {
50
+ if ( bitsAtIndex ( mask , i , 1 ) == 1 ) {
51
+ indexes . push ( i ) ;
52
+ }
53
+ }
54
+
55
+ vis . mask . setMask ( mask , indexes ) ;
56
+ } ;
57
+
58
+ const updateBinary = ( vis , value ) => {
59
+ vis . mask . setBinary ( value ) ;
60
+ } ;
61
+
62
+ const bitsAtIndex = ( num , index , bits ) => {
63
+ return num >> ( index * bits ) & ( ( 1 << bits ) - 1 ) ;
64
+ } ;
65
+
66
+ const setArray = ( visArray , array ) => {
67
+ visArray . set ( array , 'straightRadixSort' ) ;
68
+ } ;
69
+
70
+ export default {
71
+ initVisualisers,
72
+
73
+ /**
74
+ *
75
+ * @param {object } chunker
76
+ * @param {array } nodes array of numbers needs to be sorted
77
+ */
78
+ run ( chunker , { nodes } ) {
79
+ let A = [ ...nodes ] ;
80
+ const n = A . length ;
81
+
82
+ const countingSort = ( A , k , n , bits ) => {
83
+ const count = Array . apply ( null , Array ( 1 << bits ) ) . map ( ( ) => 0 ) ;
84
+ let lastBit = - 1 ;
85
+
86
+ chunker . add ( SRS_BOOKMARKS . count_nums ) ;
87
+
88
+ for ( let i = 0 ; i < n ; i ++ ) {
89
+ chunker . add ( SRS_BOOKMARKS . add_count_for_loop ,
90
+ ( vis , i , lastBit ) => {
91
+ if ( i !== 0 ) {
92
+ unhighlight ( vis . array , i - 1 ) ;
93
+ }
94
+
95
+ if ( lastBit !== - 1 && isCountExpanded ( ) ) {
96
+ unhighlight ( vis . countArray , lastBit ) ;
97
+ }
98
+
99
+ highlight ( vis . array , i ) ;
100
+ updateBinary ( vis , A [ i ] ) ;
101
+ } ,
102
+ [ i , lastBit ]
103
+ ) ;
104
+
105
+ const bit = bitsAtIndex ( A [ i ] , k , bits ) ;
106
+ count [ bit ] ++ ;
107
+
108
+ chunker . add ( SRS_BOOKMARKS . add_to_count ,
109
+ ( vis , count ) => {
110
+ if ( isCountExpanded ( ) ) {
111
+ setArray ( vis . countArray , count ) ;
112
+ highlight ( vis . countArray , bit ) ;
113
+ }
114
+ } ,
115
+ [ count ]
116
+ ) ;
117
+
118
+ lastBit = bit ;
119
+ }
120
+
121
+ chunker . add ( SRS_BOOKMARKS . cumulative_sum ,
122
+ ( vis , n , lastBit ) => {
123
+ unhighlight ( vis . array , n - 1 ) ;
124
+
125
+ if ( isCountExpanded ( ) ) {
126
+ unhighlight ( vis . countArray , lastBit ) ;
127
+ }
128
+ } ,
129
+ [ n , lastBit ]
130
+ ) ;
131
+
132
+ for ( let i = 1 ; i < count . length ; i ++ ) {
133
+ chunker . add ( SRS_BOOKMARKS . cum_sum_for_loop ,
134
+ ( vis , i ) => {
135
+ if ( i === 1 && isCountExpanded ( ) ) {
136
+ highlight ( vis . countArray , 0 ) ;
137
+ }
138
+ } ,
139
+ [ i ]
140
+ ) ;
141
+
142
+ count [ i ] += count [ i - 1 ] ;
143
+
144
+ chunker . add ( SRS_BOOKMARKS . add_cum_sum ,
145
+ ( vis , count , i ) => {
146
+ if ( isCountExpanded ( ) ) {
147
+ setArray ( vis . countArray , count ) ;
148
+ highlight ( vis . countArray , i ) ;
149
+ }
150
+ } ,
151
+ [ count , i ]
152
+ )
153
+ }
154
+
155
+ const sortedA = Array . apply ( null , Array ( n ) ) . map ( ( ) => 0 ) ;
156
+
157
+ chunker . add ( SRS_BOOKMARKS . populate_array ,
158
+ ( vis , countLength ) => {
159
+ if ( isCountExpanded ( ) ) {
160
+ unhighlight ( vis . countArray , countLength - 1 ) ;
161
+ }
162
+ } ,
163
+ [ count . length ]
164
+ ) ;
165
+
166
+ chunker . add ( SRS_BOOKMARKS . populate_for_loop ) ;
167
+
168
+ let bit ;
169
+
170
+ for ( let i = n - 1 ; i >= 0 ; i -- ) {
171
+ const num = A [ i ] ;
172
+ bit = bitsAtIndex ( num , k , bits ) ;
173
+ count [ bit ] -- ;
174
+ sortedA [ count [ bit ] ] = num ;
175
+ chunker . add ( SRS_BOOKMARKS . insert_into_array ,
176
+ ( vis , num , i , bit , count , sortedA ) => {
177
+ if ( i !== n - 1 ) {
178
+ unhighlight ( vis . array , i + 1 ) ;
179
+ }
180
+
181
+ if ( isCountExpanded ( ) ) {
182
+ setArray ( vis . countArray , count ) ;
183
+ setArray ( vis . tempArray , sortedA ) ;
184
+ highlight ( vis . countArray , bit ) ;
185
+ highlight ( vis . tempArray , count [ bit ] ) ;
186
+ }
187
+
188
+ updateBinary ( vis , num ) ;
189
+ highlight ( vis . array , i ) ;
190
+ } ,
191
+ [ num , i , bit , count , sortedA ]
192
+ ) ;
193
+ }
194
+
195
+ chunker . add ( SRS_BOOKMARKS . copy ,
196
+ ( vis , array , n , countLength ) => {
197
+ setArray ( vis . array , array ) ;
198
+
199
+ if ( isCountExpanded ( ) ) {
200
+ setArray ( vis . tempArray , Array . apply ( null , Array ( n ) ) . map ( ( ) => undefined ) ) ;
201
+ setArray ( vis . countArray , Array . apply ( null , Array ( countLength ) ) . map ( ( ) => undefined ) ) ;
202
+ }
203
+ } ,
204
+ [ sortedA , n , count . length ]
205
+ ) ;
206
+
207
+ return sortedA ;
208
+ } ;
209
+
210
+ let maxNumber = Math . max ( ...A ) ;
211
+ let maxBit = - 1 ;
212
+
213
+ while ( maxNumber > 0 ) {
214
+ maxNumber = Math . floor ( maxNumber / 2 ) ;
215
+ maxBit ++ ;
216
+ }
217
+
218
+ let bits = 1 ;
219
+
220
+ while ( bits < maxBit ) {
221
+ bits *= 2 ;
222
+ }
223
+
224
+ chunker . add ( SRS_BOOKMARKS . radix_sort ,
225
+ ( vis , array ) => {
226
+ setArray ( vis . array , array ) ;
227
+
228
+ if ( isCountExpanded ( ) ) {
229
+ setArray ( vis . countArray , Array . apply ( null , Array ( 1 << BITS ) ) . map ( ( ) => undefined ) ) ;
230
+ setArray ( vis . tempArray , Array . apply ( null , Array ( n ) ) . map ( ( ) => undefined ) ) ;
231
+ }
232
+ } ,
233
+ [ nodes ]
234
+ ) ;
235
+
236
+ chunker . add ( SRS_BOOKMARKS . max_number ,
237
+ ( vis , bits ) => {
238
+ vis . mask . setMaxBits ( bits ) ;
239
+ } ,
240
+ [ bits ]
241
+ ) ;
242
+
243
+ for ( let k = 0 ; k < bits / BITS ; k ++ ) {
244
+ chunker . add ( SRS_BOOKMARKS . counting_sort_for_loop ,
245
+ vis => {
246
+ updateMask ( vis , k , BITS ) ;
247
+ }
248
+ ) ;
249
+
250
+ A = countingSort ( A , k , n , BITS ) ;
251
+
252
+ chunker . add ( SRS_BOOKMARKS . counting_sort ) ;
253
+ }
254
+
255
+ chunker . add ( SRS_BOOKMARKS . done ,
256
+ vis => {
257
+ for ( let i = 0 ; i < n ; i ++ ) {
258
+ vis . array . sorted ( i ) ;
259
+ }
260
+ }
261
+ ) ;
262
+
263
+ return A ;
264
+ }
265
+ } ;
266
+
267
+
268
+ export function initVisualisers ( ) {
269
+ if ( isCountExpanded ( ) ) {
270
+ return {
271
+ mask : {
272
+ instance : new MaskTracer ( 'mask' , null , 'Mask' ) ,
273
+ order : 0 ,
274
+ } ,
275
+ array : {
276
+ instance : new ArrayTracer ( 'array' , null , 'Array view' , { arrayItemMagnitudes : false } ) ,
277
+ order : 1 ,
278
+ } ,
279
+ countArray : {
280
+ instance : new ArrayTracer ( 'countArray' , null , 'Count array' , { arrayItemMagnitudes : false } ) ,
281
+ order : 1 ,
282
+ } ,
283
+ tempArray : {
284
+ instance : new ArrayTracer ( 'tempArray' , null , 'Temp array' , { arrayItemMagnitudes : false } ) ,
285
+ order : 1 ,
286
+ } ,
287
+ } ;
288
+ } else {
289
+ return {
290
+ mask : {
291
+ instance : new MaskTracer ( 'mask' , null , 'Mask' ) ,
292
+ order : 0 ,
293
+ } ,
294
+ array : {
295
+ instance : new ArrayTracer ( 'array' , null , 'Array view' , { arrayItemMagnitudes : true } ) ,
296
+ order : 1 ,
297
+ } ,
298
+ } ;
299
+ }
300
+ }
0 commit comments