美文网首页
排序(二) -- 进阶排序算法

排序(二) -- 进阶排序算法

作者: OakesYa | 来源:发表于2020-09-15 14:29 被阅读0次

背景

我们上一节复习了三个初级的排序算法(选择,插入,冒泡),这一节我们继续学习时间复杂度优于初级算法的三个算法(希尔,归并,快速),工具类复用上一节的代码。

具体算法

  • 希尔算法
/**
 * 希尔排序是根据gap去交换符合gap的相差gap的所有数据提前进行排序
 * 譬如8个数的数组,第一轮gap=4,先判断[0,4],[1,5],[2,6],[3,7]的大小
 * 第二轮gap=2,判断[0,2],[1,3],[2,4],[0-2],[3,5],[1-3]...的大小
 * 第三轮gap=1,再次回归到插入算法,时间复杂度为啥优于插入排序可以参考https://www.zhihu.com/question/24637339
 */
public class ShellSort {

    public static int[] sort(int[] array) {
        if (!SortUtil.safeCheck(array)) {
            return array;
        }
        int length = array.length;

        for (int gap = length / 2; gap > 0; gap /= 2) {
            for (int i = gap; i < length; i++) {
                for (int j = i - gap; j >= 0;j -= gap) {
                    if (array[j+gap] < array[j]) {
                        SortUtil.exchange(array, j+gap, j);
                    }
                }
            }
        }
        return array;
    }
}
  • 归并排序
/**
 * 首先实现两个数组merge成一个有序数组
 * 利用递归将数组不断分拆成两个数组合并排序即可
 */
public class MergeSort {
    public static int[] sort(int[] array) {
        if (!SortUtil.safeCheck(array)) {
            return array;
        }

        divideAndMerge(array, 0, array.length-1);
        return array;
    }

    /**
     * 合并两个数组成一个有序数组
     */
    private static void merge(int array[], int left, int middle, int right) {
        int leftSize = middle - left;
        int rightSize = right - middle + 1;
        int[] leftArray = new int[leftSize];
        int[] rightArray = new int[rightSize];

        for (int i = left; i < middle; i++) {
            leftArray[i - left] = array[i];
        }
        for(int i = middle; i <= right; i++) {
            rightArray[i-middle] = array[i];
        }

        int i = 0, j = 0, k = left;
        while (i < leftSize && j < rightSize) {
            if (leftArray[i] < rightArray[j]) {
                array[k] = leftArray[i];
                i++;
            } else {
                array[k] = rightArray[j];
                j++;
            }
            k++;
        }
        while (i < leftSize) {
            array[k] = leftArray[i];
            i++;
            k++;
        }
        while(j < rightSize) {
            array[k] = rightArray[j];
            j++;
            k++;
        }
    }

    private static void divideAndMerge(int array[], int left, int right) {
        if (left == right) {
            return;
        }
        int middle = (left + right) / 2;
        divideAndMerge(array, left, middle);
        divideAndMerge(array, middle+1, right);
        merge(array, left, middle+1, right);
    }
}
  • 快速排序
/**
 * 首先选择一个基点,然后将小于基点的数放在基点左边,大于基点的数放在基点右边
 * 递归基点左边和右边的数组,但是要特别注意快速不是稳定的算法,因为它是左右两边
 * 顺序是相反的譬如基点66,两个55的数可能后面一个55先判断小于66而提到了前一个55的前面
 */
public class QuickSort {
    public static int[] sort(int[] array) {
        if (!SortUtil.safeCheck(array)) {
            return array;
        }
        divideAndSort(array, 0, array.length -1);
        return array;
    }

    public static int pivotSort(int[] array, int left, int right) {
        int pivot = array[left];
        int k = 0;
        while (left != right) {
            if (k ==0) {
               if (array[right] >= pivot) {
                   right--;
               } else {
                   array[left] = array[right];
                   k++;
               }
            } else if (k == 1) {
                if (array[left] <= pivot) {
                    left++;
                } else {
                    array[right] = array[left];
                    k--;
                }
            }
        }
        array[left] = pivot;
        return left;
    }

    private static void divideAndSort(int[] array, int left, int right) {
        if (left >= right) {
            return;
        }
        int i = pivotSort(array, left, right);
        divideAndSort(array, left, i - 1);
        divideAndSort(array, i + 1, right);
    }
}
  • 测试代码
public class SortTest {
    public static void main(String[] args) {
        int[] array = new int[] {3,25,88,299,23,88,-1};

        System.out.println(Arrays.toString(ShellSort.sort(array)));
        //System.out.println(Arrays.toString(MergeSort.sort(array)));
        //System.out.println(Arrays.toString(QuickSort.sort(array)));
    }
}

总结

这次的三个排序(希尔,归并,快速)是NlogN平均时间度的算法,可以从通过跳跃式减少完全逆序情况下数据的角度出发考虑时间的减少,我们平时常用的Arrays.sort方法就是使用的快速排序,归并和快速算是平时使用率较高的算法了

相关文章

  • 排序(二) -- 进阶排序算法

    背景 我们上一节复习了三个初级的排序算法(选择,插入,冒泡),这一节我们继续学习时间复杂度优于初级算法的三个算法(...

  • 前端算法之排序(二)---- 选择排序

    写在前面昨天我们学习了最基础的排序算法----冒泡排序,今天呢,我们一起来看一下冒泡排序的进阶算法,选择排序。 大...

  • OC常用算法

    排序算法 冒泡排序 选择排序 快速排序 插入 二分查找

  • 算法之:排序

    排序算法 冒泡排序 选择排序 快速排序 插入 二分查找

  • 算法04-棋牌游戏常用排序算法

    算法04-棋牌游戏常用排序算法 一、介绍 棋牌游戏常用排序算法包括:链式基数排序、插入排序、希尔排序。 二、链式基...

  • 数据结构01-常规排序算法

    第一章 常规排序算法 第一章 常规排序算法一、排序的基本概念排序内部排序与外部排序排序的稳定性二、冒泡排序算法思想...

  • Chapter 2 Foundation of Algorith

    Chapter 2 插入排序 线性查找 选择算法 归并排序算法 二分查找算法 冒泡排序 插入排序 循环不...

  • 数据结构&算法(一)

    一、Java实现快速排序算法 二、Java实现折半插入排序算法 三、Java实现冒泡排序算法

  • 基础排序算法

    快速排序 二分查找 冒泡排序 归并算法 选择排序 插入排序 Shell排序

  • 排序算法(二)之希尔排序

    图解排序算法(二)之希尔排序 希尔排序是希尔(Donald Shell)于1959年提出的一种排序算法。希尔排序也...

网友评论

      本文标题:排序(二) -- 进阶排序算法

      本文链接:https://www.haomeiwen.com/subject/dykfyktx.html