数据结构:排序干货!(7大排序汇总+快速排序的优化+计数排序+基数排序+桶排序)

这篇具有很好参考价值的文章主要介绍了数据结构:排序干货!(7大排序汇总+快速排序的优化+计数排序+基数排序+桶排序)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

概念

插入排序

直接插入排序

希尔排序

选择排序

直接选择排序

双向选择排序

堆排序

交换排序

冒泡排序

快速排序

Hoare法

挖坑法

前后指针法

快排的优化

三数取中法

非递归快排

归并排序

分治算法+二路归并

非递归归并

应用

排序总结

其他排序

计数排序

简单版本

复杂版本(稳定版本)

基数排序 

桶排序 


概念

排序:所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作。

稳定性:假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,r[i]=r[j],且r[i]r[j]之前,而在排序后的序列中,r[i]仍在r[j]之前,则称这种排序算法是稳定的;否则称为不稳定的。  

数据结构:排序干货!(7大排序汇总+快速排序的优化+计数排序+基数排序+桶排序),Java数据结构,排序算法,java,算法,数据结构

内部排序:数据元素全部放在内存中的排序

外部排序:数据元素太多不能同时放在内存中,根据排序过程的要求不能在内外存之间移动数据的排序。 (比如要放在磁盘,硬盘等来进行排序)

分类:

数据结构:排序干货!(7大排序汇总+快速排序的优化+计数排序+基数排序+桶排序),Java数据结构,排序算法,java,算法,数据结构


插入排序

直接插入排序

动图演示如下:数据结构:排序干货!(7大排序汇总+快速排序的优化+计数排序+基数排序+桶排序),Java数据结构,排序算法,java,算法,数据结构

我们可以设置两个指针i和j,i放在第二个元素的位置,j放在第一个元素的位置

每次把i位置的元素提取出来放到tmp中,和j位置的元素进行比较,如果tmp的元素较小,就与j位置元素进行交换

交换完之后j--,看看前面还有没有元素比交换后靠前的元素大,如果有就重复上述步骤,没有就把j和i挪到下一个元素

数据结构:排序干货!(7大排序汇总+快速排序的优化+计数排序+基数排序+桶排序),Java数据结构,排序算法,java,算法,数据结构 数据结构:排序干货!(7大排序汇总+快速排序的优化+计数排序+基数排序+桶排序),Java数据结构,排序算法,java,算法,数据结构

数据结构:排序干货!(7大排序汇总+快速排序的优化+计数排序+基数排序+桶排序),Java数据结构,排序算法,java,算法,数据结构数据结构:排序干货!(7大排序汇总+快速排序的优化+计数排序+基数排序+桶排序),Java数据结构,排序算法,java,算法,数据结构

数据结构:排序干货!(7大排序汇总+快速排序的优化+计数排序+基数排序+桶排序),Java数据结构,排序算法,java,算法,数据结构

    public static void insertSort(int[] array) {
        for (int i = 1; i < array.length; i++) {
            int tmp = array[i];
            int j = i - 1;
            for (; j >= 0; j--) {
                if (array[j] > tmp) {
                    array[j + 1] = array[j];
                } else {
                    break;
                }
            }
            array[j + 1] = tmp;
        }
    }

时间复杂度?

最坏情况:

假设有n个数据,遍历第2个元素并进行交换,j要回退2-1 = 1次

遍历第3个元素并进行交换,j要回退3-1 = 2次

遍历第n个元素并进行交换,j还需要进行回退n-1次,那么需要n-1次操作,

总共就需要

1+2+3+...+n-1 ≈ n^2 -->O(n^2)

最好情况:

交换之后j不需要进行回退,那么直直遍历下去 --> O(n)

所以直插适用于:待排序序列基本趋于有序了

稳定性?

直接插入排序是稳定的,数据交换判断需要array[i] > tmp才有进行交换,如果原本序列有两个相同的数字,那直插是不会改变这两个数字的顺序的,所以是稳定的

⚠一个稳定的排序可以通过修改条件变成不稳定的排序,但是不稳定的排序一定不能变成稳定的排序


希尔排序

缩小增量排序,比如下面的排序

初始数据我们可以分成5组,此时的增量就是5,接着第1个元素与第6个元素,第2个元素与第7个元素等两两交换

数据结构:排序干货!(7大排序汇总+快速排序的优化+计数排序+基数排序+桶排序),Java数据结构,排序算法,java,算法,数据结构

接着降低增量(gap / 2),增加每组的数据,继续进行排序

数据结构:排序干货!(7大排序汇总+快速排序的优化+计数排序+基数排序+桶排序),Java数据结构,排序算法,java,算法,数据结构

