九大经典排序算法小结+自创简易测试框架

最近写了颇多笔试,下面归纳一下遇到过的经典排序算法

1、为了方便调试这些排序算法,这里设计了一个的简易测试框架

  • 具体功能:当我们实现不同算法时,只需要关注方法本身的正确性和完整性,框架会自动化帮助我们完成对该方法的测试用例

  • 实现方式:我们在外层调用封装好的框架,将对象传入框架中进行自我检查,使目标方法得以调用,并进行所有测试用例的检测。

package com.demo.sort.loader;

import com.demo.sort.annotation.Sort;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.text.DecimalFormat;

/**
 * Created with IDEA
 * User: zzzz76
 * Date: 2018-03-24
 */
public class TestLoader {
    private static final DecimalFormat df = new DecimalFormat("0.00%");

    /**
     * 生成随机数组
     *
     * @param len
     * @param range
     * @return
     */
    private static int[] generateArray(int len, int range) {
        if (len < 1) {
            return null;
        }
        int[] arr = new int[len];
        for (int i = 0; i < len; i++) {
            arr[i] = (int) (Math.random() * range);
        }
        return arr;
    }

    /**
     * 输出数组
     *
     * @param arr
     */
    private static void printArray(int[] arr) {
        if (arr == null || arr.length == 0) {
            return;
        }
        System.out.print(arr[0]);
        for (int i = 1; i < arr.length; i++) {
            System.out.print(", " + arr[i]);
        }
        System.out.println();
    }

    /**
     * 检查是否排序
     *
     * @param arr
     * @return
     */
    private static boolean isSorted(int[] arr) {
        if (arr == null || arr.length < 2) {
            return true;
        }
        for (int i = 1; i < arr.length; i++) {
            if (arr[i - 1] > arr[i]) {
                return false;
            }
        }
        return true;
    }

    /**
     * 加载实例,完成测试
     *
     * @param object
     */
    public static void load(Object object) {
        try {
            Class testClass = object.getClass();
            Method[] methods = testClass.getDeclaredMethods();
            for (Method method: methods) {
                if (method.isAnnotationPresent(Sort.class)) {
                    Sort sort = method.getAnnotation(Sort.class);
                    System.out.println("Start test: " + sort.value());
                    //排序测试
                    int testFail = 0;
                    int testCount = 0;
                    int testPass = 0;

                    int len;
                    int range = 10;
                    for (int i = 0; i < 50000; ++i) {
                        len = (int) (Math.random() * (range + 1));
                        int[] arr = generateArray(len, range);
                        method.invoke(object, (Object) arr);
                        testCount++;
                        if (!isSorted(arr)) {
                            if (testFail == 0) {
                                System.out.println("Wrong case: ");
                            }
                            if (testFail < 5) {
                                printArray(arr);
                            }
                            if (testFail == 5) {
                                System.out.println("...");
                            }
                            testFail++;
                        } else {
                            testPass++;
                        }
                    }
                    System.out.println(testPass+ "/" + testCount + " " + df.format((double) testPass / testCount) + "passed\n");
                }
            }
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }

}

2、九大经典排序算法

冒泡排序、选择排序、插入排序

其中插入排序的时间受源数组顺序影响

package com.demo.sort;

import com.demo.sort.annotation.Sort;
import com.demo.sort.loader.TestLoader;

/**
 * Created with IDEA
 * User: zzzz76
 * Date: 2018-03-24
 *
 * 题目:
 * 比较排序算法A
 * 时间复杂度:O(N^2)
 * 空间复杂度:O(1)
 */
public class SortTestA {

    public static void main(String[] args) {
        TestLoader.load(new SortTestA());
    }

    private void swap(int[] arr, int index1, int index2) {
        int tmp = arr[index1];
        arr[index1] = arr[index2];
        arr[index2] = tmp;
    }

    /**
     * 冒泡排序
     * 稳定的排序算法
     *
     * @param arr
     */
    @Sort(value = "bubbleSort")
    public void bubbleSort(int[] arr) {
        if (arr == null || arr.length < 2) {
            return;
        }
        for (int i = arr.length - 1; i >= 0; i--) {
            for (int j = 0; j < i; j++) {
                if (arr[j] > arr[j + 1]) {
                    swap(arr, j, j + 1);
                }
            }
        }
    }

