SORTING with the Shell Sort
By: Eric Guevara
ICS 211 [Section 3]
04.24.2002

We use computer programs almost on a daily basis to perform all kinds of tasks from word processing to video games. Computer programs are basically made up of algorithms and abstract structures like an Array to hold data. Algorithms are like a recipe for preparing a dish. They are a set of instructions written in programming languages like c/c++ or Java that are performed in a certain order to achieve a function like searching for a file on your disk and deleting it. There are many functions that go on behind the screen that we don’t really care about. But these functions are really important in transforming the information in the ways that we want to see them. To display information how we want to see it often calls upon functions to calculate, sort, and search before the information is displayed. The function that you will see here is sorting.

The sorting process goes on in many computer applications that we use. It goes on internally within the computers RAM or slower externally on disks or tape. Sorting arranges data in either ascending or descending order. You can see this function applied in spread sheet, database, and jukebox programs where names and songs are organized alphabetically or by types. Many times, in programs and programming a search function is also used. In some search algorithms particularly the binary search algorithm, data must be sorted in order for the binary search to work correctly. So you can see that sorting is an important function because it allows us to organize information and helps us to find things faster. There are many sorting algorithms that are used in programs. Some are the selection sort, bubble sort, insertion sort, shell sort, merge sort, radix sort and quick sort. I am not going over all of these sorting algorithms but I will go over the shell sort.

Before going over the shell sort I will briefly describe the insertion sort because it is after all, the basis of the shell sort. How do you sort an array with an insertion sort? Take a look at Figure 1.0. Initially, when sorting an array with the insertion sort the element in the second index (i1) or the 2 that is highlighted will be selected first. So in the array 10,2,6,0 the 2 is selected first and is compared to the first element to the left which is 10. Now since 2 is less than 10 it is inserted into the 10s index and the 10 is moved up to the place that 2 was in. The array now becomes 2,10,6,0. Next, the initial index is incremented by 1 to index 2 and the 6 is selected to be compared to the sorted elements to the left. The elements to the left of the highlighted one are sorted and the elements to tbe right are unsorted. So now the 6 is compared to the 2 and 10. It is less than 10 so it is inserted into 10s position and the 10 is moved up. This continues until the last element is compared to the sorted elements and inserted into the correct position.

Figure 1.0
Using insertion sort on an array

Index>>

i0

i1

i2

i3

10

2

6

0

<< unordered array

10

2

6

0

2

10

6

0

2

6

10

0

0

2

6

10

<< sorted array

How well does the insertion sort perform? The insertion sorts growth rate is a Big O of n^2. The Big O helps to express the time it takes for a set of n items to be sorted and helps in determining the efficiency of an algorithm. This is a fast growth rate. The faster the growth rate the more time it takes to sort and the slower the growth rate the faster and more efficient the algorithm. So the closer the Big O of an algorithm is to n the better it is. According to Carrano and Prichard the authors of Data Abstraction and Problem Solving with JAVA, insertion sort is efficient if you are sorting a small array with 25 or less items. And it is inefficient if you are sorting a large array. (Carrano 393)

Since the insertion sort algorithm wasn’t that efficient with large amounts of numbers and had a decent Big O someone thought that they could improve on it. So in 1959 one person invented a new way of sorting. That person who refined the insertion sort was Donald L. Shell. Thus, the shell sort was created. The shell sort can be described as an in-place diminishing increment sort because of the way it works. The shell sort is an in-place sort because the items that are sorted occupy the same storage as the original items. It is described as a diminishing increment sort because it starts out with a certain increment number that reduces by half on each sorting pass until the increment reaches 1.

How does the shell sort work? The shell sort is based on the insertion sort. So the concept in shell sorting is to perform an insertion sort, but this time the insertion sort is used more efficiently. It is used efficiently by doing an insertion sort in the fashion of a diminishing increment sort so that it sorts less numbers at time. For an example to help understand this better see Figure 1.2.

Figure 1.2
Shell sort on an array

7

4

5

1

8

9

0

6

<<Unsorted Array

^

^

Sort by 4s

7

4

5

1

8

9

0

6

^

^

7

4

5

1

8

9

0

6

^

^

7

4

0

1

8

9

5

6

^

^

7

4

0

1

8

9

5

6

^

^

^

^

Sort by 2s

0

4

5

1

7

9

8

6

^

^

^

^

0

1

5

4

7

6

8

9

^

^

^

^

^

^

^

^

Sort by 1s

0

1

4

5

6

7

8

9

<<Sorted Array

In the example above an initial increment of 4 is used though others can be used depending on the number of items. So we start out with an unsorted set of numbers: 7,4,5,1,8,9,0,6. Since the increment is 4 the spacing in between the numbers being compared is 4. In the first step the first numbers to be sorted would be 7 and 8. So 7 and 8 are sorted by the insertion sort, but in this case they are already in order so the next two are insertion sorted. The next two are 4 and 9. Again the two are already in order so the next two, which are 5, and 0 are insertion sorted. 0 is less than 5 so by insertion sort the two switch positions. Now the last two, 1 and 6 are sorted already so since all positions were sorted by 4’s, the increment is reduced by half and the array is now sorted by 2’s. The array now looks like 7,4,0,1,8,9,5,6. The same process as in sorting by 4’s is done but this time the spacing is by 2. So the numbers involved in the insertion sort now are 7,0,8,and 5. After the sort, the next set, which is 4, 1, 9, and 6 are sorted. Now all positions were sorted by 2’s and the array looks like 0,1,5,4,7,6,8,9. Lastly the array is sorted by 1’s and a regular insertion sort is done on the array. Only 4, 5, 6, and 7 had to switch positions. Although it may seem like more work is being done by the shell sort in contrast to the insertion sort there are fewer rearrangements because at each new diminishing increment the items are already ordered well.