其实前面的增量分组相当于一个预排序,真正的排序是最后一组

    //希尔排序
    public static void shellSort(int[] array){
        int gap = array.length;
        while(gap>1){
            gap /= 2;
            shell(array,gap);
        }
    }

    /**
     * 对每组进行排序
     * 这段代码其实跟插入排序差不多,就是i其实位置在gap上,j每次递减递增gap个单位
     * @param array
     * @param gap
     */

    public static void shell(int[] array, int gap){
        for (int i = gap; i < array.length; i++) {
            int tmp = array[i];
            int j = i -gap;
            for (; j >= 0 ; j-=gap) {
                if (array[j] > tmp){
                    array[j+gap] = array[j];
                }else{
                    break;
                }
            }
            array[j+gap] = tmp;
        }
    }

时间复杂度?

数据结构:排序干货!(7大排序汇总+快速排序的优化+计数排序+基数排序+桶排序),Java数据结构,排序算法,java,算法,数据结构

稳定性?不稳定,因为分组交换之后会打乱相同的数字原本的前后顺序

编写个代码来测试一下两者的运行时间

import java.util.Arrays;

public class Test {
    public static void testInsert(int[] array){
        int[] tmpArray = Arrays.copyOf(array, array.length);
        long startTime = System.currentTimeMillis();
        Sort.insertSort(tmpArray);
        long endTime = System.currentTimeMillis();
        System.out.println("直接插入排序时间:"+(endTime-startTime));
    }
    public static void testShell(int[] array){
        int[] tmpArray = Arrays.copyOf(array, array.length);
        long startTime = System.currentTimeMillis();
        Sort.shellSort(tmpArray);
        long endTime = System.currentTimeMillis();
        System.out.println("希尔排序时间:"+(endTime-startTime));
    }
    public static void initArray(int[] array){
        for (int i = 0; i < array.length; i++) {
            array[i] = array.length-i;
        }
    }

    public static void main(String[] args) {
        int[] array = new int[10_0000];
        initArray(array);
        testInsert(array);
        testShell(array);
    }
}

数据结构:排序干货!(7大排序汇总+快速排序的优化+计数排序+基数排序+桶排序),Java数据结构,排序算法,java,算法,数据结构


选择排序

直接选择排序

动图如下:
数据结构:排序干货!(7大排序汇总+快速排序的优化+计数排序+基数排序+桶排序),Java数据结构,排序算法,java,算法,数据结构

数据结构:排序干货!(7大排序汇总+快速排序的优化+计数排序+基数排序+桶排序),Java数据结构,排序算法,java,算法,数据结构

设置i和j,遍历当前i下标后面的元素(j++),找到一个最小的值与i下标的元素进行替换

然后i++,进行下一个元素的交换

    /**
     * 选择排序
     * 时间复杂度O(n^2)
     * 空间复杂度O(1)
     * 稳定性:不稳定
     * @param array
     * @param i
     * @param j
     */
    public static void swap(int[] array,int i,int j){
        int tmp = array[i];
        array[i] = array[j];
        array[j] = tmp;
    }
    public static void selectSort(int[] array){
        for (int i = 0; i < array.length; i++) {
            int minIndex = i;
            //j往后遍历,每次找到比minIndex下标元素小的就进行下标替换
            for (int j = i+1; j < array.length; j++) {
                if(array[j] < array[minIndex]){
                    minIndex = j;
                }
            }
            swap(array,i,minIndex);
        }
    }

双向选择排序

设置最左边下标l和最右边下标r,设置i = l+1,往后遍历,找到最小值的下标和最大值的下标

数据结构:排序干货!(7大排序汇总+快速排序的优化+计数排序+基数排序+桶排序),Java数据结构,排序算法,java,算法,数据结构

数据结构:排序干货!(7大排序汇总+快速排序的优化+计数排序+基数排序+桶排序),Java数据结构,排序算法,java,算法,数据结构

接着把minIndex的元素与l交换,maxIndex的元素与r交换

接着再i++,l++,r--,重复上面的步骤

注意:如果l的位置就是最大值,经过与最小值交换之后不一定有序

数据结构:排序干货!(7大排序汇总+快速排序的优化+计数排序+基数排序+桶排序),Java数据结构,排序算法,java,算法,数据结构数据结构:排序干货!(7大排序汇总+快速排序的优化+计数排序+基数排序+桶排序),Java数据结构,排序算法,java,算法,数据结构

所以我们要把minIndex和maxIndex换过来

    public static void selectSort2(int[] array){
        int left = 0;
        int right = array.length-1;
        while(left<right){
            int minIndex = left;
            int maxIndex = right;
            //找到最大值和最小值下标
            for (int i = left+1; i <= right; i++) {
                if(array[i] < array[minIndex]){
                    minIndex = i;
                }
                if(array[i] > array[maxIndex]){
                    maxIndex = i;
                }
            }
            swap(array,minIndex,left);
            if(maxIndex == left){
                maxIndex = minIndex;
            }
            swap(array,maxIndex,right);
            left++;
            right--;
        }
    }

堆排序

可以看着我这篇博客的思路数据结构:优先级队列(堆)-CSDN博客