    /**
     * 选择排序
     * 不稳定的排序算法
     *
     * @param arr
     */
    @Sort(value = "selectSort")
    public void selectSort(int[] arr) {
        if (arr == null || arr.length < 2) {
            return;
        }
        int mini = 0;
        for (int i = 0; i < arr.length - 1; i++) {
            mini = i;
            for (int j = i + 1; j < arr.length; j++) {
                mini = arr[mini] > arr[j] ? j : mini;
            }
            swap(arr, i, mini);
        }
    }

    /**
     * 插入排序
     * 最优时间复杂度:O(N)
     * 最差时间复杂度:O(N^2)
     * 稳定的排序算法
     *
     * @param arr
     */
    @Sort(value = "insertSort")
    public void insertionSort(int[] arr) {
        if (arr == null || arr.length < 2) {
            return;
        }
        int index = 0;
        for (int i = 1; i < arr.length; i++) {
            index = i;
            while (index > 0) {
                if (arr[index - 1] > arr[index]) {
                    swap(arr, index - 1, index);
                    index--;
                } else {
                    break;
                }
            }
        }
    }
}

归并排序、快速排序、堆排序、希尔排序

归并排序可以看做是后序遍历的过程,其中二叉树的叶子节点对应着数组的个数,所以归并的递归深度为logN
快速排序可以看做是前序遍历的过程,其中二叉树的总节点对应着数组的个数,递归深度为logN
堆排序建立的大/小根堆的总节点对应着数组的个数,大/小根堆的调整深度对应着二叉树的深度,递归深度为logN

package com.demo.sort;

import com.demo.sort.annotation.Sort;
import com.demo.sort.loader.TestLoader;

/**
 * Created with IDEA
 * User: zzzz76
 * Date: 2018-03-25
 *
 * 题目:
 * 比较排序算法B
 * 时间复杂度:O(N*logN)
 */
public class SortTestB {
    public static void main(String[] args) {
        TestLoader.load(new SortTestB());
    }

    private void swap(int[] arr, int index1, int index2) {
        int tmp = arr[index1];
        arr[index1] = arr[index2];
        arr[index2] = tmp;
    }

    private void merge(int[] arr, int left, int mid, int right) {
        int[] help = new int[right - left + 1];
        int l = left;
        int r = mid + 1;
        int index = 0;
        while (l <= mid && r <= right) {
            if (arr[l] <= arr[r]) {
                help[index++] = arr[l++];
            } else {
                help[index++] = arr[r++];
            }
        }
        while (l <= mid) {
            help[index++] = arr[l++];
        }
        while (r <= right) {
            help[index++] = arr[r++];
        }
        for (int i = 0; i < help.length; i++) {
            arr[left + i] = help[i];
        }
    }

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

    /**
     * 归并排序(后序遍历二叉树)
     * 空间复杂度:O(N + logN)
     * 稳定的排序算法
     *
     * @param arr
     */
    @Sort(value = "mergeSort")
    public void mergeSort(int[] arr) {
        if (arr == null || arr.length < 2) {
            return;
        }
        mergeProcess(arr, 0, arr.length - 1);
    }

    private int partition(int[] arr, int left, int right) {
        int pivot = left - 1;
        int index = left;
        while (index <= right) {
            if (arr[index] <= arr[right]) {
                swap(arr, ++pivot, index);
            }
            index++;
        }
        return pivot;
    }

    private void quickProcess(int[] arr, int left, int right) {
        if (left < right) {
            int random = left + (int) (Math.random() * (right - left + 1));
            swap(arr, random, right);
            int mid = partition(arr, left, right);
            quickProcess(arr, left, mid - 1);
            quickProcess(arr, mid + 1, right);
        }
    }

    /**
     * 快速排序(前序遍历二叉树)
     * 最优空间复杂度:O(logN)
     * 最差空间复杂度:O(N)
     * 最优时间复杂度:O(N*logN)
     * 最差时间复杂度:O(N^2)
     * 不稳定的排序算法
     *
     * @param arr
     */
    @Sort(value = "quickSort")
    public void quickSort(int[] arr) {
        if (arr == null || arr.length < 2) {
            return;
        }
        quickProcess(arr, 0, arr.length - 1);
    }

