In order to concentrate on basic sorting, we will discuss
sorting arrays of integers. Even here, we need to express the order in
which we are sorting the array of integers. We cannot sort anything without
having the concept of an order over the data items we are sorting. It might
seem obvious that sorting an array of integers means sorting into the
arrangement with the lowest integer first, the second lowest second, and so
on. But this is sorting in "ascending numerical order". Thinking about this,
it's obvious we could also sort in "descending numerical order" (highest
first). It requires a little more thought to think of other orders on
numbers. What about sorting "in order of closeness to 100", so 95 comes
before 108 but after 102, for example? Or "sorting in ascending order of
the number of prime factors", so that 285 (3×5×19) comes before
210 (2×3×5×7) but after 221 (13×17)? For simplicity,
we will assume for the present that "sorting an array of integers" means
sorting it in ascending numerical order.
An Iterative Sorting Algorithm
The following sorting algorithm, called selection sort, uses
iteration. Its main advantage is that it is simple to explain and fairly
intuitive:
Find the position of the smallest item in the array, swap that item
with the first item in the array.
Find the position of the smallest item in the portion of the array apart
from the first element, swap that item with the second item in the
array.
Find the position of the smallest item in the portion of the array apart
from the first and second elements, swap that item with the third item in
the array.
And so on until we are looking at just the last two items in the array.
Now the array is sorted.
As an example, consider the following array:
After the first step of the algorithm, the 2 will be swapped with the 5, since 2 is the smallest integer in the array. This gives the situation:
As 2 is the smallest integer in the array, it is now in its correct position for the array with its elements rearranged so as to be sorted in ascending numerical order. The next step swaps the 3 with the 9, giving:
The vertical line through the array here indicates that at this point in the algorithm, the array can be considered divided into two parts, the part to the left of the line which stores the elements in their orders and places for the final arrangement of the array, and the part to the right, which contains the remaining elements of the array in no particular order. Each step in the algorithm moves the line one space to the right, so the next step (swapping 7 and 4) gives:
The next step involves finding the smallest element in the part of the array to the right of the line, and swapping it with the first element to the right of the line. As it happens, the smallest element to the right of the line is the first element to the right of the line, so it is "swapped with itself", in other words no change. However, moving to the next step of the algorithm can be considered as moving the line on, giving:
The next step swaps the 7 with the 6, giving:
The step after that swaps the 7 with the 9, giving:
Now everything to the left of the line is its place for the final sorted form of the array, and there is only one integer to the right of the line, which must be the highest integer, so the whole array is sorted.
In this case, there is a slight trickiness involved because the
algorithm doesn't actually return anything. It acts by changing the
values in the array which is passed to it as an argument rather than
by creating a new array and returning it. So its return type is given
as void
meaning "nothing returned". As we are dealing with
arrays of integers, the type of the method's argument is int[]
.
In short general purpose methods dealing with arrays, it's conventional
to name the array just a
, which we shall do so here. However,
you should be aware that it is good programming practice when writing
methods for more specific purposes to use meaningful variable names,
and avoid one-letter variable names. We now have the following signature for
the method:
public static void sort(int[] a)It is declared as
static
because we assume this method will be called
on its own and not attached to some object.
Looking at the algorithm, we can see there is a general pattern, and
we need to express this in terms of a loop. On each step round the loop,
we look for the smallest element in that portion of the array from the
i
th element to the last element in the array, and we swap
that element with the i
th element. This gives us the
following for the partially developed code:
public static void sort(int[] a) { for(int i=0; i<a.length-1; i++) { int pos = position of smallest element in array from position i swap ith position of array with posth position of array } }Again, while one-letter variable names should mostly be avoided, it's a common convention that a variable used as an index to an array is called
i
, or if that variable name has already been used to index
another array, j
, in circumstances where the piece of code
where the variable is used is not very long and there's no particular
meaning to the variable except that it's an array index.
The parts in italics above indicate where what is written needs
further developing until it becomes Java code. One easy way of dealing
with this is to make it calls to new Java methods which do the required
work, this then leaves us with the separate issue of writing the code
for the new Java methods. The methods are declared as private
because they are introduced only to help us develop our sort
method, so there is no need to make them available to anyone else. We also
add comments describing what each method does, giving is:
public static void sort(int[] a) // Sort the contents of array a in ascending numerical order { for(int i=0; i<a.length-1; i++) { int pos = smallestPosFrom(i,a); swap(a,i,pos); } } private static int smallestPosFrom(int from,int[] a) // Return the index of the smallest element in the section of // array 'a' from that indexed 'from' to the end of the array private static void swap(int[] a,int pos1, int pos2) // Swap the elements indexed pos1 and pos2 within array aHere,
swap
, like sort
works by changing the
array it takes as an argument, so its return type is void
.
What we need to do is change the values stored in the array cells, so
that after a call to the method a[pos1]
stores what
a[pos2]
stored before, and a[pos2]
stores
what a[pos1]
stored before. We can't just do this by:
a[pos1] = a[pos2]; a[pos2] = a[pos1];because the first assignment here will copy what is in
a[pos2]
into a[pos1]
, thus losing the old value of a[pos1]
altogether, leaving us with two copies of what was originally in
a[pos2]
. So the correct code for the method swap
employs a local variable to act as a temporary storage for the old value
of a[pos1]
so this can be copied into a[pos2]
:
private static void swap(int[] a,int pos1, int pos2) // Swap the elements indexed pos1 and pos2 within array a { int temp; temp = a[pos1]; a[pos1] = a[pos2]; a[pos2] = temp; }When considering
smallestPosFrom
, it is important to note
that it returns the index of the smallest integer in the
section of the array starting at the i
th element, and
not the smallest integer itself. A common source of errors when dealing
with arrays of integers is to confuse the integers stored in the arrays
with the integers used to index the arrays. The algorithm to find
the smallest integer in the section of the array starting at the
i
th element requires a local variable which stores
the index of the smallest element found so far, which is initially
i
, but is replaced by the index of smaller elements as they are
found. Here's the code:
private static int smallestPosFrom(int from,int[] a) // Return the index of the smallest element in the section of // array 'a' from that indexed 'from' to the end of the array { int pos=from; for(int i=from+1; i<a.length; i++) if(a[i]<a[pos]) pos=i; return pos; }The loop invariant here is that the variable
pos
is
set such that a[pos]
is the smallest integer in the section of
array a
between and including position from
and up to but not including position i
. This holds at the
start of the loop, since then i
is from+1
,
so there is only integer in the section, so it must be the lowest,
and pos
set to from
indexes it. At any time
round the loop, if this loop invariant is true, then either the next
integer in the array is smaller than the one indexed by pos
in which case pos
is changed to index that integer, so the
loop invariant continues to hold after i
is increased by
1, or the next integer in the array is not smaller than a[pos]
,
so the loop invariant still holds after i
is increased by 1.
When the loop finishes, i
must have the value
a.length
, and as the loop invariant must hold, pos
must be the index of the smallest integer in the section of array
a
starting at position from
and continuing to the
end of the array.
As a minor point, the names of the variables in the comment to the
method smallestPosFrom
are surrounded by single quotes. This
is to avoid confusion between the word "from" and the variable name
from
.
main
method which enables it to be tested from Linux:
import java.io.*; class SortIntArrayIt1 { public static void main(String[] args) throws IOException { int n; int[] array; BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); System.out.print("Enter number of integers : "); n = Integer.parseInt(in.readLine()); array = new int[n]; for(int i=0; i<n; i++) { System.out.print("Enter integer "+i+": "); array[i] = Integer.parseInt(in.readLine()); } System.out.println("The array you entered is:"); System.out.println(arrayToString(array)); sort(array); System.out.println("After sorting, the array is:"); System.out.println(arrayToString(array)); } private static String arrayToString(int[] a) { String str="["; if(a.length>0) { str+=a[0]; for(int i=1; i<a.length; i++) str+="|"+a[i]; } return str+"]"; } public static void sort(int[] a) // Sort the contents of array a in ascending numerical order { for(int i=0; i<a.length-1; i++) { int pos = smallestPosFrom(i,a); swap(a,i,pos); } } private static int smallestPosFrom(int from,int[] a) // Return the index of the smallest element in the section of // array 'a' from that indexed 'from' to the end of the array { int pos=from; for(int i=from+1; i<a.length; i++) if(a[i]<a[pos]) pos=i; return pos; } private static void swap(int[] a,int pos1, int pos2) // Swap the elements indexed pos1 and pos2 within array a { int temp; temp = a[pos1]; a[pos1] = a[pos2]; a[pos2] = temp; } }The variable referring to the array in the
main
method
is called array
. This is permissible in Java, because the
word array
is not reserved as a key-word, so can be
used as a variable name. It is necessary to ask in advance how many
integers will be in the array, since when an array object is created in
Java you have to declare the number of elements in it, and that number
can't be changed. However, an array variable can refer to arrays of
any size, so the size of the array is fixed when the program is run
(run-time) and not when the program is written and compiled (compile-time).
In order to be able to display the array, a separate method which takes
an array of integers and returns a string, called arrayToString
is given. The string will consist of the characters for the numbers of the
array in the order they are in the array, separated by commas, and with
square brackets surrounding the whole. You cannot expect Java to "know"
how to display an array of integers. Making the code to display an
array into a separate method helps break down the code to easily understood
small parts, and enables this code to be re-used, first to display the
original array, then to display the array after it is sorted. It is
more flexible, and in keeping with the way Java does things, for the
method to return a string which can be printed than for it to do the
printing itself.
For comparison, below is a version of the sort
method
in which the code for the algorithm is run together into one method
rather than spread across several methods:
public static void sort(int[] a) // Sort the contents of array a in ascending numerical order { for(int i=0; i<a.length-1; i++) { int temp,pos=i; for(int j=i+1; j<a.length; j++) if(a[j]<a[pos]) pos=j; temp = a[i]; a[i] = a[pos]; a[pos] = temp; } }This is just another way of expressing the same algorithm. Because the code isn't broken up into methods with meaningful name, it's harder when looking at it to understand what it is doing. It would, however, be a little more efficient when run because the overhead involved in making large numbers of method calls has gone. It is a matter of judgement when to separate out a piece of code into another method. If doing so enables you to re-use the code in the method by calling that method more than once, it's generally a good idea, which will save you time when writing the code or if you ever have to make changes to it. Otherwise, it is a matter of balancing understandibility with efficiency. As you get more used to Java you may feel more at ease writing code with more complex loops within loops, as the second form of
sort
above. However, experts suggest that a good rule of
thumb is that a single method should never be so long that it can't
be viewed completely in one go on the computer screen. If your method
becomes that long it would be a good idea to consider breaking it
down by putting some of the code into subsidiary helper methods.
The method
sort
had return type void
, but the
array the variable passed to it as an argument referred to was changed.
To consider how this works, remember if a
and b
are of object types (anything except the primitive types, including
all arrays even if the contents of the array are of a primitive type),
then the assignment a=b
doesn't make a copy of what
b
refers to and make a
refer to that, rather
it makes a
refer to the same object that b
refers to. So if you change the object a
refers to, the
object b
refers to is also changed, and so on, because
they are the same thing. This can be shown diagramatically with the
variables having pointers to the object:
a
and b
happen to be of some array type,
then a=b
will mean a
and b
are
two different names for the same array, so:
int[] a, b; some code which sets b to refer to an array object a=b;will result in the following situation:
where the numbers are given just as an illustration of what could be in the array object. Note that the arrows here, representing variables referring to an object, should be considered as pointing to the whole array object, not to the particular cell where the arrow head happens to be. Java (unlike C) doesn't have the concept of a variable referring to a particular part of an array.
Assuming the numbers as in the diagram above, then executing
a[2]=1;will cause the situation to change to:
In other words, b[2]
is changed to 1 as well as a[2]
because a
and b
are two names for the same
array object, so a[2]
and b[2]
are exactly
the same thing (the same store location, not two separate store locations
that both happen to hold 6).
When in the main
method above we make the call
sort(array);a similar sort of thing happens. The effect when we start executing the call is as if we executed
a=array
(remember a
is the parameter name in the method sort
), except that
array
is a name used in the main
method, and
a
a name used in the sort
method. However, they
refer to the same array, so using our previous example, we have:
So when the code for method sort
changes a[i]
for some i
, the value of array[i]
for that
same i
is changed, because they are the same thing.
Note that while the change in the value of an array in a method passes through to the code that called that method, the change in the value of a primitive won't. Suppose we have a method written:
private static void swapvals(int m, int n) { int temp; temp=n; n=m; m=temp; }You may be tempted to think that the code:
int u,v; u=5; v=8; System.out.println(u+" "+v); swapvals(u,v); System.out.println(u+" "+v);will cause
5 8 8 5to be printed, because
swapvals(u,v)
would swap round
the values in u
and v
. Actually, it
won't. This is because if a
and b
are
variables of primitive type (such as int
), then
a=b
causes the value that is in variable b
to be copied into variable a
, but no connection
between a
and b
is established:
So when swapvals(u,v)
is called, it as as if:
m=u; n=v;is executed before the code for
swapvals
is
executed. This will result in the situation:
When this is followed by the code in method swapvals
it
results in the situation:
So the values in u
and v
are unaffected.
Executing the code:
int m,n; m=5; n=8; System.out.println(m+" "+n); swapvals(m,n); System.out.println(m+" "+n);makes no difference, as the variables names
m
and
n
inside the execution of swapvals
are
different variables (albeit with the same names) from the variables
outside. The situation at the end of the code for swapvals
is:
Then when swapvals
finishes executing, its local variables
disappear, and we go back to the old set of variables where
m
still holds value 5 and n
still holds value 8.
Last modified: 22 January 2004