代码如下:

    private static void createHeap(int[] array) {
        for (int parent = (array.length-1-1)/2; parent >= 0 ; parent--) {
            siftDown(array,parent,array.length);//alt+enter
        }
    }

    private static void siftDown(int[] array,int parent, int length) {
        int child = 2*parent + 1;
        while (child < length) {
            if(child+1 < length && array[child] < array[child+1]) {
                child++;
            }
            if(array[child] > array[parent]) {
                swap(array,child,parent);
                parent = child;
                child = 2*parent+1;
            }else {
                break;
            }
        }
    }

    /**
     * 时间复杂度:O(N*logN)
     * 空间复杂度:O(1)
     * 稳定性:不稳定的排序
     * @param array
     */
    public static void heapSort(int[] array) {
        createHeap(array);
        int end = array.length-1;
        while (end > 0) {
            swap(array,0,end);
            siftDown(array,0,end);
            end--;
        }
    }

交换排序

冒泡排序

动图如下:
数据结构:排序干货!(7大排序汇总+快速排序的优化+计数排序+基数排序+桶排序),Java数据结构,排序算法,java,算法,数据结构

    /**
     * 时间复杂度:O(n^2)
     * 空间复杂度:O(1)
     * 稳定性:稳定
     * @param array
     */
    public static void bubbleSort(int[] array){
        //i代表趟数
        for (int i = 0; i < array.length-1; i++) {
            //每一趟都比较上一趟有没有交换
            boolean flg = false;
            //j来比较每个数据的大小
            for (int j = 0; j < array.length-1-i; j++) {
                if(array[j]>array[j+1]){
                    swap(array,j,j+1);
                    flg = true;
                }
            }
            if(flg==false){
                break;
            }
        }
    }

快速排序

Hoare法

单趟动图如下:
数据结构:排序干货!(7大排序汇总+快速排序的优化+计数排序+基数排序+桶排序),Java数据结构,排序算法,java,算法,数据结构

第一轮交换之后,6在中间,6的左边都比6小,右边都比6大

数据结构:排序干货!(7大排序汇总+快速排序的优化+计数排序+基数排序+桶排序),Java数据结构,排序算法,java,算法,数据结构

第二轮和第一轮一样,接着不停地递归下去

数据结构:排序干货!(7大排序汇总+快速排序的优化+计数排序+基数排序+桶排序),Java数据结构,排序算法,java,算法,数据结构

数据结构:排序干货!(7大排序汇总+快速排序的优化+计数排序+基数排序+桶排序),Java数据结构,排序算法,java,算法,数据结构

这些数组可以拆分并组成一棵二叉树如下图,二叉树就是左边和右边分别递归 

数据结构:排序干货!(7大排序汇总+快速排序的优化+计数排序+基数排序+桶排序),Java数据结构,排序算法,java,算法,数据结构

   public static void quickSort(int[] array){
        quick(array,0,array.length-1);
    }

    private static void quick(int[] array, int start, int end){
        if(start >= end){
            return;
        }
        //找到中间的值
        int pivot = partitionHoare(array,start,end);
        //左右分别进行递归
        quick(array,start,pivot-1);
        quick(array,pivot+1,end);
    }

接下来我们要来搞定partition的方法,也就是要找到整个序列中间值

先确定第一个元素是pivot元素

right指针负责找到比array[right]小的数字,left指针负责找到比array[left]大的数字

找到了就进行交换,直到左右指针相遇

    private static int partitionHoare(int[] array, int left, int right){
        int tmp = array[left];
        int i = left;
        //整个的循环,要求left和right相遇之后能交换数字
        while(left<right){
            //单独的循环,因为如果right--一直找不到比tmp大的数,而right不能一直减到最左边的边界
            //所以需要再规定依次left<right
            while(left<right && array[right] >= tmp){
                right--;
            }
            while (left<right && array[left] <= tmp){
                left++;
            }
            swap(array,left,right);
        }
        swap(array,i,left);
        return left;
    }

思考:

1.为什么这里要有一个等于号

数据结构:排序干货!(7大排序汇总+快速排序的优化+计数排序+基数排序+桶排序),Java数据结构,排序算法,java,算法,数据结构

如果不用=号可能会进入死循环

数据结构:排序干货!(7大排序汇总+快速排序的优化+计数排序+基数排序+桶排序),Java数据结构,排序算法,java,算法,数据结构

如果没有等于号,第一个循环因为6不大于6,right没办法--,同理left没办法++,走到后面right和left进行交换,只是相当于6和6这两个元素的下标进行交换而已,整个数组也没有进行排序

2.为什么从右边开始而不是从左边开始?

如果先走左边,有可能会出现相遇的时大的数据,最后把大的数据放在最前面

数据结构:排序干货!(7大排序汇总+快速排序的优化+计数排序+基数排序+桶排序),Java数据结构,排序算法,java,算法,数据结构

而先走右边的话可以先遇到小的,可以把小的放到前面


时间复杂度?

最好情况:

数据结构:排序干货!(7大排序汇总+快速排序的优化+计数排序+基数排序+桶排序),Java数据结构,排序算法,java,算法,数据结构