Different initial increments should be used for different amounts of data. Below is the method of determing the optimal initial increment from [website].

Knuth recommends a technique, due to Sedgewick, that determines spacing h based on the following formulas:

hs = 9·2^s - 9·2^s/2 + 1, if s is even
hs = 8·2^s - 6·2^(s+1)/2 + 1, if s is odd

These calculations result in values (h0,h1,h2,…) = (1,5,19,41,109,201,…). Calculate h until 3ht >= N, the number of elements in the array. Then choose ht-1 for a starting value. For example, to sort 150 items, ht = 109 (3·109 >= 150), so the first spacing is ht-1, or 41. The second spacing is 19, then 5, and finally 1. (Niemann)

The shell sort algorithm is categorized in the Big O(n^2) category along with the insertion sort, bubble sort, and selection sort but it is the faster and more efficient of the four. It may be the better of that bunch but it is not as efficient as the merge sort and quick sort. Most sources say that it is a very complex algorithm and it’s Big O varies depending on the increment used. But the average is O(n^1.2) and the worst case scenario is Big O(n^1.3).

Sample Shell Sort Code:

/*
 * @(#)ShellSortAlgorithm.java	1.1 2000/04/12 Jason Harrison
 *
 * Copyright (c) 1995 University of British Columbia
 *
 * Permission to use, copy, modify, and distribute this software
 * and its documentation for NON-COMMERCIAL purposes and without
 * fee is hereby granted provided that this copyright notice
 * appears in all copies. Please refer to the file "copyright.html"
 * for further important copyright and licensing information.
 *
 * UBC MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
 * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
 * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
 * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. UBC SHALL NOT BE LIABLE FOR
 * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
 * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
 */

/**
 * A shell sort demonstration algorithm
 * SortAlgorithm.java, Thu Oct 27 10:32:35 1994
 * Note: Invented by Donald Lewis Shell [CACM, July, 1959, pages 30-32]
 * @author Jason Harrison@cs.ubc.ca
 * @version 	1.0, 23 Jun 1995
 * @version 	1.1, 12 Apr 2000
 *              -- fixed java.lang.ArrayIndexOutOfBoundsException
 *                 Joel Berry <jmbshifty@yahoo.com> found this bug
 */

/* http://www.auto.tuwien.ac.at/~blieb/woop/shell.html
 *
 * Shellsort is a simple extension of insertion sort which gains speed
 * by allowing exchanges of elements that are far apart. The idea is
 * to rearrange the array to give it the property that every hth
 * element (starting anywhere) yields a sorted array. Such an array
 * is said to be h-sorted.
 *
 * By h-sorting for some large values of h, we can move elements in
 * the array long distances and thus make it easier to h-sort for
 * smaller values of h. Using such a procedure for any sequence of
 * values h which ends in 1 will produce a sorted array.
 */

class ShellSortAlgorithm extends SortAlgorithm {
    void sort(int a[]) throws Exception {
	int h = 1;
        /*
         * find the largest h value possible
         */
        while ((h * 3 + 1) < a.length) {
	    h = 3 * h + 1;
	}

        /*
         * while h remains larger than 0
         */
        while( h > 0 ) {
            /*
             * for each set of elements (there are h sets)
             */
            for (int i = h - 1; i < a.length; i++) {
                /*
                 * pick the last element in the set
                 */
                int B = a[i];
                int j = i;
                /*
                 * compare the element at B to the one before it in the set
                 * if they are out of order continue this loop, moving
                 * elements "back" to make room for B to be inserted.
                 */
                for( j = i; (j >= h) && (a[j-h] > B); j -= h) {
                    if (stopRequested) {
		        return;
                    }
                    a[j] = a[j-h];
		    pause(i,j);
                }
                /*
                 *  insert B into the correct place
                 */
                a[j] = B;
	        pause(j);
            }
            /*
             * all sets h-sorted, now decrease set size
             */
            h = h / 3;
        }
    }
}

See sorting algorithms in action here.

Bibliography

Carrano, Frank M., and Prichard, Janet J. Data Abstraction and Problem Solving with JAVA
    Addison Wesley Longman Inc., 2001.

Wirth, Niklaus. Algorithms and Data Structures.
    New Jersey: Prentice-Hall Inc., 1986

Chen, Yin-So. Shell Sort. 13 Sep. 1999. <http://www.gamedev.net/reference/articles/article702.asp>

Niemann, Thomas. Sorting and Searching Algorithms. Shell Sort. 20 Apr. 2002.
<http://epaperpress.com/sortsearch/shl.html>

<<Home