Sorting Algorithms

update Aug 13, 2019

// Implement sorting algorithm

import java.util.*;
import java.util.stream.*;

public class Sorting {
    public static void main(String[] args) {
        // test here
        int[] arr1 = {0, 1, 2, 3, 4, 5, 6};
        int[] arr2 = {6, 5, 4, 3, 2, 1, 0};
        int[] arr3 = {34, 5, 12, 12, 59, 846, 1323, 22, 4, 22, 8};
        int[] arr4 = {2};
        int[] arr5 = {5, 4};

        // testInsertionSort(arr1);
        // testInsertionSort(arr2);
        // testInsertionSort(arr3);
        // testInsertionSort(arr4);
        // testInsertionSort(arr5);

        // testMergeSort(arr1);
        // testMergeSort(arr2);
        // testMergeSort(arr3);
        // testMergeSort(arr4);
        // testMergeSort(arr5);

        testQuickSort(arr1);
        testQuickSort(arr2);
        testQuickSort(arr3);
        testQuickSort(arr4);
        testQuickSort(arr5);

        // testBubbleSort(arr1);
        // testBubbleSort(arr2);
        // testBubbleSort(arr3);
        // testBubbleSort(arr4);
        // testBubbleSort(arr5);

        // testSelectionSort(arr1);
        // testSelectionSort(arr2);
        // testSelectionSort(arr3);
        // testSelectionSort(arr4);
        // testSelectionSort(arr5);

        // testCountingSort(arr1);
        // testCountingSort(arr2);
        // testCountingSort(arr3);
        // testCountingSort(arr4);
        // testCountingSort(arr5);
    }

// Counting Sort ********************************************
    // stable counting sort
    public static void testCountingSort(int[] arr) {
        int[] result = countingSort(arr);
        System.out.print("countingSort output: { ");
        for (int n : result) {
            System.out.print(n + " ");
        }
        System.out.print(" }\n");
    }
    public static int[] countingSort(int[] arr) {
        int[] ret = new int[arr.length];
        // 先建一个长度等于数据范围的数组
        int min = arr[0], max = arr[0];
        for (int i : arr) {
            if (i > max) max = i;
            else if (i < min) min = i;
        }
        int[] count = new int[max - min + 1];
        // 数组中每个位置存放input array中对应元素出现的次数
        for (int i : arr) {
            count[i - min]++;
        }
        // 为了stable,将count数组转换为原始count数组的preSum数组, 到这里为止,解释一下:
        // 现在count 数组中的 count[i] 表示原数组arr中有 count[i] 个数小于等于 i+min;
        // 则我们可知原数组中位置最靠右的 i+min, 它在结果中的位置一定是 index=count[i]-1
        for (int i = 1; i < count.length; ++i) {
            count[i] += count[i - 1];
        }
        // 根据如上理由,ret中的数 x(最靠右的x) 在count中对应的下标应为 x-min,而 count[x-min]-1 就
        // 是 x 在ret中的 index,于是将 x 放在 ret[count[x-min]]-1 之后,还要将 count[x-min] 也减一
        for (int i = arr.length - 1; i >= 0; --i) {
            ret[--count[arr[i] - min]] = arr[i];
        }
        return ret;
    }


// Selection sort **************************************************
    // left part is sorted, find min of the rest part in each iteration and swap
    // with the left most element of the right part.
    public static void testSelectionSort(int[] arr) {
        int[] result = selectionSort(arr);
        System.out.print("selectionSort output: { ");
        for (int n : result) {
            System.out.print(n + " ");
        }
        System.out.print(" }\n");
    }
    public static int[] selectionSort(int[] arr) {
        int[] ret = arr.clone();
        for (int i = 0; i < ret.length - 1; ++i) {
            int minIndex = i;
            for (int j = i + 1; j < ret.length; ++j) {
                if (ret[minIndex] > ret[j]) minIndex = j;
            }
            swap(ret, minIndex, i);
        }
        return ret;
    }

// Bubble sort **********************************************
    // Iterate n times, swap larger neighbors to right in each iteration.
    public static void testBubbleSort(int[] arr) {
        int[] result = bubbleSort(arr);
        System.out.print("bubbleSort output: { ");
        for (int n : result) {
            System.out.print(n + " ");
        }
        System.out.print(" }\n");
    }
    public static int[] bubbleSort(int[] arr) {
        int[] ret = arr.clone();
        for (int i = 0; i < ret.length; ++i) {
            for (int j = 1; j < ret.length; ++j) {
                if (ret[j - 1] > ret[j]) swap(ret, j, j - 1);
            }
        }
        return ret;
    }


// Insertion sort ******************************************
    // maintain a sorted sequence at left, insert one element at one time
    public static void testInsertionSort(int[] arr) {
        int[] result = insertionSort(arr);
        System.out.print("insertionSort output: { ");
        for (int n : result) {
            System.out.print(n + " ");
        }
        System.out.print(" }\n");
    }

