数组排序算法

一、冒泡排序

​ 原理:元素两两比较,交换位置,大元素往后放,经过一轮轮比较,每次都少比一次,每次最大的元素就会出现在最大索引处。

public class SortDemo01 {
    public static void main(String[] args) {
        int[] arr={10,101,20,9,901};//5个数,需要比较4轮比较
        //总共比较多少轮,5个数,需要比较4轮比较
        for (int j = 0; j < arr.length - 1; j++) {
            //每加一轮少比一次,所以每次要多减1个数j=0,1,2,3
            for (int i = 0; i < arr.length -1 -j; i++) {
                //两两比较
                //如果前面元素比后面的大,交换位置
                if (arr[i]>arr[i+1]){
                    int t=arr[i];
                    arr[i]=arr[i+1];
                    arr[i+1]=t;
                }
                System.out.println(Arrays.toString(arr));//输出数组
            }
            System.out.println("++++++++++++++++++++++++");
        }
        //System.out.println(Arrays.toString(arr));//输出数组
    }
}
//输出

/*	
[10, 101, 20, 9, 901]	
[10, 20, 101, 9, 901]
[10, 20, 9, 101, 901]
[10, 20, 9, 101, 901]
++++++++++++++++++++++++
[10, 20, 9, 101, 901]
[10, 9, 20, 101, 901]
[10, 9, 20, 101, 901]
++++++++++++++++++++++++
[9, 10, 20, 101, 901]
[9, 10, 20, 101, 901]
+++++++++++++++++++++++
[9, 10, 20, 101, 901]
++++++++++++++++++++++++
*/

二、选择排序

​ 原理:从0索引处开始,依次和后面的元素进行比较,小的元素前移

public class SortDemo02 {
    public static void main(String[] args) {
        //选择排序
        //从索引为0处的元素依次和后面的元素进行比较,小的元素前移
        int[] arr={80,24,69,57,5};//个数为4
        //每轮比较索引+1,总共有4轮
        for (int index = 0; index < arr.length-1; index++) {
            //每轮比较将后一位和前一们进行比较,小的提前
            /*
            	第一轮:比较4次
            	第二轮:比较3次
            	第三轮:比较2次
            	第四轮:比较1次
            */
            for (int i = 1+index; i < arr.length; i++) {
                if(arr[index]>arr[i]){
                    int t=arr[index];
                    arr[index]=arr[i];
                    arr[i]=t;
                }
                System.out.println(Arrays.toString(arr));
            }
            System.out.println("+++++++++++++++++++++++++++++");
        }
    }
}
//输出
/*
[24, 80, 69, 57, 5]
[24, 80, 69, 57, 5]
[24, 80, 69, 57, 5]
[5, 80, 69, 57, 24]
+++++++++++++++++++++++++++++
[5, 69, 80, 57, 24]
[5, 57, 80, 69, 24]
[5, 24, 80, 69, 57]
+++++++++++++++++++++++++++++
[5, 24, 69, 80, 57]
[5, 24, 57, 80, 69]
+++++++++++++++++++++++++++++
[5, 24, 57, 69, 80]
+++++++++++++++++++++++++++++
*/

三、直接插入排序

​ 原理:从索引1开始,将元素一个个插入到之前的有序表中,使之仍然有序.

​ 从索引用1开始,每个数和前面的数比较,比其小的数就插入其前面,比他大的数不变

import java.util.Arrays;

