-------------------------------------------------------------------------------

    public static void bubbleSort(int data[], int n)
    // pre: 0 <= n <= data.length
    // post: values in data[0..n-1] in ascending order
    {
	for (int numSorted = 0; numSorted < n; numSorted++)
	{
	    // bubble a large element to higher array index
	    for (int index = 1; index < n-numSorted; index++)
	    {
		if (data[index-1] > data[index])
		    swap(data,index-1,index);
	    }
	}
    }

-------------------------------------------------------------------------------

    public static void selectionSort(int data[], int n)
    // pre: 0 <= n <= data.length
    // post: values in data[0..n-1] are in ascending order
    {
	for (numUnsorted = n; numUnsorted > 0; numUnsorted--)
	{
	    // determine maximum value in array
	    int max = 0;
	    for (int index = 1; index < numUnsorted; index++)
	    {
		if (data[max] < data[index]) max = index;
	    }
	    swap(data,max,numUnsorted-1);
	}
    }

-------------------------------------------------------------------------------

    public static void insertionSort(int data[], int n)
    // pre: 0 <= n <= data.length
    // post: values in data[0..n-1] are in ascending order
    {
	for (int numSorted = 1; numSorted < n; numSorted++)
	{
	    // take the first unsorted value
	    int temp = data[numSorted];
	    // ...and insert it among the sorted:
	    for (int index = numSorted; index > 0; index--)
	    {
		if (temp < data[index-1])
		{
		    data[index] = data[index-1];
		} else {
		    break;
		}
	    }
	    // reinsert value
	    data[index] = temp;
	}
    }

-------------------------------------------------------------------------------

    public static void mergeSort(int data[], int n)
    // pre: 0 <= n <= data.length
    // post: values in data[0..n-1] are in ascending order
    {
	mergeSortRecursive(data,new int[n],0,n-1);
    }
	
    private static void mergeSortRecursive(int data[], int temp[], 
					   int low, int high) {
	int n = high-low+1;
	int middle = low + n/2;
	int i;

	if (n < 2) return;
	// move lower half of data into temporary storage
	for (i = low; i < middle; i++)
	{
	    temp[i] = data[i];
	}
	// sort lower half of array
	mergeSortRecursive(temp,data,low,middle-1);
	// sort upper half of array
	mergeSortRecursive(data,temp,middle,high);
	// merge halves together
	merge(data,temp,low,middle,high);
    }
	
    private static void merge(int data[], int temp[],
			      int low, int middle, int high)
    // pre: data[middle..high] are ascending
    //      temp[low..middle-1] are ascending
    // post: data[low..high] contains all values in ascending order
    {
	int ri = low; // result index
	int ti = low; // temp index
	int di = middle; // destination index
	// while two lists are not empty merge smaller value
	while (ti < middle && di <= high)
	{
	    if (data[di] < temp[ti]) {
		data[ri++] = data[di++]; // smaller is in high data
	    } else {
		data[ri++] = temp[ti++]; // smaller is in temp
	    }
	}
	// possibly some values left in temp array
	while (ti < middle)
	{
	    data[ri++] = temp[ti++];
	}
	// ...or some values left (in correct place) in data array
    }

    public static void swap(int data[], int i, int j)
    // pre: 0 <= i,j < data.length
    // post: data[i] and data[j] are exchanged
    {
	int temp;
	temp = data[i];
	data[i] = data[j];
	data[j] = temp;
    }