    public static int[] insertionSort(int[] arr) {
        int[] ret = arr.clone();
        for (int i = 1; i < ret.length; ++i) {
            int key = ret[i];
            int j = 0;
            for (j = i - 1; j >= 0 && ret[j] > key; --j) {
                ret[j + 1] = ret[j];
            }
            ret[j + 1] = key;
        }
        return ret;
    }


// Merge sort ************************************************
/*
    MergeSort 为什么需要 O(n) space:
    因为每次我们需要把两个sorted array merge 到原来的 array 中的时候,我们必须新建辅助数组
    储存那两个array,这个过程在recursion的过程中,至多消耗O(n)的space;
*/
    public static void testMergeSort(int[] arr) {
        int[] result = mergeSort(arr);
        System.out.print("mergeSort output: { ");
        for (int n : result) {
            System.out.print(n + " ");
        }
        System.out.print(" }\n");
    }

// // merge sort, 手动建一个aux array的解法,这种方法也可以用来说明mergesort O(n) 的空间复杂度
    public static int[] mergeSort(int[] arr) {
        int[] ret = Arrays.copyOf(arr, arr.length);
        // 这里建一个长度为n的aux数组,用来作为每次merge的缓存数组,也是除了递归栈之外的所有额外空间,
        // 递归栈高度为logn,所以整个的空间复杂度为 O(n + logn) == O(n);
        int[] aux = new int[arr.length];
        // mergeSort(ret, aux, 0, arr.length - 1);
        mergeSort(ret, 0, arr.length - 1);
        return ret;
    }

    private static void mergeSort(int[] arr, int left, int right) {
        if (left >= right) return;
        int mid = left + (right - left) / 2;
        mergeSort(arr, left, mid);
        mergeSort(arr, mid + 1, right);
        merge(arr, left, mid, right);
    }

    private static void merge(int[] arr, int left, int mid, int right) {
        int[] aux = Arrays.copyOfRange(arr, left, right + 1);
        int i = left, j = mid + 1;
        for (int k = left; k <= right; ++k) {
            if (i > mid) arr[k] = aux[j++ - left];
            else if (j > right) arr[k] = aux[i++ - left];
            else if (aux[i - left] < aux[j - left]) arr[k] = aux[i++ - left];
            else arr[k] = aux[j++ - left];
        }
    }

    // private static void mergeSort(int[] arr, int[] aux, int p, int r) {
    //     if (p >= r) return;
    //     int q = p + (r - p) / 2;
    //     mergeSort(arr, aux, p, q);
    //     mergeSort(arr, aux, q + 1, r);
    //     merge(arr, aux, p, q, r);
    // }

    // private static void merge(int[] arr, int[] aux, int p, int q, int r) {
    //     // 先把arr中需要merge部分复制到aux中,然后merge后的结果存回arr原位
    //     for (int i = p; i <= r; ++i) {
    //         aux[i] = arr[i];
    //     }
    //     int i = p, j = q + 1;
    //     for (int k = p; k <= r; ++k) {
    //         if (i > q) arr[k] = aux[j++];
    //         else if (j > r) arr[k] = aux[i++];
    //         else if (aux[i] < aux[j]) arr[k] = aux[i++];
    //         else arr[k] = aux[j++];
    //     }
    // }


// // MergeSort 简洁的写法
    // public static int[] mergeSort(int[] arr) {
    //     int[] ret = Arrays.copyOf(arr, arr.length);
    //     mergeSort(ret, 0, ret.length - 1);
    //     return ret;
    // }
    // private static void mergeSort(int[] arr, int p, int r) {
    //     if (p >= r) return;
    //     int q = (p + r) / 2;
    //     mergeSort(arr, p, q);
    //     mergeSort(arr, q + 1, r);
    //     merge(arr, p, q, r);
    // }
    //
    // // 写这个函数之前先画图:
    // //  input arr: __|p|__________| q |______| r |_____
    // //  aux:         |0|__________|q-p|______|r-p|
    // private static void merge(int[] arr, int p, int q, int r) {
    //     int[] aux = Arrays.copyOfRange(arr, p, r + 1);
    //     int i = 0, j = q - p + 1;
    //     for (int k = p; k < r + 1; ++k) {
    //         if (i > q - p)            arr[k] = aux[j++];
    //         else if (j > r - p)       arr[k] = aux[i++];
    //         else if (aux[i] < aux[j]) arr[k] = aux[i++];
    //         else                      arr[k] = aux[j++];
    //     }
    // }



// Quick sort ************************************************
    public static void testQuickSort(int[] arr) {
        int[] result = quickSort(arr);
        System.out.print("quickSort output: { ");
        for (int n : result) {
            System.out.print(n + " ");
        }
        System.out.print(" }\n");
    }

    public static int[] quickSort(int[] arr) {
        int[] ret = Arrays.copyOf(arr, arr.length);
        quickSort(ret, 0, ret.length - 1);
        return ret;
    }

    private static void quickSort(int[] arr, int left, int right) {
        if (left >= right) return;
        int mid = partition(arr, left, right);
        quickSort(arr, left, mid - 1);
        quickSort(arr, mid + 1, right);
    }
    // |----------------i-------------j->             pivot|
    // left  <= pivot   |   > pivot   |  unexplored       right
    private static int partition(int[] arr, int left, int right) {
        int pivot = arr[right];
        int i = left - 1;
        for (int j = left; j <= right; ++j) {
            if (arr[j] <= pivot) swap(arr, ++i, j);
        }
        return i;
    }


    private static void swap(int[] arr, int i, int j) {
        int t = arr[i];
        arr[i] = arr[j];
        arr[j] = t;
    }
}

results matching ""

    No results matching ""