public class SortDemo04 {
    public static void main(String[] args) {
        //直接插入排序
        int[] arr={46,55,13,42,17,94,5,70};
        Sort(arr);
    }
    private static void Sort(int[] arr) {
        for (int i = 1; i < arr.length; i++) {
            int j=i;
            while(j>0&&arr[j]<arr[j-1]){
                int t=arr[j-1];
                arr[j-1]=arr[j];
                arr[j]=t;
                j--;
                System.out.println(Arrays.toString(arr));
            }
            System.out.println("第"+i+"轮排序最终结果"+Arrays.toString(arr));
            System.out.println("===============================");
        }
    }
}
/*
第1轮排序最终结果[46, 55, 13, 42, 17, 94, 5, 70]
===============================
[46, 13, 55, 42, 17, 94, 5, 70]
[13, 46, 55, 42, 17, 94, 5, 70]
第2轮排序最终结果[13, 46, 55, 42, 17, 94, 5, 70]
===============================
[13, 46, 42, 55, 17, 94, 5, 70]
[13, 42, 46, 55, 17, 94, 5, 70]
第3轮排序最终结果[13, 42, 46, 55, 17, 94, 5, 70]
===============================
[13, 42, 46, 17, 55, 94, 5, 70]
[13, 42, 17, 46, 55, 94, 5, 70]
[13, 17, 42, 46, 55, 94, 5, 70]
第4轮排序最终结果[13, 17, 42, 46, 55, 94, 5, 70]
===============================
第5轮排序最终结果[13, 17, 42, 46, 55, 94, 5, 70]
===============================
[13, 17, 42, 46, 55, 5, 94, 70]
[13, 17, 42, 46, 5, 55, 94, 70]
[13, 17, 42, 5, 46, 55, 94, 70]
[13, 17, 5, 42, 46, 55, 94, 70]
[13, 5, 17, 42, 46, 55, 94, 70]
[5, 13, 17, 42, 46, 55, 94, 70]
第6轮排序最终结果[5, 13, 17, 42, 46, 55, 94, 70]
===============================
[5, 13, 17, 42, 46, 55, 70, 94]
第7轮排序最终结果[5, 13, 17, 42, 46, 55, 70, 94]
===============================
*/

四、希尔排序

​ 原理:是对直接插入排序的优化,通过设置增量(步长),对相同步长间隔的元素进行比较,然后不断缩减增量,最终使增量为1,完成排序。

​ 直接插入排序可以看成增量为1的希尔排序。

举例:设增量从4开始缩减

import java.util.Arrays;

public class SortDemo04 {
    public static void main(String[] args) {
        //希尔排序
        int[] arr={46,55,13,42,17,94,5,70};
        shellSort(arr);
    }
    //希尔排序是对直接插入排序的优化,通过设置增量(步长),
    //对相同步长间隔的元素进行比较,然后不断缩减增量,最终使增量为1,完成排序。
    //直接插入排序可以看成增量为1的希尔排序。
    private static void shellSort(int[] arr) {
        int h=4;//增量
        System.out.println("增量:4");
        for (int i = h; i < arr.length; i++) {
            int j=i;
            while(j>h-1&&arr[j]<arr[j-h]){
                int t=arr[j-h];
                arr[j-h]=arr[j];
                arr[j]=t;
                j-=h;
                System.out.println(Arrays.toString(arr));
            }
            System.out.println("第"+(i-h+1)+"轮排序最终结果"+Arrays.toString(arr));
            System.out.println("===============================");
        }
        System.out.println("**");
        System.out.println("**");
        System.out.println("**");    
        System.out.println("**");
        System.out.println("**");
        h=2;//增量
        System.out.println("增量:2");
        for (int i = h; i < arr.length; i++) {
            int j=i;
            while(j>h-1&&arr[j]<arr[j-h]){
                int t=arr[j-h];
                arr[j-h]=arr[j];
                arr[j]=t;
                j-=h;
                System.out.println(Arrays.toString(arr));
            }
            System.out.println("第"+(i-h+1)+"轮排序最终结果"+Arrays.toString(arr));
            System.out.println("===============================");
        }
        System.out.println("**");
        System.out.println("**");
        System.out.println("**");
        System.out.println("**");
        System.out.println("**");
        h=1;//增量
        System.out.println("增量:1");
        for (int i = h; i < arr.length; i++) {
            int j=i;
            while(j>h-1&&arr[j]<arr[j-h]){
                int t=arr[j-h];
                arr[j-h]=arr[j];
                arr[j]=t;
                j-=h;
                System.out.println(Arrays.toString(arr));
            }
            System.out.println("第"+(i-h+1)+"轮排序最终结果"+Arrays.toString(arr));
            System.out.println("===============================");
        }
    }
}
/*
增量:4
[17, 55, 13, 42, 46, 94, 5, 70]
第1轮排序最终结果[17, 55, 13, 42, 46, 94, 5, 70]
===============================
第2轮排序最终结果[17, 55, 13, 42, 46, 94, 5, 70]
===============================
[17, 55, 5, 42, 46, 94, 13, 70]
第3轮排序最终结果[17, 55, 5, 42, 46, 94, 13, 70]
===============================
第4轮排序最终结果[17, 55, 5, 42, 46, 94, 13, 70]
===============================
**
**
**
**
**
增量:2
[5, 55, 17, 42, 46, 94, 13, 70]
第1轮排序最终结果[5, 55, 17, 42, 46, 94, 13, 70]
===============================
[5, 42, 17, 55, 46, 94, 13, 70]
第2轮排序最终结果[5, 42, 17, 55, 46, 94, 13, 70]
===============================
第3轮排序最终结果[5, 42, 17, 55, 46, 94, 13, 70]
===============================
第4轮排序最终结果[5, 42, 17, 55, 46, 94, 13, 70]
===============================
[5, 42, 17, 55, 13, 94, 46, 70]
[5, 42, 13, 55, 17, 94, 46, 70]
第5轮排序最终结果[5, 42, 13, 55, 17, 94, 46, 70]
===============================
[5, 42, 13, 55, 17, 70, 46, 94]
第6轮排序最终结果[5, 42, 13, 55, 17, 70, 46, 94]
===============================
**
**
**
**
**
增量:1
第1轮排序最终结果[5, 42, 13, 55, 17, 70, 46, 94]
===============================
[5, 13, 42, 55, 17, 70, 46, 94]
第2轮排序最终结果[5, 13, 42, 55, 17, 70, 46, 94]
===============================
第3轮排序最终结果[5, 13, 42, 55, 17, 70, 46, 94]
===============================
[5, 13, 42, 17, 55, 70, 46, 94]
[5, 13, 17, 42, 55, 70, 46, 94]
第4轮排序最终结果[5, 13, 17, 42, 55, 70, 46, 94]
===============================
第5轮排序最终结果[5, 13, 17, 42, 55, 70, 46, 94]
===============================
[5, 13, 17, 42, 55, 46, 70, 94]
[5, 13, 17, 42, 46, 55, 70, 94]
第6轮排序最终结果[5, 13, 17, 42, 46, 55, 70, 94]
===============================
第7轮排序最终结果[5, 13, 17, 42, 46, 55, 70, 94]
===============================
*/

