0

I'm doing an assignment for my Data Structures class and I can't figure out why my Insertion Sort is much faster than my merge sort. I have posted 2 version one with he fast insertion sort code and one with the slow version I discovered later. My professor was really surprised and said I understood it well. I believe its because I avoided a time consuming task, but I did this unintentionally and I'm still trying to learn time complexity so it's confusing me.

(Slow version)

package sorting; 

import java.util.*;

public class Sort {

    public static int[] insertion_sort (int[] array) {

    int i;

        for (int j = 1; j < array.length; j++) {
            int key = array[j-1];  // assigns the key to the first value of the array  

            i = j-1; // i is always one less than j

            while (i >0 && array[i] > key) {
                array[i+1] = array[i];
                i = i -1;
            }
                array[i+1] = key;
        }



        return array;
    }

    public static int[] merge_sort (int[] array, int p, int r) {

        if (p < r) {
            int q = (p + r) /2;
            Sort.merge_sort(array, p, q);
            Sort.merge_sort(array, q+1, r);
            Sort.merge(array, p, q, r);
        }

        return array;
    }

    public static int[] merge (int[] array, int p, int q, int r) {
        int n1  = q - p +1;
        int n2 = r - q;
        int[] L = new int[n1+1];
        int[] R = new int [n2+1];

        for (int i = 0; i < n1; i++) {
            L[i] = array[p+i];

        }

        for (int j = 0; j <n2; j++) {
            R[j] = array[q+j+1];
        }

        L[n1] = Integer.MAX_VALUE;
        R[n2] = Integer.MAX_VALUE;

        int i = 0; 
        int j = 0;

        for (int k = p; k<= r; k++) {
            if (L[i] <= R[j]) {
                array[k] = L[i];
                i++;
            }

            else {
                array[k] = R[j];
            }
        }
        return array;
    }

    /*
     * n: the size of the output array
     * k: the maximum value in the array
     */
    public static int[] generate_random_array (int n, int k) {
        List<Integer> list;
        int[] array;
        Random rnd;

        rnd = new Random(System.currentTimeMillis());

        list = new ArrayList<Integer> ();
        for (int i = 1; i <= n; i++) 
            list.add(new Integer(rnd.nextInt(k+1)));

        Collections.shuffle(list, rnd);

        array = new int[n];
        for (int i = 0; i < n; i++) 
            array[i] = list.get(i).intValue();

        return array;
    }

    /*
     * n: the size of the output array
     */
    public static int[] generate_random_array (int n) {
        List<Integer> list;
        int[] array;

        list = new ArrayList<Integer> ();
        for (int i = 1; i <= n; i++) 
            list.add(new Integer(i));

        Collections.shuffle(list, new Random(System.currentTimeMillis()));

        array = new int[n];
        for (int i = 0; i < n; i++) 
            array[i] = list.get(i).intValue();

        return array;
    }

    /*
     * Input: an integer array
     * Output: true if the array is acsendingly sorted, otherwise return false
     */
    public static boolean check_sorted (int[] array) {
        for (int i = 1; i < array.length; i++) {
            if (array[i-1] > array[i])
                return false;
        }
        return true;
    }

    public static void print_array (int[] array) {
        for (int i = 0; i < array.length; i++)
            System.out.print(array[i] + ", ");
        System.out.println();
    }

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        System.out.println("Insertion sort starts ------------------");
        for (int n = 100000; n <= 1000000; n=n+100000) {
            int[] array = Sort.generate_random_array(n);
            long t1 = System.currentTimeMillis();
            array = Sort.insertion_sort(array);
            long t2 = System.currentTimeMillis();
            long t = t2 - t1;
            boolean flag = Sort.check_sorted(array);
            System.out.println(n + "," + t + "," + flag);
        }
        System.out.println("Insertion sort ends ------------------");


        System.out.println("Merge sort starts ------------------");
        for (int n = 100000; n <= 1000000; n=n+100000) {
            int[] array = Sort.generate_random_array(n);
            //Sort.print_array(array);
            long t1 = System.currentTimeMillis();
            array = Sort.merge_sort(array, 0, n-1);
            long t2 = System.currentTimeMillis();
            long t = t2 - t1;
            //Sort.print_array(array);
            boolean flag = Sort.check_sorted(array);
            System.out.println(n + "," + t + "," + flag);
        }
        System.out.println("Merge sort ends ------------------");
    }

}

(Slow version)


import java.util.*;

public class Sort {

    public static int[] insertion_sort (int[] array) {

    int i;

        for (int j = 1; j < array.length; j++) {
            int key = array[j];  // assigns the key to the first value of the array  

            i = j-1; // i is always one less than j

            while (i >=0 && array[i] > key) {
                array[i+1] = array[i];
                i = i -1;
            }
                array[i+1] = key;
        }



        return array;
    }