根据上方代码的递归分治思想,找到中间值,递归左边递归右边再出中间值,每次出一个中间值都是把一部分一分为二进行寻找(logn)

每次循环都有n个元素要进行遍历

最后总的时间复杂度O(n*logn)

最坏情况:

比如:1 2 3 4 5

递归时right每次找到比1小的值都要遍历n个元素,在循环中每次都要遍历n个元素检查是否进行交换

所以总的时间复杂度就是O(n^2)

⚠快排使用时,数据一般不是逆序或者有序的

⚠快排使用时,往往会有栈的溢出

数据结构:排序干货!(7大排序汇总+快速排序的优化+计数排序+基数排序+桶排序),Java数据结构,排序算法,java,算法,数据结构

这个错误跟我们递归的层次有关系,递归越多在栈上开辟的空间就越多,而IDEA默认给出的空间是256KB,这么小的空间容纳不了我们10万个数据进行栈空间的开辟

我们要对IDEA进行一个调整

数据结构:排序干货!(7大排序汇总+快速排序的优化+计数排序+基数排序+桶排序),Java数据结构,排序算法,java,算法,数据结构

数据结构:排序干货!(7大排序汇总+快速排序的优化+计数排序+基数排序+桶排序),Java数据结构,排序算法,java,算法,数据结构

数据结构:排序干货!(7大排序汇总+快速排序的优化+计数排序+基数排序+桶排序),Java数据结构,排序算法,java,算法,数据结构


挖坑法

单趟动图如下:
数据结构:排序干货!(7大排序汇总+快速排序的优化+计数排序+基数排序+桶排序),Java数据结构,排序算法,java,算法,数据结构

    private static int partitionHole(int[] array, int left, int right){
        int tmp = array[left];
        //整个的循环,要求left和right相遇之后能交换数字
        while(left<right){
            //单独的循环,因为如果right--一直找不到比tmp大的数,而right不能一直减到最左边的边界
            //所以需要再规定依次left<right
            while(left<right && array[right] >= tmp){
                right--;
            }
            array[left] = array[right];
            while (left<right && array[left] <= tmp){
                left++;
            }
            array[right] = array[left];
            swap(array,left,right);
        }
        array[left] = tmp;
        return left;
    }

前后指针法

思路:
1、选出一个key,一般是最左边或是最右边的。
2、起始时,prev指针指向序列开头,cur指针指向prev+1。
3、若cur指向的内容小于key,则prev先向后移动一位,然后交换prev和cur指针指向的内容,然后cur指针++;若cur指向的内容大于key,则cur指针直接++。如此进行下去,直到cur到达end位置,此时将key和++prev指针指向的内容交换即可。

数据结构:排序干货!(7大排序汇总+快速排序的优化+计数排序+基数排序+桶排序),Java数据结构,排序算法,java,算法,数据结构

  /**
     * 前后指针法:
     *  总结:
     *  1. Hoare 优先级: 2
     *  2. 挖坑法 优先级:1
     *  3. 前后指针法 优先级:3
     *  这3种方式  每次划分之后的前后顺序 有可能是不一样的
     * @param array
     * @param left
     * @param right
     * @return
     */
    private static int partition(int[] array, int left, int right) {
        int prev = left;
        int cur = left + 1;
        while (cur <= right) {
            if (array[cur] < array[left] && array[++prev] != array[cur]) {
                swap(array, cur, prev);
            }
            cur++;
        }

        swap(array, prev, left);
        return prev;
    }

选择题: 

对记录( 54,38,96,23,15,72,60,45,83 )进行从小到大的直接插入排序时,当把第 8 个记录 45 插入到有序表时,为找到插入位置需比较() 次?(采用从后往前比较)
A: 3 B: 4 C: 5 D: 6

这道题不要太死板地做,题目问我们第8个记录45,那么说明45之前的数字一定是有序的

数据结构:排序干货!(7大排序汇总+快速排序的优化+计数排序+基数排序+桶排序),Java数据结构,排序算法,java,算法,数据结构

那45就需要比较到比它小的数就行,很简单选C


快排的优化

上面我们提到了,快排一旦递归较多的时候容易出现栈溢出的情况

所以我们优化方向:1.减少递归次数;2.让每一次都能均匀地分割数组

三数取中法

上面提到当快排的hoare和挖坑法遇到有序数列时,l和r都跑到第一个元素去,右边有一大坨数字,无法实现取到中间数的效果

数据结构:排序干货!(7大排序汇总+快速排序的优化+计数排序+基数排序+桶排序),Java数据结构,排序算法,java,算法,数据结构

我们采用三数取中法

1.先找到数列中间下标(m)的数字

int mid = (left+right)/2;

数据结构:排序干货!(7大排序汇总+快速排序的优化+计数排序+基数排序+桶排序),Java数据结构,排序算法,java,算法,数据结构

定义大前提

 数据结构:排序干货!(7大排序汇总+快速排序的优化+计数排序+基数排序+桶排序),Java数据结构,排序算法,java,算法,数据结构

2.找出l,m,r下标的三个数字排在最中间的那个数