简化:可以取数组长度的一半来做为增量

import java.util.Arrays;

public class SortDemo04 {
    public static void main(String[] args) {
        //希尔排序
        int[] arr={46,55,13,42,17,94,5,70};
        shellSort(arr);
    }
    //希尔排序是对直接插入排序的优化,通过设置增量(步长),
    //对相同步长间隔的元素进行比较,然后不断缩减增量,最终使增量为1,完成排序。
    //直接插入排序可以看成增量为1的希尔排序。
    private static void shellSort(int[] arr) {
        for (int h = arr.length/2; h > 0; h/=2) {
            System.out.println("增量:"+h);
            for (int i = h; i < arr.length; i++) {
                int j=i;
                while(j>h-1&&arr[j]<arr[j-h]){
                    int t=arr[j-h];
                    arr[j-h]=arr[j];
                    arr[j]=t;
                    j-=h;
                    System.out.println(Arrays.toString(arr));
                }
                System.out.println("第"+(i-h+1)+"轮排序最终结果"+Arrays.toString(arr));
                System.out.println("===============================");
            }
            System.out.println("**");
            System.out.println("**");
            System.out.println("**");
            System.out.println("**");
            System.out.println("**");
        }
    }
}
/*
增量:4
[17, 55, 13, 42, 46, 94, 5, 70]
第1轮排序最终结果[17, 55, 13, 42, 46, 94, 5, 70]
===============================
第2轮排序最终结果[17, 55, 13, 42, 46, 94, 5, 70]
===============================
[17, 55, 5, 42, 46, 94, 13, 70]
第3轮排序最终结果[17, 55, 5, 42, 46, 94, 13, 70]
===============================
第4轮排序最终结果[17, 55, 5, 42, 46, 94, 13, 70]
===============================
**
**
**
**
**
增量:2
[5, 55, 17, 42, 46, 94, 13, 70]
第1轮排序最终结果[5, 55, 17, 42, 46, 94, 13, 70]
===============================
[5, 42, 17, 55, 46, 94, 13, 70]
第2轮排序最终结果[5, 42, 17, 55, 46, 94, 13, 70]
===============================
第3轮排序最终结果[5, 42, 17, 55, 46, 94, 13, 70]
===============================
第4轮排序最终结果[5, 42, 17, 55, 46, 94, 13, 70]
===============================
[5, 42, 17, 55, 13, 94, 46, 70]
[5, 42, 13, 55, 17, 94, 46, 70]
第5轮排序最终结果[5, 42, 13, 55, 17, 94, 46, 70]
===============================
[5, 42, 13, 55, 17, 70, 46, 94]
第6轮排序最终结果[5, 42, 13, 55, 17, 70, 46, 94]
===============================
**
**
**
**
**
增量:1
第1轮排序最终结果[5, 42, 13, 55, 17, 70, 46, 94]
===============================
[5, 13, 42, 55, 17, 70, 46, 94]
第2轮排序最终结果[5, 13, 42, 55, 17, 70, 46, 94]
===============================
第3轮排序最终结果[5, 13, 42, 55, 17, 70, 46, 94]
===============================
[5, 13, 42, 17, 55, 70, 46, 94]
[5, 13, 17, 42, 55, 70, 46, 94]
第4轮排序最终结果[5, 13, 17, 42, 55, 70, 46, 94]
===============================
第5轮排序最终结果[5, 13, 17, 42, 55, 70, 46, 94]
===============================
[5, 13, 17, 42, 55, 46, 70, 94]
[5, 13, 17, 42, 46, 55, 70, 94]
第6轮排序最终结果[5, 13, 17, 42, 46, 55, 70, 94]
===============================
第7轮排序最终结果[5, 13, 17, 42, 46, 55, 70, 94]
===============================
*/