    public static int[] merge_sort (int[] array, int p, int r) {

        if (p < r) {
            int q = (p + r) /2;
            Sort.merge_sort(array, p, q);
            Sort.merge_sort(array, q+1, r);
            Sort.merge(array, p, q, r);
        }

        return array;
    }

    public static int[] merge (int[] array, int p, int q, int r) {
        int n1  = q - p +1;
        int n2 = r - q;
        int[] L = new int[n1+1];
        int[] R = new int [n2+1];

        for (int i = 0; i < n1; i++) {
            L[i] = array[p+i];

        }

        for (int j = 0; j <n2; j++) {
            R[j] = array[q+j+1];
        }

        L[n1] = Integer.MAX_VALUE;
        R[n2] = Integer.MAX_VALUE;

        int i = 0; 
        int j = 0;

        for (int k = p; k<= r; k++) {
            if (L[i] <= R[j]) {
                array[k] = L[i];
                i++;
            }

            else {
                array[k] = R[j];
            }
        }
        return array;
    }

    /*
     * n: the size of the output array
     * k: the maximum value in the array
     */
    public static int[] generate_random_array (int n, int k) {
        List<Integer> list;
        int[] array;
        Random rnd;

        rnd = new Random(System.currentTimeMillis());

        list = new ArrayList<Integer> ();
        for (int i = 1; i <= n; i++) 
            list.add(new Integer(rnd.nextInt(k+1)));

        Collections.shuffle(list, rnd);

        array = new int[n];
        for (int i = 0; i < n; i++) 
            array[i] = list.get(i).intValue();

        return array;
    }

    /*
     * n: the size of the output array
     */
    public static int[] generate_random_array (int n) {
        List<Integer> list;
        int[] array;

        list = new ArrayList<Integer> ();
        for (int i = 1; i <= n; i++) 
            list.add(new Integer(i));

        Collections.shuffle(list, new Random(System.currentTimeMillis()));

        array = new int[n];
        for (int i = 0; i < n; i++) 
            array[i] = list.get(i).intValue();

        return array;
    }

    /*
     * Input: an integer array
     * Output: true if the array is acsendingly sorted, otherwise return false
     */
    public static boolean check_sorted (int[] array) {
        for (int i = 1; i < array.length; i++) {
            if (array[i-1] > array[i])
                return false;
        }
        return true;
    }

    public static void print_array (int[] array) {
        for (int i = 0; i < array.length; i++)
            System.out.print(array[i] + ", ");
        System.out.println();
    }

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        System.out.println("Insertion sort starts ------------------");
        for (int n = 100000; n <= 1000000; n=n+100000) {
            int[] array = Sort.generate_random_array(n);
            long t1 = System.currentTimeMillis();
            array = Sort.insertion_sort(array);
            long t2 = System.currentTimeMillis();
            long t = t2 - t1;
            boolean flag = Sort.check_sorted(array);
            System.out.println(n + "," + t + "," + flag);
        }
        System.out.println("Insertion sort ends ------------------");


        System.out.println("Merge sort starts ------------------");
        for (int n = 100000; n <= 1000000; n=n+100000) {
            int[] array = Sort.generate_random_array(n);
            //Sort.print_array(array);
            long t1 = System.currentTimeMillis();
            array = Sort.merge_sort(array, 0, n-1);
            long t2 = System.currentTimeMillis();
            long t = t2 - t1;
            //Sort.print_array(array);
            boolean flag = Sort.check_sorted(array);
            System.out.println(n + "," + t + "," + flag);
        }
        System.out.println("Merge sort ends ------------------");
    }

}
MyStackRunnethOver
  • 4,872
  • 2
  • 28
  • 42
Chigozie A.
  • 335
  • 4
  • 16
  • Is your benchmark accurate? Read [this](https://stackoverflow.com/questions/504103/how-do-i-write-a-correct-micro-benchmark-in-java) – achAmháin Sep 20 '18 at 21:31
  • The merge sort could be significantly improved. The entry function should do a one time allocation of a temp array the same size as the original array. Then the sub-arrays should be selected by index, rather than allocate / copy / ... . The merge sort should alternate the direction of merge based on the level of recursion (use a parameter, or use two functions, one where data ends up in the original array, one where data ends up in the temp array), or for a bit faster version, use a bottom up merge sort, and alternate direction based on the pass. – rcgldr Sep 20 '18 at 22:07
  • [This answer](https://stackoverflow.com/questions/46106922/mergesort-algorithm-whats-the-better-implementation-in-java/46107386#46107386) shows the implementations for both bottom up and top down merge sort that I mentioned. For small arrays (64 elements or less), insertion sort can be faster than merge sort due to cache. Libraries often use variations of hybrid bottom up merge sort, where insertion sort is done on small sub-arrays (32 or 64 elements), before switching to merge sort. [TimSort](https://en.wikipedia.org/wiki/Timsort) further improves this looking for natural runs. – rcgldr Sep 20 '18 at 22:19

0 Answers0