array[left]<array[right]

数据结构:排序干货!(7大排序汇总+快速排序的优化+计数排序+基数排序+桶排序),Java数据结构,排序算法,java,算法,数据结构

array[left]>array[right]

数据结构:排序干货!(7大排序汇总+快速排序的优化+计数排序+基数排序+桶排序),Java数据结构,排序算法,java,算法,数据结构 

        if(array[left] < array[right]){
            if(array[mid]<array[left]){
                return left;
            }else if(array[mid] > array[right]){
                return right;
            }else{
                return mid;
            }
        }else{
            //array[left] > array[right]
            if(array[mid]>array[left]){
                return left;
            }else if(array[mid] < array[right]){
                return right;
            }else{
                return mid;
            }
        }

3.把m坐标元素与l坐标元素交换

数据结构:排序干货!(7大排序汇总+快速排序的优化+计数排序+基数排序+桶排序),Java数据结构,排序算法,java,算法,数据结构

4.然后以4为基准,利用r--找到比4小的元素,把这个元素与4交换

数据结构:排序干货!(7大排序汇总+快速排序的优化+计数排序+基数排序+桶排序),Java数据结构,排序算法,java,算法,数据结构

这样就不会出现找不到左数或者右数的情况

5.接着左右子树进行遍历就行了

        if(start>=end){
            return;
        }
        //1 2 3 4 5 6 7
        int index = middleNum(array,start,end);
        swap(array,index,start);
        //4 2 3 1 5 6 7
        int pivot = partition(array,start,end);
        quick2(array,start,pivot-1);
        quick2(array,pivot+1,end);

6.排序的最终步骤一般集中在数组二叉树的最后两层,而当排序到这个地方的时候,整个数组已经偏向有序的状态了,所以我们没必要再让二叉树继续递归下去,我们可以采用插入排序,在一个很小的序列中进行排序。这样可以降低树的高度,减少递归的次数

整个的代码

    private static int middleNum(int[] array, int left,int right){
        int mid = (left+right)/2;
        //求中位数的下标
        if(array[left] < array[right]){
            if(array[mid]<array[left]){
                return left;
            }else if(array[mid] > array[right]){
                return right;
            }else{
                return mid;
            }
        }else{
            //array[left] > array[right]
            if(array[mid]>array[left]){
                return left;
            }else if(array[mid] < array[right]){
                return right;
            }else{
                return mid;
            }
        }
    }

    public static void insertSort(int[] array, int left,int right) {
        for (int i = left+1; i <= right; i++) {
            int tmp = array[i];
            int j = i - 1;
            for (; j >= left; j--) {
                if (array[j] > tmp) {
                    array[j + 1] = array[j];
                } else {
                    break;
                }
            }
            array[j + 1] = tmp;
        }
    }
    private static void quick2(int[] array, int start, int end){
        if(start>=end){
            return;
        }
        if(end-start+1<=15){
            insertSort(array,start,end);
            return;
        }
        //1 2 3 4 5 6 7
        int index = middleNum(array,start,end);
        swap(array,index,start);
        //4 2 3 1 5 6 7
        int pivot = partition(array,start,end);
        quick2(array,start,pivot-1);
        quick2(array,pivot+1,end);
    }

非递归快排

先利用挖坑法排好序

数据结构:排序干货!(7大排序汇总+快速排序的优化+计数排序+基数排序+桶排序),Java数据结构,排序算法,java,算法,数据结构

数据结构:排序干货!(7大排序汇总+快速排序的优化+计数排序+基数排序+桶排序),Java数据结构,排序算法,java,算法,数据结构

创建一个栈,把6左边第一个和最后一个元素(pivot-1)的位置放入栈中,右边同理

数据结构:排序干货!(7大排序汇总+快速排序的优化+计数排序+基数排序+桶排序),Java数据结构,排序算法,java,算法,数据结构

弹出一个9给r,弹出6给l

数据结构:排序干货!(7大排序汇总+快速排序的优化+计数排序+基数排序+桶排序),Java数据结构,排序算法,java,算法,数据结构

 再重复一次挖坑法partition方法

数据结构:排序干货!(7大排序汇总+快速排序的优化+计数排序+基数排序+桶排序),Java数据结构,排序算法,java,算法,数据结构

9右边的元素不需要递归,所以直接当成pivot 

数据结构:排序干货!(7大排序汇总+快速排序的优化+计数排序+基数排序+桶排序),Java数据结构,排序算法,java,算法,数据结构

把9左边的第一个元素下标(6)和最后一个元素(7)放入栈中

数据结构:排序干货!(7大排序汇总+快速排序的优化+计数排序+基数排序+桶排序),Java数据结构,排序算法,java,算法,数据结构 

怎么判断pivot左边和右边有多少个元素呢?

当pivot+1 = e的时候,右边只有1个元素;当pivot+1<e的时候,右边有两个或两个以上的元素

相反当pivot-1>s,左边有两个或两个以上元素

总结步骤:

