This is easily done with arrayLists, since an arrayList can change in
size. You will remember that the class ArrayList
defines
two methods called add
. One adds the argument it takes
to the end of the arrayList it is called on, but the other specifies
a position it is to go in. If we assume an arrayList is sorted, and we
want to insert a new item and keep it sorted, we can go through the items
in the arrayList one at a time until we find the first one which is not
less than the one being inserted. Then we insert the new item at that
position, which will cause the item already at that position and all the ones
following it to be moved up one place. This gives the following code for
insertion sort on an arrayList of integers:
public static ArrayList<Integer> sort(ArrayList<Integer> a) { ArrayList<Integer> b = new ArrayList<Integer>(); for(int i=0; i<a.size(); i++) insert(a.get(i),b); return b; } private static void insert(Integer n,ArrayList<Integer> a) { int i; for(i=0; i<a.size()&&a.get(i).compareTo(n)<0; i++) {} a.add(i,n); }Remember that the base type for
ArrayList
(as for any generic
type) must be an object type, so we use Integer
rather
than int
. We use the compareTo
method to
compare Integer
values. So if m
and n
are expressions of type Integer
(maybe variables, but maybe
method calls whose return type is Integer
) then
m.compareTo(n)
gives a negative value of type int
if m
represents an integer value less than that represented
by n
, a positive int
value if m
represents a value greater than n
, and 0
if
m
and n
represent the same integer value.
Note that the loop in the method insert
has to have
a conjunction of two tests. It has to check that the integer
indexed by the loop variable i
is less than the integer
n
to be inserted, which is done by
a.get(i).compareTo(n)<0
. It also has to check that the loop
index is less than the size of the arrayList. If the loop index is equal to the
size of the arrayList, it means we have gone through the whole arrayList and
even the last item is less than the item to be inserted, so we insert
the new item at the end. In that case, i<a.size()
is
false
and the test a.get(i).compareTo(n)<0
is never tried because of the "short circuit" effect of the &&
operator. That is why the i<a.size()
test has to come first,
because if i
has reached the value of a.size()
then
calling a.get(i)
will throw an IndexOutOfBoundsException
.
When writing code you always need to consider if there are any special cases
which need careful dealing with, such as this case where inserting an
item in an ordered happens to mean inserting it after all other items
in the collection because all other items are smaller.
There are three files in the directory ~mmh/DCS128/code/sort
which have exactly the same code for the sorting algorithm, but which
differ in the support code to demonstrate it. In
InsertSort1.java,
the user is prompted to type in numbers to be sorted. In
InsertSort2.java,
the user is only asked for the number of numbers and the highest possible
number. Then random numbers are generated within this range, but the numbers
are printed before and after sorting. In
InsertSort3.java,
the numbers are generated randomly as before, but they are not printed;
they are still sorted but only the time taken to sort them is printed.
This enables you to test the code with your own numbers, then test it
with so many numbers that it would be tedious to type that many yourself
but they are still displayed so you can see the code works, then to test
it with so many numbers that it would be impractical to display them.
The issue of efficiency is something we will deal with later. In practice, computer programs often have to deal with large amounts of data, much more than you could type by hand or display on one screen. Differences of efficiency between different algorithms become much more apparant when they are run with large amounts of data. So it's important to test code on large amounts of data.
Note that while testing code by running it with data and observing the results
is an important part of software development, we can also analyse algorithms
mathematically to prove they work correctly and to find out their
efficiency. Although the emphasis in this course is on programming
algorithms, the scientific study of algorithms is much more concerned
with mathematical analysis of them then on coding issues.
Insertion sort in place
Destructive sorting of a collection involves moving the items from their
original locations to new locations in the collection rather than
constructing a new sorted collection. Another name for this
destructive sorting is sorting in place. Destructive insertion
sort works like constructive insertion sort by going through the
collection one item at a time and inserting it in place. However,
instead of inserting the item into a new collection, it works by
having part of the collection holding sorted data, and the rest unsorted.
As each item is gone through in the unsorted data it is inserted into the
sorted data with the portion of the data which is sorted growing until
it becomes all of it.
The method for insertion sort in place of an arrayList of integers is:
public static void sort(ArrayList<Integer> a) { for(int i=1; i<a.size(); i++) insert(a.get(i),a,i); }At the start of each execution of the loop body, the portion of the arrayList up to but not including that component indexed by
i
is sorted. The call of insert(a.get(i),a,i)
in the loop
body takes the component indexed by i
and inserts it
into the sorted part. It does this by moving up one place all those
items in the sorted part which are greater than the item indexed by
i
, then putting the item which was indexed by i
in its place. This makes the code for insert
:
private static void insert(Integer n,ArrayListThis is best illustrated using an example shown by a diagram. Suppose we want to sort the following arrayList:a,int i) { for(; i>0&&a.get(i-1).compareTo(n)>0; i--) a.set(i,a.get(i-1)); a.set(i,n); }
When the loop body in the sort
method has been executed
five times, leaving i
with the value 6
, the
arrayList will be:
The bar through it indicates the division between the sorted part and
the unsorted part. The method insert
is executed
in an environment where n
is set to a.get(i)
,
which is 28
, and there is a local variable i
set
to the value of i
in the environment for sort
,
which is 6
, and a
refers to the same arrayList.
Diagrammatically, the situation is:
After the loop in the insert
method has been
executed, the items in the sorted part of the arrayList which are
greater than 28
will have neen "moved up" one place,
making the situation:
with the local variable i
in the environment for the call
to insert
having its value changed to 3
. Then,
executing a.set(i,n)
sets the arrayList to:
where the bar again indicates the division between a sorted and unsorted
part, and you can see it has moved up one place. When execution returns
to the environment for the sort
method call, the contents
of the arrayList referred to by a
will have been changed
in this way. The loop on the sort
call finishes when its
i
variable has as its value the size of the arrayList,
indicating that now all of it has been sorted.
Since this algorithm for sorting an arrayList in place does not change the size of the arrayList at any time, the same algorithm can be used to sort an array in place. The code for this is:
public static void sort(Integer[] a) { for(int i=1; i<a.length; i++) insert(a[i],a,i); } private static void insert(Integer n,Integer[] a,int i) { for(; i>0&&a[i-1].compareTo(n)>0; i--) a[i]=a[i-1]; a[i]=n; }Full code for sorting an arrayList in place can be found in the files InsertSort4.java and InsertSort5.java, in the first case with randomly generated numbers which are displayed, in the second with randomly generated numbers and only timing figures, no display. Similarly, full code and supporting code for demonstrating for sorting in place of an array can be found in InsertSort6.java and InsertSort7.java.
The algorithm for selection sort works by first finding the lowest item in the original array and swapping that in position with the item in the first indexed component of the array. Then the lowest item in the remainder of the array (i.e. the second lowest item in the whole array) is found and swapped in position with the item in the second indexed component of the array. Then the lowest item in the portion of the array starting at the third indexed position is found and swapped with the item at the third indexed position, and so on. Here is the code to do that:
public static void sort(Integer[] a) { for(int i=0; i<a.length-1; i++) { int pos = findMinPos(a,i); swap(a,i,pos); } } private static int findMinPos(Integer[] a,int pos) { for(int i=pos+1; i<a.length; i++) if(a[i].compareTo(a[pos])<0) pos=i; return pos; } private static void swap(Integer[] a,int pos1,int pos2) { Integer temp = a[pos1]; a[pos1]=a[pos2]; a[pos2]=temp; }Here the method
findMinPos
with arguments
a
and pos
returns the position
of the smallest item in the portion of array a
starting with the component indexed by pos
.
The method swap
with arguments a
,
pos1
and pos2
changes the array
a
destructively by swapping round the item at
position pos1
with the item at position pos2
.
Code for selection sort of arrays of integers can be found in the files SelSort1.java SelSort3.java and SelSort5.java. In the first case there is supporting code for the numbers to be sorter to be typed in, in the second they are generated randomly and displayed, in the third they are generated randomly and only timing figures are given. In SelSort2.java SelSort4.java and SelSort6.java selection sort is similarly applied to an array of strings. You will also need the file WordGen.java which randomly generates pronounceable words. The code for selection sort of an array of strings is:
public static void sort(String[] a) { for(int i=0; i<a.length-1; i++) { int pos = findMinPos(a,i); swap(a,i,pos); } } private static int findMinPos(String[] a,int pos) { for(int i=pos+1; i<a.length; i++) if(a[i].compareTo(a[pos])<0) pos=i; return pos; } private static void swap(String[] a,int pos1,int pos2) { String temp = a[pos1]; a[pos1]=a[pos2]; a[pos2]=temp; }As you can see, it is exactly the same as the code for selection sort of an array of integers, apart from the type
String
used where Integer
was used before. The reason it
would not be possible to write a simple generic version with a
type variable replacing String
and Integer
is the call to compareTo
in the method findMinPos
.
Only some types may have the method compareTo
called on
them, so we cannot call it on an object where we know nothing about
its type, which is the case with type variables as we have seen them
up till now. Later we will see a way round this, but for now we will
give code for sorting algorithms in terms of sorting collections of
integers.
If we use the same example as before, sorting the array which starts out
as [30,25,47,99,8,12,23,63,16,20]
, the lowest item in the whole
array is found and swapped with the first item, giving
[8,25,47,99,30,12,23,63,16,20]
. Then the lowest item in the
rest of the array is found and swapped with the item in the second position,
giving [8,12,47,99,30,25,23,63,16,20]
. Following each
step in the algorithm, the successive steps in the transformation of
the array are:
[30,25,47,99,8,12,23,63,16,20] [8|25,47,99,30,12,23,63,16,20] [8,12|47,99,30,25,23,63,16,20] [8,12,16|99,30,25,23,63,47,20] [8,12,16,20|30,25,23,63,47,99] [8,12,16,20,23|25,30,63,47,99] [8,12,16,20,23,25|30,63,47,99] [8,12,16,20,23,25,30|63,47,99] [8,12,16,20,23,25,30,47|63,99] [8,12,16,20,23,25,30,47,63|99] [8,12,16,20,23,25,30,47,63,99]with the
|
character used to indicate the
division between the sorted portion and the unsorted portion.
Selection sort may be applied to an arrayList as well, the
only difference with its application to arrays being the use
of method calls rather than the special array syntax. Here is
the code for selection sort on an object of type
ArrayList<Integer>
:
public static void sort(ArrayList<Integer> a) { for(int i=0; i<a.size()-1; i++) { int pos = findMinPos(a,i); swap(a,i,pos); } } private static int findMinPos(ArrayList<Integer> a,int pos) { for(int i=pos+1; i<a.size(); i++) if(a.get(i).compareTo(a.get(pos))<0) pos=i; return pos; } private static void swap(ArrayList<Integer> a,int pos1,int pos2) { Integer temp = a.get(pos1); a.set(pos1,a.get(pos2)); a.set(pos2,temp); }The files SelSort7.java and SelSort8.java give code for selections sort on arrayLists of integers, together with supporting code.
Last modified: 3 August 2005