最终版:常常采用克努特(Kunth)间隔数列来计算最佳增量。

克努特(Kunth)间隔数列:h=3h+1--->1、4、13、40、121、364...

融合到希尔排序中,即选取h=3h+1的最大取值为增量,每次不断缩减h=(h-1)/3--->...364、121、40、13、4、1

import java.util.Arrays;

public class SortDemo04 {
    public static void main(String[] args) {
        //希尔排序
        int[] arr={46,55,13,42,17,94,5,70,15,14,2,4,13,89};
        shellSort(arr);
    }
    //希尔排序是对直接插入排序的优化,通过设置增量(步长),
    //对相同步长间隔的元素进行比较,然后不断缩减增量,最终使增量为1,完成排序。
    //直接插入排序可以看成增量为1的希尔排序。
    private static void shellSort(int[] arr) {
        int interval=1;//通过克努特数列来计算最佳增量取值
        while(interval*3+1<=arr.length){
            interval=interval*3+1;

        }
        for (int h = interval; h > 0; h=(h-1)/3) {
            System.out.println("增量:"+h);
            for (int i = h; i < arr.length; i++) {
                int j=i;
                while(j>h-1&&arr[j]<arr[j-h]){
                    int t=arr[j-h];
                    arr[j-h]=arr[j];
                    arr[j]=t;
                    j-=h;
                    System.out.println(Arrays.toString(arr));
                }
                System.out.println("第"+(i-h+1)+"轮排序最终结果"+Arrays.toString(arr));
                System.out.println("===============================");
            }
            System.out.println("**");
            System.out.println("**");
            System.out.println("**");
            System.out.println("**");
            System.out.println("**");
        }
    }
}
/*
增量:13
**
**
**
**
**
增量:4
[17, 55, 13, 42, 46, 94, 5, 70]
第1轮排序最终结果[17, 55, 13, 42, 46, 94, 5, 70]
===============================
第2轮排序最终结果[17, 55, 13, 42, 46, 94, 5, 70]
===============================
[17, 55, 5, 42, 46, 94, 13, 70]
第3轮排序最终结果[17, 55, 5, 42, 46, 94, 13, 70]
===============================
第4轮排序最终结果[17, 55, 5, 42, 46, 94, 13, 70]
===============================
**
**
**
**
**
增量:2
[5, 55, 17, 42, 46, 94, 13, 70]
第1轮排序最终结果[5, 55, 17, 42, 46, 94, 13, 70]
===============================
[5, 42, 17, 55, 46, 94, 13, 70]
第2轮排序最终结果[5, 42, 17, 55, 46, 94, 13, 70]
===============================
第3轮排序最终结果[5, 42, 17, 55, 46, 94, 13, 70]
===============================
第4轮排序最终结果[5, 42, 17, 55, 46, 94, 13, 70]
===============================
[5, 42, 17, 55, 13, 94, 46, 70]
[5, 42, 13, 55, 17, 94, 46, 70]
第5轮排序最终结果[5, 42, 13, 55, 17, 94, 46, 70]
===============================
[5, 42, 13, 55, 17, 70, 46, 94]
第6轮排序最终结果[5, 42, 13, 55, 17, 70, 46, 94]
===============================
**
**
**
**
**
增量:1
第1轮排序最终结果[5, 42, 13, 55, 17, 70, 46, 94]
===============================
[5, 13, 42, 55, 17, 70, 46, 94]
第2轮排序最终结果[5, 13, 42, 55, 17, 70, 46, 94]
===============================
第3轮排序最终结果[5, 13, 42, 55, 17, 70, 46, 94]
===============================
[5, 13, 42, 17, 55, 70, 46, 94]
[5, 13, 17, 42, 55, 70, 46, 94]
第4轮排序最终结果[5, 13, 17, 42, 55, 70, 46, 94]
===============================
第5轮排序最终结果[5, 13, 17, 42, 55, 70, 46, 94]
===============================
[5, 13, 17, 42, 55, 46, 70, 94]
[5, 13, 17, 42, 46, 55, 70, 94]
第6轮排序最终结果[5, 13, 17, 42, 46, 55, 70, 94]
===============================
第7轮排序最终结果[5, 13, 17, 42, 46, 55, 70, 94]
===============================
*/

