排序II

归并排序

归并排序的思想:假设初始序列含有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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值