Shellsort is the same as insertion sort. Except that it uses a pass array to decide how many number of steps to jump.
In Insertion Sort, we always use 1 step. When we backtrack, we go back 1 step. But in Shellsort, we have an array, where we decide how many jumps to backtrack. This is called a “gap”. Of course in the very end, we’ll definitely have 1 step at the end.
1 2 3 4 5 6 7 8 |
for (var gapIndex = 0; gapIndex < gaps.length; gapIndex++) { var gap = gaps[gapIndex]; for (var i = gap; i < dataStore.length; ++i) { // do Insertion sort using "gap" number of steps when going backwards } } |
In our example, we decide to use 5, 3, 1. What this means is that we will sort this via Insertion via passes where we jump 5 steps, then 3 steps, then 1 step. So for step 5, we start at index 5 of the array. Do the Insertion sort, but instead of using 1 step when going backwards, we use 5 steps.
first pass, 5 steps
We start off at index 5. Will process the insertion sort, and when we’re done, we go down the array 1 by 1.
The insertion sort itself will use 5 steps when sorting via
1 |
j -= gap |
Everything else is processed the same way as Insertion Sort. We get the current valueToInsert. It needs to satisfy a few points:
1) is the index larger or equal to the gap index?
2) is the previous gapped element larger than the valueToInsert?
If so, we assign the previous gapped element to the current one.
If not, we just put the valueToInsert back to the current element.
Given the Insertion Code with the gap element like so:
1 2 3 4 5 6 7 8 9 10 11 |
for (var i = gap; i < dataStore.length; ++i) { var valueToInsert = dataStore[i]; for (var j = i; j >= gap && (dataStore[j-gap] > valueToInsert) ; j -= gap) { dataStore[j] = dataStore[j - gap]; } dataStore[j] = valueToInsert; // insert valueToInsert at the appropriate place console.log("index j: "+j + ", dataStore[j] = valueToInsert"); } |
The gap we use is 5. So we need to do an Insertion pass where the gap is 5.
We start index 5. The value at that index is 11. 11 is the value we need to check and find a proper place to insert.
The Insertion sort happens when we have j point to i.
1) j>= gap, 5 >= 5 ? yes
2) previous gapped element > valueToInsert, 6 > 11 ? NO
dataStore[5] = 11, we move down the array.
The next index is 6. dataStore[6] is 8. The previous gapped element is dataStore[6-5] is 0
1) j >= gap, 6 >= 5? yes
2) previous gapped element > valueToInsert, 0 > 8, NO
dataStore[6] = 8, we move down the array
The next index is 7. dataStore[7] is 0. Its previous gapped element dataStore[7-5] is 2.
1) j >= gap, 7 >= 5? yes
2) previous gapped element > valueToInsert, 2 > 0 yes
When both requirements is true, we exchange the element values. Basically storing the previous value into the current value. This is the because the previous value is larger than the current value.
We continue on the insertion sort by looking back at -gap elements. Namely, j-= gap. Hence our j is now at index 2, dataStore[2] = 2.
We check the requirements again:
1) j >= gap, 2 >= 5 NO
So we jump out of the loop and assign the valueToInsert at dataStore[2]. This perfectly switches the numbers at dataStore[2], and dataStore[7].
We move onto the next index at 8. dataStore[8] is 5.
Previous gapped element is dataStore[8-5] = 9
1) j >= gap, 8 >= 5, yes
2) previous gapped element > valueToInsert, 9 > 5 yes
Hence we need to copy the previous element to the current one. We then backtrack gap steps into index 3
1) j >= gap, 3 >= 5, NO
therefore dataStore[3] = 5.
We keep going down the array.
We process the last element at index 9, dataStore[9] is 4.
dataStore[9] is 4
dataStore[9-5] is 3
1) j>= gap, 9 >= 5
2) previous gapped element > valueToInsert, 3 > 4, NO.
So we jump out of the loop
dataStore[9] = 4
next gap pass, 3 steps
We start from beginning to end, and at index gap. We do the insertion sort with gap steps, however, we process each element down the array one by one.
index 3
Hence, our next pass involves gap 3. We start off at index 3.
We see that dataStore[3] is 9. valueToInsert = 9.
Previous gap element is dataStore[0] is 6.
is index 3 >= 3 yes
6 > 9 (valeToinsert) NO, move on to next index
index 4
We now on index 4.
dataStore[4] = 3, valueToInsert = 3
dataStore[4-3] = 0
4 >= 3 yes
0 > 3 (valeToInsert) NO, move on to next index
index 5
We now on index 5.
dataStore[5] is 11, valueToInsert = 11
dataStore[5-3] is 2
5 >= 3 yes
2 > 11 (valeToInsert), NO, move on to next index
index 6
We now on index 6.
dataStore[6] is 8 valueToInsert = 8
dataStore[6-3] is 9.
6 >= 3 yes
9 > 8(valeToInsert), we then copy over the value from the previous element to the current
Thus, dataStore[6] = 9.
We go back 1 gap step so now j is at index 3.
dataStore[3] is 9
dataStore[3-3] is 6
3 >= 3 yes
6 > 8 (valeToInsert), NO, we skip out. have current index j, dataStore[3] = 8 (valueToInsert)
move forward down the array
index 7
We are now at index 7.
dataStore[7] is 0. valueToInsert is 0.
dataStore[7-3] is 3
7>=3 yes
3 > 0 yes
Let’s copy previous element to current so now
dataStore[7] is 3.
j moves a “gap” step back to index 4
dataStore[4] is 3
dataStore[1] is 0
4 >= 3, YES
0 > 0 NO
dataStore[4] is 0.
Move forward
index 8
dataStore[8] is 5 (valueToInsert)
dataStore[8-3] is 11
8 >= 3 yes
11 > 5 yes
So we need to copy the previous value over to current.
dataStore[8] = 11
Go back 1 “gap” step to index 5
dataStore[5] is 11
dataStore[5-3] is 2
5 >= 3 yes
2 >= 5 (valueToInsert) NO
dataStore[5] = 5
move on…
Index 9
Finally, we are index 9.
dataStore[9] is 4 (valueToInsert)
dataStore[9-3] is 8
9 >= 3 yes
8 > 4 yes
so we copy the previous gap element to current
dataStore[9] = 8
we go previous gap element to index 6
dataStore[6] is 8
dataStore[6-3] is 9
6 >= 3, YES
9 >= 4 (valueToInsert), YES
copy the previous gap element to current
dataStore[6] = 9
go back “gap” elements
dataStore[3] is 9
dataStore[0] is 6
3 >= 3, YES
6 > 4 (valueToInsert) YES
copy the previous gap element to current
dataStore[3] = 6
go back “gap” elements
index is now 0
0 >= 3 NO
so dataStore[0] = 4 (valueToInsert)
Done for gap 3 pass
Full Source
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 |
"use strict"; var dataStore = [6,0,2,9,3,11,8,0,5,4]; // gaps element is "starting index" var gaps = [5,3,1]; function shellsort() { for (var gapIndex = 0; gapIndex < gaps.length; gapIndex++) { var gap = gaps[gapIndex]; console.log("***** gap:" + gap + " *******"); for (var i = gap; i < dataStore.length; ++i) { var valueToInsert = dataStore[i]; console.log("i " + i + ", valueToInsert is: " + valueToInsert); console.log("------------ APPLY INSERTION SORT HERE ------------"); console.log("dataStore[i-gap]: "+dataStore[i-gap]); for (var j = i; j >= gap && dataStore[j-gap] > valueToInsert; j -= gap) { console.log("-- j is: " + j + "--"); console.log("dataStore is: "+dataStore[j-gap]); dataStore[j] = dataStore[j - gap]; } dataStore[j] = valueToInsert; console.log("index j: "+j + ", dataStore[j] = valueToInsert"); } } return dataStore; } var sorted = shellsort(); console.log(sorted); |