经测试,并不是所有的数组最佳排序算法都是用克努特序列,其步长的选择有时并不一定是最佳的,但大多数是循环调用次数最少的,相比于直接插入排序,调用少了太多,自行测试吧

五、快速排序

​ 原理:分治法,再分区。

​ 1.先取一个基准数,在通过基准数来进行比较

​ 2.将比这个数大的放右边,将比这个数小的放左边

​ 3.不断重复

实现:

​ 1.采用挖坑填数的思想

​ 2.先找一个基准数,一般取第一个元素

​ 3.将这个基准数挖出,从右往左,如果遇到比基准数小的,将这个数挖出放入前一个坑中,此时坑已经变了,再变换方向

​ 4.从左往右,如果遇到比基准数大的,将这个数挖出放入前一个坑中,此时坑已经变了,再变换方向到第二步,如此循环下去,直到坑位与上一个坑位重合,最后将基准数填入最后一个坑中

​ 5.重选基准数,直到排序完成(通过回调的方式实现)

import java.util.Arrays;
public class SortDemo05 {
    static int flag=0;
    public static void main(String[] args) {
        //快速排序
        //1.先取一个基准数,在通过基准数来进行比较
        //2.将比这个数大的放右边,将比这个数小的放左边
        //3.不断重复
        int[] arr={4,9,8,7,6,5,342,523};
        System.out.println("原始数组"+Arrays.toString(arr));
        sort(arr,0,arr.length-1);
        System.out.println("最终排序结果"+Arrays.toString(arr));
    }
    private static void sort(int[] arr, int start, int end) {
        if (start<end){
            int index=getIndex(arr,start,end);
            sort(arr,start,index-1);
            sort(arr,index+1,end);
        }
    }
    private static int getIndex(int[] arr, int start, int end) {
        int i=start;
        int j=end;
        int x=arr[i];//基准数
        flag++;//标志位++
        while(i<j){
            //从右往左,如果遇到比基准数小的,将这个数挖出放入前一个坑中,此时坑已经变了,再变换方向
            while(i<j&&arr[j]>=x){
                j--;//遇不到,则把j--,与前一个数继续比较
            }
            if (i < j) {
                arr[i]=arr[j];
                System.out.println("第"+flag+"轮while1"+Arrays.toString(arr));
                i++;//从左边的下一位开始比,因此要++
            }
            //从左往右,如果遇到比基准数大的,将这个数挖出放入前一个坑中,此时坑已经变了,再变换方向
            while(i<j&&arr[i]<x){
                i++;
            }
            if (i < j) {
                arr[j]=arr[i];
                System.out.println("第"+flag+"轮while2"+Arrays.toString(arr));
                j--;//从右边的下一位开始比,因此要++
            }
        }
        arr[i]=x;//将基准数放到最后一个坑中
        System.out.println("第"+flag+"轮"+Arrays.toString(arr));
        System.out.println("index="+i);
        return i;//返回最终的索引,通过+1,-1来进行回调
    }
}
/*
输出结果:
原始数组[4, 9, 8, 7, 6, 5, 342, 523]
第1轮[4, 9, 8, 7, 6, 5, 342, 523]
index=0
第2轮while1[4, 5, 8, 7, 6, 5, 342, 523]
第2轮[4, 5, 8, 7, 6, 9, 342, 523]
index=5
第3轮[4, 5, 8, 7, 6, 9, 342, 523]
index=1
第4轮while1[4, 5, 6, 7, 6, 9, 342, 523]
第4轮[4, 5, 6, 7, 8, 9, 342, 523]
index=4
第5轮[4, 5, 6, 7, 8, 9, 342, 523]
index=2
第6轮[4, 5, 6, 7, 8, 9, 342, 523]
index=6
最终排序结果[4, 5, 6, 7, 8, 9, 342, 523]
*/