1.调用partition方法找出整个数组的中间数位置pivot

2.左边有没有两个元素,下标放到栈

3.右边一样

4.判断栈空不空-->不空的话就pop两个元素出来分别交给r和l(注意最先出来的给r,慢一点的给l)

整个代码:

    public static void quickSortNor(int[] array){
        int start = 0;
        int end = array.length-1;
        Stack<Integer> stack = new Stack<>();
        int pivot = partitionHoare(array,start,end);
        if(pivot>start+1){
            stack.push(start);
            stack.push(pivot-1);
        }
        if(pivot+1<end){
            stack.push(pivot+1);
            stack.push(end);
        }
        while(!stack.isEmpty()){
            end = stack.pop();
            start=stack.pop();
            pivot = partitionHoare(array,start,end);
            if(pivot>start+1){
                stack.push(start);
                stack.push(pivot-1);
            }
            if(pivot+1<end){
                stack.push(pivot+1);
                stack.push(end);
            }
        }
    }

归并排序

分治算法+二路归并

数据结构:排序干货!(7大排序汇总+快速排序的优化+计数排序+基数排序+桶排序),Java数据结构,排序算法,java,算法,数据结构

分解:

    public static void mergeSort(int[] array){
        mergeSortFun(array,0, array.length-1);
    }

    private static void mergeSortFun(int[] array,int start,int end){
        if(start>=end){
            return;
        }
        //分解
        int mid = (start+end)/2;
        mergeSortFun(array,start,mid);
        mergeSortFun(array,mid+1,end);
        //合并
        merge(array,start,mid,end);
    }

归并方法

创建一个tmpArr数组记录排序好的数字

先进行s1和s2两个元素的比较,s2的元素比较小先扔到tmpArr里面,s2++

数据结构:排序干货!(7大排序汇总+快速排序的优化+计数排序+基数排序+桶排序),Java数据结构,排序算法,java,算法,数据结构

 接着再比较s2和s1,发现s1更小,扔到tmpArr里面,s1++

数据结构:排序干货!(7大排序汇总+快速排序的优化+计数排序+基数排序+桶排序),Java数据结构,排序算法,java,算法,数据结构

后面的步骤差不多,比较s1和s2两个元素,谁小谁放进数组

    private static void merge(int[] array, int left, int mid,int right) {
        int s1 = left;
        int e1 = mid;
        int s2 = mid+1;
        int e2 = right;
        int[] tmpArr = new int[right-left+1];
        int k = 0;//tmpArr的下标
        //同时满足两个归并段都有数据
        while(s1 <= e1 && s2 <= e2){
            if(array[s1] <= array[s2]){
                tmpArr[k++] = array[s1++];
            }else{
                tmpArr[k++] = array[s2++];
            }
        }
        while(s1 <= e1){
            tmpArr[k++] = array[s1++];
        }
        while(s2 <= e2){
            tmpArr[k++] = array[s2++];
        }
        //把排好的数据拷贝回原来的数组array中
        for (int i = 0; i < tmpArr.length; i++) {
            array[i+left] = tmpArr[i];
        }
    }

时间复杂度

每次都要遍历n个元素,而分解过程分治算法和二路归并的复杂度logn

总的复杂度O(N*logN)

数据结构:排序干货!(7大排序汇总+快速排序的优化+计数排序+基数排序+桶排序),Java数据结构,排序算法,java,算法,数据结构

稳定性:稳定


非递归归并

数据结构:排序干货!(7大排序汇总+快速排序的优化+计数排序+基数排序+桶排序),Java数据结构,排序算法,java,算法,数据结构

先让每组的两个数据进行排序,接着再让两个组的四个数据进行排序

每组一个数据进行排序

数据结构:排序干货!(7大排序汇总+快速排序的优化+计数排序+基数排序+桶排序),Java数据结构,排序算法,java,算法,数据结构

两组的数据排序

数据结构:排序干货!(7大排序汇总+快速排序的优化+计数排序+基数排序+桶排序),Java数据结构,排序算法,java,算法,数据结构 

数据结构:排序干货!(7大排序汇总+快速排序的优化+计数排序+基数排序+桶排序),Java数据结构,排序算法,java,算法,数据结构

        int gap = 1;
        while(gap<array.length){
            for (int i = 0; i < array.length; i = i+gap*2) {
                int left = i;
                int mid = left+gap-1;
                int right = mid+gap;

                merge(array,left,mid,right);
            }
            gap*=2;
        }

mid和right的定义方式可能会有越界的风险

所以我们需要进行风险修正

                if(mid >= array.length){
                    mid = array.length-1;
                }
                if(right>=array.length){
                    right = array.length-1;
                }

整个代码:

    public static void mergeSortNor(int[] array){
        int gap = 1;
        while(gap<array.length){
            for (int i = 0; i < array.length; i = i+gap*2) {
                int left = i;
                int mid = left+gap-1;
                int right = mid+gap;
                if(mid >= array.length){
                    mid = array.length-1;
                }
                if(right>=array.length){
                    right = array.length-1;
                }
                merge(array,left,mid,right);
            }
            gap*=2;
        }
    }

