Skip to content

Commit db64445

Browse files
committed
Add shell sort tests. Expand explanation.
1 parent 77d2f55 commit db64445

File tree

10 files changed

+1369
-60
lines changed

10 files changed

+1369
-60
lines changed

Shell Sort/README.markdown

+120
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
# Shell Sort
2+
3+
Shell sort is based on [insertion sort](../Insertion%20Sort/) as a general way to improve its performance, by breaking the original list into smaller sublists which can then be individually sorted using insertion sort.
4+
5+
[There is a nice video created at Sapientia University](https://www.youtube.com/watch?v=CmPA7zE8mx0) which shows the process as a Hungarian folk dance.
6+
7+
## How it works
8+
9+
Instead of comparing elements that are side-by-side and swapping them if they are out of order, the way insertion sort does it, the shell sort algorithm compares elements that are far apart.
10+
11+
The distance between elements is known as the *gap*. If the elements being compared are in the wrong order, they are swapped across the gap. This eliminates many in-between copies that are common with insertion sort.
12+
13+
The idea is that by moving the elements over large gaps, the array becomes partially sorted quite quickly. This makes later passes faster because they don't have to swap so many items anymore.
14+
15+
Once a pass has been completed, the gap is made smaller and a new pass starts. This repeats until the gap is 1, at which point the algorithm functions just like insertion sort. But since the data is already fairly well sorted by then, the final pass can be very quick.
16+
17+
## An example
18+
19+
Suppose we want to sort the array `[64, 20, 50, 33, 72, 10, 23, -1, 4]` using shell sort.
20+
21+
We start by dividing the length of the array by 2:
22+
23+
n = floor(9/2) = 4
24+
25+
This is the gap size.
26+
27+
We create `n` sublists. In each sublist, the items are spaced apart by a gap of size `n`. In our example, we need to make four of these sublists. The sublists are sorted by the `insertionSort()` function.
28+
29+
That probably didn't make a whole lot of sense, so let's look at what happens.
30+
31+
The first pass is as follows. We have `n = 4`, so we make four sublists:
32+
33+
list 0: [ 64, xx, xx, xx, 72, xx, xx, xx, 4 ]
34+
list 1: [ xx, 20, xx, xx, xx, 10, xx, xx, xx ]
35+
list 2: [ xx, xx, 50, xx, xx, xx, 23, xx, xx ]
36+
list 3: [ xx, xx, xx, 33, xx, xx, xx, -1, xx ]
37+
38+
As you can see, each list contains only every 4th item from the original array. The items that are not in a sublist are marked with `xx`. So the first list is `[ 64, 72, 4]` and the second is `[ 20, 10 ]`, and so on. The reason we use this "gap" is so that we don't have to actually make new arrays. Instead, we interleave them in the original array.
39+
40+
We now call `insertionSort()` once on each sublist.
41+
42+
This particular version of [insertion sort](../Insertion Sort/) sorts from the back to the front. Each item in the sublist is compared against the others. If they're in the wrong order, the value is swapped and travels all the way down until we reach the start of the list.
43+
44+
So for list 0, we swap `4` with `72`, then swap `4` with `64`. After sorting, this sublist looks like:
45+
46+
list 0: [ 4, xx, xx, xx, 64, xx, xx, xx, 72 ]
47+
48+
The other three sublists after sorting:
49+
50+
list 1: [ xx, 10, xx, xx, xx, 20, xx, xx, xx ]
51+
list 2: [ xx, xx, 23, xx, xx, xx, 50, xx, xx ]
52+
list 3: [ xx, xx, xx, -1, xx, xx, xx, 33, xx ]
53+
54+
The total array looks like this now:
55+
56+
[ 4, 10, 23, -1, 64, 20, 50, 33, 72 ]
57+
58+
It's not sorted yet but it's more sorted than before. This completes the first pass.
59+
60+
In the second pass, we divide the gap size by two:
61+
62+
n = floor(4/2) = 2
63+
64+
That means we now create only two sublists:
65+
66+
list 0: [ 4, xx, 23, xx, 64, xx, 50, xx, 72 ]
67+
list 1: [ xx, 10, xx, -1, xx, 20, xx, 33, xx ]
68+
69+
Each sublist contains every 2nd item. Again, we call `insertionSort()` to sort these sublists. The result is:
70+
71+
list 0: [ 4, xx, 23, xx, 50, xx, 64, xx, 72 ]
72+
list 1: [ xx, -1, xx, 10, xx, 20, xx, 33, xx ]
73+
74+
Note that in each list only two elements were out of place. So the insertion sort is really fast. That's because we already sorted the array a little in the first pass.
75+
76+
The total array looks like this now:
77+
78+
[ 4, -1, 23, 10, 50, 20, 64, 33, 72 ]
79+
80+
This completes the second pass. The gap size of the final pass is:
81+
82+
n = floor(2/2) = 1
83+
84+
A gap size of 1 means we only have a single sublist, the array itself, and once again we call `insertionSort()` to sort it. The final sorted array is:
85+
86+
[ -1, 4, 10, 20, 23, 33, 50, 64, 72 ]
87+
88+
The performance of shell sort is **O(n^2)** or **O(n log n)** if you get lucky. This algorithm produces an unstable sort; it may change the relative order of elements with equal values.
89+
90+
## The gap sequence
91+
92+
The "gap sequence" determines the initial size of the gap and how it is made smaller with each iteration. A good gap sequence is important for shell sort to perform well.
93+
94+
The gap sequence in this implementation is the one from Shell's original version: the initial value is half the array size and then it is divided by 2 each time. There are other ways to calculate the gap sequence.
95+
96+
## Just for fun...
97+
98+
This is an old Commodore 64 BASIC version of shell sort that Matthijs used a long time ago and ported to pretty much every programming language he ever used:
99+
100+
61200 REM S is the array to be sorted
101+
61205 REM AS is the number of elements in S
102+
61210 W1=AS
103+
61220 IF W1<=0 THEN 61310
104+
61230 W1=INT(W1/2): W2=AS-W1
105+
61240 V=0
106+
61250 FOR N1=0 TO W2-1
107+
61260 W3=N1+W1
108+
61270 IF S(N1)>S(W3) THEN SH=S(N1): S(N1)=S(W3): S(W3)=SH: V=1
109+
61280 NEXT N1
110+
61290 IF V>0 THEN 61240
111+
61300 GOTO 61220
112+
61310 RETURN
113+
114+
## See also
115+
116+
[Shellsort on Wikipedia](https://en.wikipedia.org/wiki/Shellsort)
117+
118+
[Shell sort at Rosetta code](http://rosettacode.org/wiki/Sorting_algorithms/Shell_sort)
119+
120+
*Written for Swift Algorithm Club by [Mike Taghavi](https://github.com/mitghi) and Matthijs Hollemans*

Shell Sort/README.md

-45
This file was deleted.

0 commit comments

Comments
 (0)