image-20211202234952670

六、归并排序

原理:

  1. 先分成长度为1的子序列
  2. 将数组的每个元素看成是一个有序的子序列,两两归并,再两两归并,直到长度与数组长度相等,这个排序称为2路并归排序。

image-20211205134354382

​ 先分后治:分是对半分

实现思路:

  1. 先拆分:用递归的方式通过取中间索引不断的进行拆分,直到其长度为1,无法在拆分,
  2. 在拆分的最后调用归并函数,因为递归是层层调用后返回到上一层,在每次拆分到最后时进行归并,并不断的向上归并
  3. 归并需要创建一个临时数组,用来存放归并后的元素
import java.util.Arrays;
public class SortDemo {
    public static void main(String[] args) {
        //原始数组
        int[] arr={10,30,2,1,0,8,7,5};
        //归并测试数组,从中间分开
        //int[] arr={4,5,7,8,1,2,3,6};
        //拆分
        charFen(arr,0,arr.length-1);
        //归并测试
        //guiBing(arr,0,arr.length/2-1,arr.length-1);//3为中间索引
        System.out.println((Arrays.toString(arr)));
    }
	//是chaifen。。,打错
    private static void charFen(int[] arr, int startIndex, int endIndex) {
        int centerIndex=(startIndex+endIndex)/2;
        if (startIndex<endIndex){
            //10,30,2,1,0,8,7,5,19,29
            charFen(arr,startIndex,centerIndex);
            charFen(arr,centerIndex+1,endIndex);
            guiBing(arr,startIndex,centerIndex,endIndex);      
        }
    }
    private static void guiBing(int[] arr, int startIndex, int centerIndex, int endIndex) {//001
        //定义一个临时数组,要动态的定义数组长度,不能写死
        int[] tempArr=new int[endIndex-startIndex+1];
        //定义左起始索引
        int i=startIndex;
        //定义右数组起始索引
        int j=centerIndex+1;
        int index=0;//临时数组的起始索引
        //比较左右两个数组的元素大小,往临时数组里放
        while(i<=centerIndex && j<=endIndex){
            if (arr[i]<=arr[j]){
                 tempArr[index]=arr[i];
                 i++;
                System.out.println("1."+Arrays.toString(tempArr));
                System.out.println("---------------------------------");
            }else{
                tempArr[index]=arr[j];
                j++;
                System.out.println("2."+Arrays.toString(tempArr));
                System.out.println("---------------------------------");
            }
            index++;
        }
        //处理剩余元素
        while(i<=centerIndex){
            tempArr[index]=arr[i];
            i++;
            index++;
            System.out.println("3."+Arrays.toString(tempArr));
            System.out.println("---------------------------------");
        }
        while(j<=endIndex){
            tempArr[index]=arr[j];
            j++;
            index++;
            System.out.println("4."+Arrays.toString(tempArr));
            System.out.println("---------------------------------");
        }
        //将临时数组的元素赋值到arr中
        for (int k = 0; k < tempArr.length; k++) {
            arr[k+startIndex]=tempArr[k];
        }
    }
}
//如果有3个数,刚好两个条件的循环会不满足,因为不对称,会调用单个条件的循环如调用3.
/*
输出
1.[10, 0]
---------------------------------
4.[10, 30]
---------------------------------
2.[2, 0, 0]
---------------------------------
3.[2, 10, 0]
---------------------------------
3.[2, 10, 30]
---------------------------------
2.[0, 0]
---------------------------------
3.[0, 1]
---------------------------------
2.[0, 0, 0, 0, 0]
---------------------------------
2.[0, 1, 0, 0, 0]
---------------------------------
3.[0, 1, 2, 0, 0]
---------------------------------
3.[0, 1, 2, 10, 0]
---------------------------------
3.[0, 1, 2, 10, 30]
---------------------------------
2.[7, 0]
---------------------------------
3.[7, 8]
---------------------------------
1.[5, 0]
---------------------------------
4.[5, 5]
---------------------------------
2.[5, 0, 0, 0]
---------------------------------
2.[5, 5, 0, 0]
---------------------------------
3.[5, 5, 7, 0]
---------------------------------
3.[5, 5, 7, 8]
---------------------------------
1.[0, 0, 0, 0, 0, 0, 0, 0, 0]
---------------------------------
1.[0, 1, 0, 0, 0, 0, 0, 0, 0]
---------------------------------
1.[0, 1, 2, 0, 0, 0, 0, 0, 0]
---------------------------------
2.[0, 1, 2, 5, 0, 0, 0, 0, 0]
---------------------------------
2.[0, 1, 2, 5, 5, 0, 0, 0, 0]
---------------------------------
2.[0, 1, 2, 5, 5, 7, 0, 0, 0]
---------------------------------
2.[0, 1, 2, 5, 5, 7, 8, 0, 0]
---------------------------------
3.[0, 1, 2, 5, 5, 7, 8, 10, 0]
---------------------------------
3.[0, 1, 2, 5, 5, 7, 8, 10, 30]
---------------------------------
[0, 1, 2, 5, 5, 7, 8, 10, 30]
*/