应用

前提:内存只有 1G ,需要排序的数据有 100G
因为内存中因为无法把所有数据全部放下,所以需要外部排序,而归并排序是最常用的外部排序

1.先把文件切割成200份,每个512M

数据结构:排序干货!(7大排序汇总+快速排序的优化+计数排序+基数排序+桶排序),Java数据结构,排序算法,java,算法,数据结构2.分别对512M排序,任意排序都行,因为内存放的下

数据结构:排序干货!(7大排序汇总+快速排序的优化+计数排序+基数排序+桶排序),Java数据结构,排序算法,java,算法,数据结构3.进行2路归并,同时对200份有序文件做归并过程,最终结果就是有序了

数据结构:排序干货!(7大排序汇总+快速排序的优化+计数排序+基数排序+桶排序),Java数据结构,排序算法,java,算法,数据结构


排序总结

数据结构:排序干货!(7大排序汇总+快速排序的优化+计数排序+基数排序+桶排序),Java数据结构,排序算法,java,算法,数据结构


其他排序

计数排序

简单版本

有这么一组数字,要求你进行排序,注意这组数组在0~9之间

数据结构:排序干货!(7大排序汇总+快速排序的优化+计数排序+基数排序+桶排序),Java数据结构,排序算法,java,算法,数据结构

1.先申请一个计数数组count,设置一个i,定义co把每个数字出现的次数记录下来。i遍历上面的数字,每次遍历到重复的数字就co++(count[array[i] - minVal]++)

数据结构:排序干货!(7大排序汇总+快速排序的优化+计数排序+基数排序+桶排序),Java数据结构,排序算法,java,算法,数据结构

⚠计数数组上面的数字代表数组里面出现的数字,不是下标
数据结构:排序干货!(7大排序汇总+快速排序的优化+计数排序+基数排序+桶排序),Java数据结构,排序算法,java,算法,数据结构

如果不一定是以0为最小值的呢?

那我们就需要定义数组最小值minVal和最大值maxVal了

        int minVal = array[0];
        int maxVal = array[0];
        for (int i = 0; i < array.length; i++) {
            if(array[i]<minVal){
                minVal = array[i];
            }
            if(array[i]>maxVal){
                maxVal=array[i];
            }
        }

数组长度?

        //确定计数数组的长度
        int len = maxVal-minVal+1;
        int[] count = new int[len];
        //遍历array数组 把数据出现的次数存储到计数数组中
        for (int i = 0; i < array.length; i++) {
            count[array[i]-minVal]++;
        }

2.设置一个i遍历这个计数数组,把每个数字重复(如果有)记录下来并写回原来的数组

数据结构:排序干货!(7大排序汇总+快速排序的优化+计数排序+基数排序+桶排序),Java数据结构,排序算法,java,算法,数据结构

 

        //遍历计数数组,把实际的数组写回array数组
        int index = 0;
        for (int i = 0; i < count.length; i++) {
            while(count[i]>0){
                //这里需要写回array,得从array的0位置开始写
                array[index] = i+minVal;
                index++;
                //每次写进array一个元素,计数数组的对应元素数量就得减少
                count[i]--;
            }
        }

整个代码:

    public static void countSort(int[] array){
        //求数组最大值和最小值  O(N)
        int minVal = array[0];
        int maxVal = array[0];
        for (int i = 0; i < array.length; i++) {
            if(array[i]<minVal){
                minVal = array[i];
            }
            if(array[i]>maxVal){
                maxVal=array[i];
            }
        }
        //确定计数数组的长度
        int len = maxVal-minVal+1;
        int[] count = new int[len];

        //遍历array数组 把数据出现的次数存储到计数数组中    O(N)
        for (int i = 0; i < array.length; i++) {
            count[array[i]-minVal]++;
        }
        //遍历计数数组,把实际的数组写回array数组 
        //跟最大值和最小值有关系,所以是O(范围)
        int index = 0;
        for (int i = 0; i < count.length; i++) {
            while(count[i]>0){
                //这里需要写回array,得从array的0位置开始写
                array[index] = i+minVal;
                index++;
                //每次写进array一个元素,计数数组的对应元素数量就得减少
                count[i]--;
            }
        }
    }

时间复杂度:O(MAX(N, 范围))

空间复杂度:O(范围)

稳定性:不稳定


复杂版本(稳定版本)

这里字数太多(主要是我懒~),大家可以去看这篇博客计数排序 - 知乎 (zhihu.com)

数据结构:排序干货!(7大排序汇总+快速排序的优化+计数排序+基数排序+桶排序),Java数据结构,排序算法,java,算法,数据结构


基数排序 

基数排序动图演示

数据结构:排序干货!(7大排序汇总+快速排序的优化+计数排序+基数排序+桶排序),Java数据结构,排序算法,java,算法,数据结构

从低位到高位数字,让每位数字依次有序

代码见下:

1.10 基数排序 | 菜鸟教程 (runoob.com) 


