排序II

来源:互联网 发布:sql like 编辑:程序博客网 时间:2024/05/22 06:13

归并排序

归并排序的思想:假设初始序列含有n个记录,则可以看成是n个有序的子序列,每个子序列的长度为1,然后两两归并,得到[n/2]向上取整个长度为2或者1的有序子序列,再两两归并。这种办法称为2路归并排序。

package com.weixuan.sort.merge;public class MergeSort {    public static void printArray(int[] array) {        for (int i = 0; i < array.length; i++)            System.out.print(array[i] + "\t");    }    public static void mergeSort(int[] data) {        mergeSortCore(data, 0, data.length - 1);    }    private static void mergeSortCore(int[] data, int low, int high) {        int midIndex = (low + high) >> 1;        if (low < high) {            // 左边            mergeSortCore(data, low, midIndex);            // 右边            mergeSortCore(data, midIndex + 1, high);            // 左右归并            merge(data, low, midIndex, high);        }    }    private static void merge(int[] data, int low, int mid, int high) {        int[] temp = new int[high - low + 1];        int i = low;// 左指针        int j = mid + 1;// 右指针        int k = 0;        // 把较小的数先移到新数组中        while (i <= mid && j <= high) {            if (data[i] < data[j]) {                temp[k++] = data[i++];            } else {                temp[k++] = data[j++];            }        }        // 把左边剩余的数移入数组        while (i <= mid) {            temp[k++] = data[i++];        }        // 把右边边剩余的数移入数组        while (j <= high) {            temp[k++] = data[j++];        }        // 把新数组中的数覆盖nums数组        for (int k2 = 0; k2 < temp.length; k2++) {            data[k2 + low] = temp[k2];        }    }}

性能

空间复杂度O(N+logN) = O(N)

时间复杂度O(NlogN)

比较过程是两两比较,不存在跳跃,是稳定的排序。

过程 初始序列{50,10,90,30,70,40,80,60,20}

堆排序

package com.weixuan.sort.heap;public class HeapSort {    public static void printArray(int[] array) {        for (int i = 0; i < array.length; i++)            System.out.print(array[i] + "\t");    }    /**     * @param data     *            原始数组序列     * @brief 构建堆     */    private static void buildHeap(int[] data) {        /**         * 获取最后一个非叶子节点         */        int begin = data.length / 2;        for (int i = begin; i >= 0; i--) {            adjustHeap(data, data.length, i);        }    }    /**     * @param data     *            要调整的数组     * @param heapSize     *            长度     * @param index     *            需要调整的节点的下标     * @brief 调整堆     */    private static void adjustHeap(int[] data, int heapSize, int index) {        /**         * 节点index的左孩子下标         */        int leftChildSubscript = 2 * index + 1;        /**         * 节点index的右孩子下标         */        int rightChildSubscript = 2 * index + 2;        /**         * 最大元素的初始下标         */        int largestSubscript = index;        /**         * 找到最大元素         */        /**         * 如果当前根节点小于左孩子的值,那么最大元素的下标为左孩子的下标.         */        if ((leftChildSubscript < heapSize) && (data[largestSubscript] < data[leftChildSubscript])) {            largestSubscript = leftChildSubscript;        }        /**         * 如果当前根节点小于右孩子的值,那么最大元素的下标为右孩子的下标.         */        if ((rightChildSubscript < heapSize) && (data[largestSubscript] < data[rightChildSubscript])) {            largestSubscript = rightChildSubscript;        }        /**         * 将最大元素调整至根节点. 根节点不是最大的,那么就调整.         */        if (index != largestSubscript) {            /**             * 将根节点的值与子节点中的最大值进行调整.             */            swapElements(data, index, largestSubscript);            /**             */            adjustHeap(data, heapSize, largestSubscript);        }    }    private static void swapElements(int[] data, int index1, int index2) {        int temp = data[index1];        data[index1] = data[index2];        data[index2] = temp;    }    /**     * @param data     *            原始数组     * @brief 堆排序     */    public static void heapSort(int[] data) {        int length = data.length;        /**         * 构建堆         */        buildHeap(data);        while (length >= 1) {            /**             * 将堆的最后一个元素与堆顶元素交换.             */            swapElements(data, 0, length - 1);            length--;            /**             * 将剩余元素调整为堆             */            adjustHeap(data, length, 0);        }    }}

性能

堆排序的运行时间主要耗费在初始创建堆和重新构建堆上。
构建堆的时间复杂度是O(N)

时间复杂度是O(NlogN),由于记录的比较是跳跃进行的,所以不稳定。

插入排序

在待排序的元素序列基本有序的前提下,效率最高的排序方法是插入排序

思想:将一个记录插入到已经排序的有序表中,从而得到一个新的记录+1的有序表。

package com.weixuan.sort.insert;public class InsertSort {    public static void printArray(int[] array) {        for (int i = 0; i < array.length; i++)            System.out.print(array[i] + "\t");    }    public static void insertSort(int[] data) {        for (int i = 1; i < data.length; i++) {            if (data[i] < data[i - 1]) {                int temp = data[i]; // 需要插入的数字                int j = i - 1;                // 数组后移                while (j >= 0 && data[j] > temp) {                    data[j + 1] = data[j];                    j--;                }                data[j + 1] = temp;            }        }    }}

性能分析

当数组基本有序时,性能最好,比较n-1次,没有数据移动。时间复杂度为O(N)

最差情况,待排数据是逆序的,需要比较

i=2ni=2+3+4+...n=(n+2)(n1)2

次,移动的次数是
i=2ni+1=(n+4)(n1)2

此时的时间复杂度是O(N2)

平均情况下,平均的比较次数和移动次数是N24

shell排序

本质是分组插入排序

package com.weixuan.sort.shell;public class ShellSort {    public static void printArray(int[] array) {        for (int i = 0; i < array.length; i++)            System.out.print(array[i] + "\t");    }    public static void shellSort(int[] data) {        int increment = data.length;        int j;        do {            increment = increment / 3 + 1;            for (int i = increment; i < data.length; i++) {                if (data[i] < data[i - increment]) {                    int temp = data[i];                    for (j = i - increment; j >= 0 && temp < data[j]; j -= increment) {                        data[j + increment] = data[j];                    }                    data[j + increment] = temp;                }            }        } while (increment > 1);    }}

性能

性能和步长(increment)有关,最佳时间复杂度是O(N3/2)

比较是跳跃性的,是非稳定的排序算法

外部排序

外部排序还要考虑IO效率

tips

堆排序,冒泡排序 ,快速排序每趟结束时,都有一个元素被放置再在其最终位置上。

0 0
原创粉丝点击