七、基数排序

   原理:通过分配再收集的方式来进行数据排序

​ 实现:假设有10个桶,按照最大数的位数来确定需要进行几轮排序

​ 1.第一轮:按照个位数来将元素分别装入到每个桶中,按从前往后、从上往下的方法再取出组成新的数组

​ 2.第二轮:按照十位数来将元素分别装入到每个桶中,按从前往后、从上往下的方法再取出组成新的数组

​ 3.第三轮:按照百位数来将元素分别装入到每个桶中,按从前往后、从上往下的方法再取出组成新的数组

​ 4....不断进行排序

图解第一轮的实现方式:

  1. 可以假设有10个桶

image-20211208130858184

  1. 每个桶中放个位数相同的数

image-20211208131014632

  1. 放好之后再按桶的位置和数的位置取出来组成一个新的数组image-20211208131056992
import java.util.Arrays;
public class SortDemo01 {
    public static void main(String[] args) {
        //基础排序:通过分配再收集的方式进行数据的排序
        int[] arr={2,1,5,21,31,444,23,33,47,10,903,124,987,100};

        //确定排序轮次
        //获取最大值
       // int turn= Max(arr);
        sortArray(arr);
        System.out.println(Arrays.toString(arr));
    }
    private static void sortArray(int[] arr) {
        //定义一个二维数组,来模拟10个桶
        int[][] tempArray=new int[10][arr.length];//用arr.length来代表1级数组的极限长度(个位数全为1时,则全加到一个一维数组中)
        //定义一个统计数组,用来存放每个桶存放了几个数,默认为0
        int[] counts=new int[10];
        int max=Max(arr);
        int len=String.valueOf(max).length();//返回最大值的长度,valueof:将其他类型转换成字符串类型
        //System.out.println(len);//3,进行3次循环
        //循环轮数
        for (int i = 0,n=1; i < len; i++,n*=10) {
            //第一轮:按个位数来进行分配
            //第二轮:按十位数来进行分配
            //第三轮:按百位数来进行分配
            for (int j = 0; j < arr.length; j++) {
                //对原数组进行遍历
                //获取每个位上的数字             
                int ys=arr[j]/n%10;
                //System.out.println(ys);
                tempArray[ys][counts[ys]++]=arr[j];
            }
            int index=0;//定义一个索引
            //取出桶中元素
            for (int k = 0; k < counts.length; k++) {
                if (counts[k]!=0){
                    for (int h = 0; h < counts[k]; h++) {
                        arr[index]=tempArray[k][h];
                        index++;
                    }
                    counts[k]=0;//清除上次的统计
                }
            }

        }
    }
    //获取最大值
    private static int Max(int[] arr) {
        int max=arr[0];
        for (int i = 0; i < arr.length; i++) {
            if (max<arr[i]){
                max=arr[i];
            }
        }
        return max;
    }
}