桶排序 

【排序】图解桶排序_桶排序图解-CSDN博客文章来源地址https://www.toymoban.com/news/detail-741090.html

到了这里,关于数据结构:排序干货!(7大排序汇总+快速排序的优化+计数排序+基数排序+桶排序)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Leetcode刷题(数据结构)】:三路划分与三数随机取中的思想实现快速排序的再优化

    快速排序是Hoare于1962年提出的一种二叉树结构的交换排序方法,其基本思想为:任取待排序元素序列中 的某元素作为基准值,按照该排序码将待排序集合分割成两子序列,左子序列中所有元素均小于基准值,右 子序列中所有元素均大于基准值,然后最左右子序列重复该过程

    2024年02月08日
    浏览(46)
  • 【数据结构】快速排序,归并排序

    1.hoare版本 根据动图的演示,整理的思路如下, 1.定义left,right,key。key默认是左边第一个元素,像两个指针,左边找比key大的,右边找比k小的,找到的话,交换二者,往返这个过程,当left与right相遇时,交换key和此时相遇的值. 单趟下来,6出现在正确的位置。 1.为什么大循环

    2024年01月20日
    浏览(41)
  • 【数据结构】排序(2)—冒泡排序 & 快速排序

                                      目录 一. 冒泡排序 基本思想 代码实现 时间和空间复杂度 稳定性 二. 快速排序 基本思想 代码实现 hoare法 挖坑法 前后指针法 时间和空间复杂度 稳定性            冒泡排序是一种交换排序。两两比较数组元素,如果是逆序(即排列顺序

    2024年02月08日
    浏览(79)
  • 数据结构——排序算法之快速排序

        个人主页: 日刷百题 系列专栏 : 〖C/C++小游戏〗 〖Linux〗 〖数据结构〗   〖C语言〗 🌎 欢迎各位 → 点赞 👍+ 收藏 ⭐️+ 留言 📝  ​ ​ 快速排序是Hoare于1962年提出的一种二叉树结构的交换排序方法。 基本思想: 任取待排序元素序列中 的某元素作为基准值,按照

    2024年01月21日
    浏览(58)
  • 【数据结构--八大排序】之快速排序

    💐 🌸 🌷 🍀 🌹 🌻 🌺 🍁 🍃 🍂 🌿 🍄🍝 🍛 🍤 📃 个人主页 :阿然成长日记 👈点击可跳转 📆 个人专栏: 🔹数据结构与算法🔹C语言进阶 🚩 不能则学,不知则问,耻于问人,决无长进 🍭 🍯 🍎 🍏 🍊 🍋 🍒 🍇 🍉 🍓 🍑 🍈 🍌 🍐 🍍 前言: 前面,我花费

    2024年02月08日
    浏览(51)
  • Mysql数据库结构优化汇总

         设计表以最大限度地减少其在磁盘上的空间。这可以减少写入磁盘和从磁盘读取的数据量,从而带来巨大的改进。较小的表通常需要较少的主内存,而它们的内容在查询执行过程中被主动处理。表数据的任何空间减少也会导致更小的索引可以更快地处理。 尽可能使用最

    2024年02月07日
    浏览(49)
  • 数据结构--快速排序

    快速排序是通过二叉树的思想,先设定一个值,通过比较,比它大的放在它的右边,比它小的放在它的左边;这样相当于在二叉树中,小的放在左子树,大的放在右子树,设定的值就是根;再通过递归的思想,将它们继续按这种方式进行排序,排到最后就排好了;这就是快速

    2024年02月08日
    浏览(40)
  • 【数据结构】快速排序详解

    目录 一、基本介绍 二、快排的实现 1. 调试环境 2.快排的单趟排序 (1)Hoare版本 (2)挖坑法 (3)前后指针法 2.递归过程 三、快排的优化 1. 优化取key方式,防止栈溢出 2. 小区间优化 四、快排的非递归方式         排序算法是日常使用最频繁的一个算法,生活中也很常

    2024年02月09日
    浏览(39)
  • 【数据结构与算法】排序算法:冒泡排序,冒泡排序优化,选择排序、选择排序优化

    目录 一、冒泡排序 1、冒泡排序思想 2、冒泡排序算法的性能分析 代码实现: 二、选择排序 1、选择排序思想 2、选择排序算法的性能分析  代码实现: 1、冒泡排序思想 冒泡排序的基本思想是通过相邻元素之间的比较和交换来逐步将最大(或最小)的元素移到右边(或左边

    2024年01月19日
    浏览(50)
  • 【数据结构与算法】:选择排序与快速排序

    🔥 个人主页 : Quitecoder 🔥 专栏 :数据结构与算法 我的博客即将同步至腾讯云开发者社区,邀请大家一同入驻:腾讯云 欢迎来到排序的第二个部分:选择排序与快速排序! 选择排序是一种简单直观的比较排序算法。该算法的基本思想是在每一轮中选出当前未排序部分的最

    2024年03月17日
    浏览(52)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包