    private void heap(int[] arr, int head, int tail, int node) {
        int leftNode = node *2+1;
        int rightNode = node *2 + 2;
        if (leftNode > tail) {
            return;
        }
        int maxNode = leftNode;
        if (rightNode <= tail) {
            maxNode = arr[leftNode] > arr[rightNode]?leftNode:rightNode;
        }

        if (arr[node] < arr[maxNode]) {
            swap(arr, node, maxNode);
            heap(arr, head, tail, maxNode);
        }
    }

    /**
     * 堆排序
     * 空间复杂度递归/迭代:O(logN)/O(1)
     * 不稳定的排序算法
     *
     * @param arr
     */
    @Sort(value = "heapSort")
    public void heapSort(int[] arr) {
        // write code here
        // 构建最大堆
        if (arr == null || arr.length < 2) {
            return;
        }
        int n = arr.length;
        for (int i = n/2 -1; i>=0;--i) {
            heap(arr, 0, n-1, i);
        }
        for (int i = n-1; i > 0; --i) {
            swap(arr, i, 0);
            heap(arr, 0, i - 1, 0);
        }
    }

    /**
     * 希尔排序
     * 空间复杂度:O(1)
     * 不稳定的排序算法
     * @param arr
     */
    @Sort(value = "shellSort")
    public void shellSort(int[] arr) {
        if (arr == null || arr.length < 2) {
            return;
        }
        int feet = arr.length / 2;
        int index = 0;
        while (feet > 0) {
            for (int i = feet; i < arr.length; i++) {
                index = i;
                while (index >= feet) {
                    if (arr[index - feet] > arr[index]) {
                        swap(arr, index - feet, index);
                        index -= feet;
                    } else {
                        break;
                    }
                }
            }
            feet /= 2;
        }
    }
}

计数排序、基数排序

package com.demo.sort;

import com.demo.sort.annotation.Sort;
import com.demo.sort.loader.TestLoader;

/**
 * Created with IDEA
 * User: zzzz76
 * Date: 2018-03-25
 *
 * 题目:
 * 桶排序C
 * 时间复杂度:O(N)
 * 空间复杂度:O(M)
 * 稳定的排序算法
 */
public class SortTestC {
    public static void main(String[] args) {
        TestLoader.load(new SortTestA());
    }

    private void swap(int[] arr, int index1, int index2) {
        int tmp = arr[index1];
        arr[index1] = arr[index2];
        arr[index2] = tmp;
    }

    @Sort(value = "countSort")
    public void countSort(int[] arr) {
        if (arr == null || arr.length < 2) {
            return;
        }
        int min = arr[0];
        int max = arr[0];
        for (int i = 1; i < arr.length; i++) {
            min = Math.min(arr[i], min);
            max = Math.max(arr[i], max);
        }
        int[] countArr = new int[max - min + 1];
        for (int i = 0; i < arr.length; i++) {
            countArr[arr[i] - min]++;
        }
        int index = 0;
        for (int i = 0; i < countArr.length; i++) {
            while (countArr[i]-- > 0) {
                arr[index++] = i + min;
            }
        }
    }

    @Sort(value = "radixSort")
    public void radixSort(int[] arr) {
        // write code here
        if (arr == null || arr.length < 2) {
            return;
        }
        int n = arr.length;
        int max = arr[0];
        for (int i = 1; i <= n -1; ++i) {
            if (max < arr[i]) {
                max = arr[i];
            }
        }
        int[] context = new int[n];
        int index = 0;
        for (int d = 1; max/d != 0;  d *= 10) {
            for (int i = 0; i <= 9; ++i) {
                for (int j = 0; j <= n -1; ++j) {
                    if ((arr[j]/d)% 10 == i) {
                        context[index] = arr[j];
                        index ++;
                    }
                }
            }
            index = 0;
            for (int i = 0; i <= n - 1; ++i) {
                arr[i] = context[i];
            }
        }
    }
}

posted @ 2018-03-26 01:20  小z同学  阅读(935)  评论(0编辑  收藏  举报