八、堆排序

​ 原理:将数组按完全二叉树的结构排列,从最后一个非叶子节点开始转,转成大顶堆,将根节点的元素和最后一个元素进行交换,重新转成大顶堆,如此往复

​ 堆排序 是利用堆这种数据结构而设计的一种排序算法,堆排序是一种选择排序。

image-20211209135856262

基本实现:

  1. 将待排序的数列构造成一个大顶堆,此时,整个序列的最大值就是堆顶的根节点。
  2. 将其与末尾元素进行交换,此时末尾就是最大值
  3. 然后剩余n-1个元素重新构造成一人上大顶堆,这样就会得到n个元素的次大值
  4. 反复执行,最终可以排序为有序序列
import java.util.Arrays;
public class SortDemo02 {
    public static void main(String[] args) {
        int[] arr={1,0,6,7,2,3,4};
        //调整为大顶堆
        //toMaxHeap(arr,arr.length,1);
        //sortArray(arr,);
        //定义开始调整的位置
        int startIndex=(arr.length-1)/2;
        //循环开始调
        for (int i=startIndex;i>=0;i--){
            toMaxHeap(arr,arr.length,i);
        }

        //以上已完成大顶堆的操作,接下来需要把根元素和最后一个元素进行调换
        for (int i = arr.length-1; i >0 ; i--) {
            //调换
            int t=arr[0];
            arr[0]=arr[i];
            arr[i]=t;
            //换完之后,再把剩余元素调成大顶堆
            toMaxHeap(arr,i,0);
        }
        System.out.println(Arrays.toString(arr));
    }
    /**
     *
     * @param arr 要排序的数组
     * @param size  调整元素的个数
     * @param index 从哪里开始调整
     */
    private static void toMaxHeap(int[] arr, int size, int index) {
        //获取左右子节点的索引
        int leftNodeIndex=index*2+1;
        int rightNodeIndex=index*2+2;
        //查找最大节点所对应的索引
        int maxIndex=index;
        if (leftNodeIndex<size  &&  arr[leftNodeIndex]>arr[maxIndex]){
            maxIndex=leftNodeIndex;
        }
        if (rightNodeIndex<size &&  arr[rightNodeIndex]>arr[maxIndex]){
            maxIndex=rightNodeIndex;
        }
        //调换位置,最大值节点索引变了,则说明需要进行交换
        if (maxIndex!=index){
            int t=arr[maxIndex];
            arr[maxIndex]=arr[index];
            arr[index]=t;
            //考虑到对后面的影响,需要重新进行大顶堆的构造
            toMaxHeap(arr,size,maxIndex);
        }
        System.out.println(Arrays.toString(arr));
    }
}
posted @ 2021-12-09 17:43  是韩信啊  阅读(79)  评论(0编辑  收藏  举报