8
8
* a positive value if `a` should come after `b`,
9
9
* and zero if `a` and `b` are considered equal.
10
10
*/
11
- type Comparator < T > = ( a : T , b : T ) => number ;
11
+ type Comparator < T > = ( a : T , b : T ) => number
12
12
13
13
// Minimum size of subarrays to be sorted using insertion sort before merging
14
- const MIN_MERGE = 32 ;
14
+ const MIN_MERGE = 32
15
15
16
16
/**
17
- * Performs insertion sort on a portion of an array.
18
- *
19
- * @typeparam T The type of elements in the array.
20
- * @param arr The array to sort.
21
- * @param startIndex The start index of the portion to sort.
22
- * @param endIndex The end index of the portion to sort.
23
- * @param compare The comparator function defining the order of elements.
24
- */
25
- const insertionSort = < T > (
26
- arr : T [ ] ,
27
- startIndex : number ,
28
- endIndex : number ,
29
- compare : Comparator < T >
30
- ) : void => {
31
- for ( let i = startIndex + 1 ; i <= endIndex ; i ++ ) {
32
- const currentElement = arr [ i ] ;
33
- let j = i - 1 ;
34
-
35
- while ( j >= startIndex && compare ( arr [ j ] , currentElement ) > 0 ) {
36
- arr [ j + 1 ] = arr [ j ] ;
37
- j -- ;
38
- }
39
- arr [ j + 1 ] = currentElement ;
40
- }
41
- } ;
42
-
43
- /**
44
- * Merges two sorted subarrays into one sorted array.
45
- * This version of merge includes "galloping mode" for performance optimization.
17
+ * Merges two sorted subarrays into one sorted array with optimized galloping mode.
46
18
*
47
19
* @typeparam T The type of elements in the array.
48
20
* @param arr The array containing the subarrays to merge.
@@ -58,32 +30,63 @@ const merge = <T>(
58
30
rightIndex : number ,
59
31
compare : Comparator < T >
60
32
) : void => {
61
- const leftArray = arr . slice ( leftIndex , middleIndex + 1 ) ;
62
- const rightArray = arr . slice ( middleIndex + 1 , rightIndex + 1 ) ;
63
-
64
- let leftPointer = 0 ;
65
- let rightPointer = 0 ;
66
- let mergedIndex = leftIndex ;
67
-
68
- while ( leftPointer < leftArray . length && rightPointer < rightArray . length ) {
69
- if ( compare ( leftArray [ leftPointer ] , rightArray [ rightPointer ] ) <= 0 ) {
70
- arr [ mergedIndex ++ ] = leftArray [ leftPointer ++ ] ;
71
- } else {
72
- arr [ mergedIndex ++ ] = rightArray [ rightPointer ++ ] ;
33
+ const leftArrayLength = middleIndex - leftIndex + 1
34
+ const rightArrayLength = rightIndex - middleIndex
35
+
36
+ // Create temporary arrays for the left and right subarrays
37
+ const leftSubarray : T [ ] = arr . slice ( leftIndex , middleIndex + 1 )
38
+ const rightSubarray : T [ ] = arr . slice ( middleIndex + 1 , rightIndex + 1 )
39
+
40
+ let leftPointer = 0
41
+ let rightPointer = 0
42
+ let mergedIndex = leftIndex
43
+
44
+ // Regular merge with galloping mode
45
+ while ( leftPointer < leftArrayLength && rightPointer < rightArrayLength ) {
46
+ let numGallops = 0
47
+
48
+ // Galloping through the left subarray
49
+ while (
50
+ leftPointer < leftArrayLength &&
51
+ numGallops < MIN_MERGE &&
52
+ compare ( leftSubarray [ leftPointer ] , rightSubarray [ rightPointer ] ) <= 0
53
+ ) {
54
+ arr [ mergedIndex ++ ] = leftSubarray [ leftPointer ++ ]
55
+ numGallops ++
56
+ }
57
+
58
+ // Galloping through the right subarray
59
+ while (
60
+ rightPointer < rightArrayLength &&
61
+ numGallops < MIN_MERGE &&
62
+ compare ( rightSubarray [ rightPointer ] , leftSubarray [ leftPointer ] ) < 0
63
+ ) {
64
+ arr [ mergedIndex ++ ] = rightSubarray [ rightPointer ++ ]
65
+ numGallops ++
73
66
}
74
- }
75
67
76
- // Copy remaining elements from leftArray, if any
77
- while ( leftPointer < leftArray . length ) {
78
- arr [ mergedIndex ++ ] = leftArray [ leftPointer ++ ] ;
68
+ // Standard merge without galloping
69
+ while ( leftPointer < leftArrayLength && rightPointer < rightArrayLength ) {
70
+ if (
71
+ compare ( leftSubarray [ leftPointer ] , rightSubarray [ rightPointer ] ) <= 0
72
+ ) {
73
+ arr [ mergedIndex ++ ] = leftSubarray [ leftPointer ++ ]
74
+ } else {
75
+ arr [ mergedIndex ++ ] = rightSubarray [ rightPointer ++ ]
76
+ }
77
+ }
79
78
}
80
79
81
- // Copy remaining elements from rightArray , if any
82
- while ( rightPointer < rightArray . length ) {
83
- arr [ mergedIndex ++ ] = rightArray [ rightPointer ++ ] ;
80
+ // Copy remaining elements from left subarray , if any
81
+ while ( leftPointer < leftArrayLength ) {
82
+ arr [ mergedIndex ++ ] = leftSubarray [ leftPointer ++ ]
84
83
}
85
- } ;
86
84
85
+ // Copy remaining elements from right subarray, if any
86
+ while ( rightPointer < rightArrayLength ) {
87
+ arr [ mergedIndex ++ ] = rightSubarray [ rightPointer ++ ]
88
+ }
89
+ }
87
90
88
91
/**
89
92
* Sorts an array using the Tim sort algorithm.
@@ -93,7 +96,7 @@ const merge = <T>(
93
96
* @param compare The comparator function defining the order of elements.
94
97
*/
95
98
export const timSort = < T > ( arr : T [ ] , compare : Comparator < T > ) : void => {
96
- const n = arr . length ;
99
+ const length = arr . length
97
100
98
101
/**
99
102
* Reverses a portion of the array.
@@ -103,11 +106,11 @@ export const timSort = <T>(arr: T[], compare: Comparator<T>): void => {
103
106
*/
104
107
const reverseRange = ( start : number , end : number ) : void => {
105
108
while ( start < end ) {
106
- const temp = arr [ start ] ;
107
- arr [ start ++ ] = arr [ end ] ;
108
- arr [ end -- ] = temp ;
109
+ const temp = arr [ start ]
110
+ arr [ start ++ ] = arr [ end ]
111
+ arr [ end -- ] = temp
109
112
}
110
- } ;
113
+ }
111
114
112
115
/**
113
116
* Identifies runs and sorts them using insertion sort.
@@ -116,71 +119,70 @@ export const timSort = <T>(arr: T[], compare: Comparator<T>): void => {
116
119
* @param end The ending index of the range to find runs.
117
120
*/
118
121
const findRunsAndSort = ( start : number , end : number ) : void => {
119
- for ( let i = start + 1 ; i <= end ; i ++ ) {
120
- const currentElement = arr [ i ] ;
121
- let j = i - 1 ;
122
+ for ( let currIdx = start + 1 ; currIdx <= end ; currIdx ++ ) {
123
+ const currentElement = arr [ currIdx ]
124
+ let prevIdx = currIdx - 1
122
125
123
- while ( j >= start && compare ( arr [ j ] , currentElement ) > 0 ) {
124
- arr [ j + 1 ] = arr [ j ] ;
125
- j -- ;
126
+ while ( prevIdx >= start && compare ( arr [ prevIdx ] , currentElement ) > 0 ) {
127
+ arr [ prevIdx + 1 ] = arr [ prevIdx ]
128
+ prevIdx --
126
129
}
127
- arr [ j + 1 ] = currentElement ;
130
+ arr [ prevIdx + 1 ] = currentElement
128
131
}
129
- } ;
132
+ }
130
133
131
134
/**
132
135
* Merges runs in the array.
133
136
*
134
137
* @param minRunLength The minimum length of a run.
135
138
*/
136
139
const mergeRuns = ( minRunLength : number ) : void => {
137
- for ( let size = minRunLength ; size < n ; size *= 2 ) {
138
- for ( let left = 0 ; left < n ; left += 2 * size ) {
139
- const mid = left + size - 1 ;
140
- const right = Math . min ( left + 2 * size - 1 , n - 1 ) ;
140
+ for ( let size = minRunLength ; size < length ; size *= 2 ) {
141
+ for ( let left = 0 ; left < length ; left += 2 * size ) {
142
+ const mid = left + size - 1
143
+ const right = Math . min ( left + 2 * size - 1 , length - 1 )
141
144
142
145
if ( mid < right ) {
143
- merge ( arr , left , mid , right , compare ) ;
146
+ merge ( arr , left , mid , right , compare )
144
147
}
145
148
}
146
149
}
147
- } ;
150
+ }
148
151
149
152
/**
150
153
* Handles descending runs in the array.
151
154
*/
152
155
const handleDescendingRuns = ( ) : void => {
153
- let stackSize = 0 ;
154
- const runStack : [ number , number ] [ ] = [ ] ;
156
+ let stackSize = 0
157
+ const runStack : [ number , number ] [ ] = [ ]
155
158
156
159
// Push runs onto stack
157
- for ( let i = 0 ; i < n ; i ++ ) {
158
- let runStart = i ;
159
- while ( i < n - 1 && compare ( arr [ i ] , arr [ i + 1 ] ) > 0 ) {
160
- i ++ ;
160
+ for ( let idx = 0 ; idx < length ; idx ++ ) {
161
+ let runStart = idx
162
+ while ( idx < length - 1 && compare ( arr [ idx ] , arr [ idx + 1 ] ) > 0 ) {
163
+ idx ++
161
164
}
162
- if ( runStart !== i ) {
163
- runStack . push ( [ runStart , i ] ) ;
165
+ if ( runStart !== idx ) {
166
+ runStack . push ( [ runStart , idx ] )
164
167
}
165
168
}
166
169
167
170
// Merge descending runs
168
171
while ( runStack . length > 1 ) {
169
- const [ start1 , end1 ] = runStack . pop ( ) ! ;
170
- const [ start2 , end2 ] = runStack . pop ( ) ! ;
171
-
172
- merge ( arr , start2 , end2 , end1 , compare ) ;
173
- runStack . push ( [ start2 , end1 ] ) ;
172
+ const [ start1 , end1 ] = runStack . pop ( ) !
173
+ const [ start2 , end2 ] = runStack . pop ( ) !
174
+
175
+ merge ( arr , start2 , end2 , end1 , compare )
176
+ runStack . push ( [ start2 , end1 ] )
174
177
}
175
- } ;
178
+ }
176
179
177
180
// Find runs and sort them
178
- findRunsAndSort ( 0 , n - 1 ) ;
181
+ findRunsAndSort ( 0 , length - 1 )
179
182
180
183
// Merge runs
181
- mergeRuns ( MIN_MERGE ) ;
184
+ mergeRuns ( MIN_MERGE )
182
185
183
186
// Handle descending runs
184
- handleDescendingRuns ( ) ;
185
- } ;
186
-
187
+ handleDescendingRuns ( )
188
+ }
0 commit comments