chapter5 八大排序算法

八大排序算法

在这里插入图片描述

时间复杂度

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

各种排序算法的时间复杂度

空间复杂度

在这里插入图片描述

冒泡排序

图解冒泡排序算法的过程

总结:一趟排序可以确定一个最大值

第一趟排序:可以把最大的值确定下来
在这里插入图片描述
在这里插入图片描述

冒泡排序应用实例

冒泡排序时间复杂度O(n^2)
在这里插入图片描述

在这里插入图片描述

未优化的冒泡排序代码

public class BubbleSort {
    public static void main(String[] args) {
        int[] arr={3,9,-1,10,-2};
        //冒泡排序的时间复杂度O(n^2)
        int temp=0;//临时变量,用来做交换
        System.out.println("------------------------");
        for (int i = 0; i <arr.length-1 ; i++) {
            for (int j = 0; j < arr.length-1-i; j++) {
                if(arr[j]>arr[j+1]){//改从大到小改这个
                    temp=arr[j];
                    arr[j]=arr[j+1];
                    arr[j+1]=temp;
                }
            }
            System.out.println("第"+(i+1)+"趟排序后的数组:");
            System.out.println(Arrays.toString(arr));
        }

        //为了容易理解,我们把冒泡排序的演变过程展示出来

        /*//第一趟排序就是将最大的数排在最后
        int temp=0;//临时变量,用来做交换
        for (int i = 0; i < arr.length-1-0; i++) {
            //如果前面的数比后面的大,则交换
            if(arr[i]>arr[i+1]){
                temp=arr[i];
                arr[i]=arr[i+1];
                arr[i+1]=temp;
            }
        }
        System.out.println("第一趟排序后的数组:");
        System.out.println(Arrays.toString(arr));

        //第二趟排序,就是将第二大的数排在倒数第二位
        for (int i = 0; i < arr.length-1-1; i++) {
            //如果前面的数比后面的大,则交换
            if(arr[i]>arr[i+1]){
                temp=arr[i];
                arr[i]=arr[i+1];
                arr[i+1]=temp;
            }
        }
        System.out.println("第二趟排序后的数组:");
        System.out.println(Arrays.toString(arr));
        //第三趟排序,就是将第三大的数排在倒数第三位
        for (int i = 0; i < arr.length-1-2; i++) {
            //如果前面的数比后面的大,则交换
            if(arr[i]>arr[i+1]){
                temp=arr[i];
                arr[i]=arr[i+1];
                arr[i+1]=temp;
            }
        }
        System.out.println("第三趟排序后的数组:");
        System.out.println(Arrays.toString(arr));
        //第四趟排序,就是将第四大的数排在倒数第四位
        for (int i = 0; i < arr.length-1-3; i++) {
            //如果前面的数比后面的大,则交换
            if(arr[i]>arr[i+1]){
                temp=arr[i];
                arr[i]=arr[i+1];
                arr[i+1]=temp;
            }
        }
        System.out.println("第四趟排序后的数组:");
        System.out.println(Arrays.toString(arr));*/
    }
}

优化后的冒泡排序代码

public class BubbleSort {
    public static void main(String[] args) {
        int[] arr={3,9,-1,10,20};
        
        //冒泡排序的时间复杂度O(n^2)
        int temp=0;//临时变量,用来做交换
        boolean flag=false;//标识变量,表示是否进行过交换
        System.out.println("------------------------");
        for (int i = 0; i <arr.length-1 ; i++) {//第几趟排序
            for (int j = 0; j < arr.length-1-i; j++) {//一趟排序的循环
                if(arr[j]>arr[j+1]){
                    flag=true;
                    temp=arr[j];
                    arr[j]=arr[j+1];
                    arr[j+1]=temp;
                }
            }
            System.out.println("第"+(i+1)+"趟排序后的数组:");
            System.out.println(Arrays.toString(arr));
            if(!flag){//说明在一趟排序中,一次交换都没有发生过
                break;
            }else{
                flag=false;//重置flag进行下次判断,必须要进行重置,否则会出问题
            }
        }
    }
}

选择排序

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

public class SelectSort {
    public static void main(String[] args) {
        //int[] arr={101,34,119,1,-1,90,123};
        int[] arr=new int[80000];
        for (int i = 0; i <80000 ; i++) {
            arr[i]=(int)(Math.random()*8000000);//生成一个[0,8000000)之间的数
        }
        //System.out.println(Arrays.toString(arr));
        System.out.println("-------------------");
        Date date1=new Date();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String date1Str=simpleDateFormat.format(date1);
        System.out.println("排序前的时间:"+date1Str);
        long start=System.currentTimeMillis();
        selectSort(arr);
        long end=System.currentTimeMillis();
        System.out.println(end-start);
        Date date2=new Date();
        String date2Str=simpleDateFormat.format(date2);
        System.out.println("排序后的时间:"+date2Str);
    }

    //选择排序
    public static void selectSort(int[] arr){

        //选择排序:时间复杂度O(n^2)
        for (int i = 0; i < arr.length-1; i++) {
            int minIndex=i;
            int min=arr[i];
            for (int j = i+1; j <arr.length ; j++) {
                if(min>arr[j]){//说明假定的最小值并不是最小 //改从大到小改这个
                    min=arr[j];//重置最小值
                    minIndex=j;//重置minindex
                }
            }
            if(minIndex!=i){
                //找到了最小值,进行交换
                arr[minIndex]=arr[i];
                arr[i]=min;
            }
            /*System.out.println("第"+(i+1)+"轮之后的数组:");
            System.out.println(Arrays.toString(arr));*/
        }
        
        
        //使用逐步推导的方式
        //原始数组:101,34,119,1
        //第一轮:1,34,119,101
        //算法:先简单后复杂,复杂问题简单化---》逐步解决
        
        /*//第一轮
        int minIndex=0;
        int min=arr[0];
        for (int j = 0+1; j <arr.length ; j++) {
            if(min>arr[j]){//说明假定的最小值并不是最小
                min=arr[j];//重置最小值
                minIndex=j;//重置minindex
            }
        }
        if(minIndex!=0){
            //找到了最小值,进行交换
            arr[minIndex]=arr[0];
            arr[0]=min;
        }

        System.out.println("第一轮之后的数组:");
        System.out.println(Arrays.toString(arr));

        //第二轮:
         minIndex=1;
         min=arr[1];
        for (int j = 1+1; j <arr.length ; j++) {
            if(min>arr[j]){//说明假定的最小值并不是最小
                min=arr[j];//重置最小值
                minIndex=j;//重置minindex
            }
        }
        if(minIndex!=1){
            //找到了最小值,进行交换
            arr[minIndex]=arr[1];
            arr[1]=min;
        }

        System.out.println("第二轮之后的数组:");
        System.out.println(Arrays.toString(arr));

        //第三轮:
        minIndex=2;
        min=arr[2];
        for (int j = 2+1; j <arr.length ; j++) {
            if(min>arr[j]){//说明假定的最小值并不是最小
                min=arr[j];//重置最小值
                minIndex=j;//重置minindex
            }
        }
        if(minIndex!=2){
            //找到了最小值,进行交换
            arr[minIndex]=arr[2];
            arr[2]=min;
        }

        System.out.println("第三轮之后的数组:");
        System.out.println(Arrays.toString(arr));*/
    }
}

选择排序的时间比冒泡排序要少较多

80000个数值,冒泡大概需要20s,而选择排序只需要2s

插入排序

在这里插入图片描述
在这里插入图片描述

public class InsertSort {
    public static void main(String[] args) {
        //int[] arr={101,34,119,1,-1,89};
        int[] arr=new int[80000];
        for (int i = 0; i <80000 ; i++) {
            arr[i]=(int)(Math.random()*8000000);//生成一个[0,8000000)之间的数
        }
        Date date1=new Date();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String date1Str=simpleDateFormat.format(date1);
        System.out.println("排序前的时间:"+date1Str);
        long start=System.currentTimeMillis();
        insertSort(arr);
        long end=System.currentTimeMillis();
        System.out.println(end-start);
        Date date2=new Date();
        String date2Str=simpleDateFormat.format(date2);
        System.out.println("排序后的时间:"+date2Str);
    }

    //插入排序
    public static void insertSort(int[] arr){
        //使用for循环简化代码
        int insertVal=0;
        int insertIndex=0;
        for (int i = 1; i <arr.length ; i++) {
            insertVal=arr[i];
            insertIndex=i-1;
            while(insertIndex>=0&&insertVal<arr[insertIndex]){//改从大到小改这个
                arr[insertIndex+1]=arr[insertIndex];
                insertIndex--;
            }
           //判断是否需要赋值?
            if(insertIndex+1!=i){
                arr[insertIndex+1]=insertVal;
            }
            /*System.out.println("第"+(i)+"趟插入排序后的数组:");
            System.out.println(Arrays.toString(arr));*/
        }
        
        
        /*//第一轮
        //定义待插入的数
        int insertVal=arr[1];
        //定义待插入数的索引
        int insertIndex=1-1;//即arr【1】前面这个数的下标
        //给insertVal找到插入的位置
        //1. insertIndex>=0保证找插入位置时不越界
        //2. insertVal<arr[insertIndex]说明待插入的数还没有找到插入位置
        //3. 需要将arr[insertIndex]后移
        while(insertIndex>=0&&insertVal<arr[insertIndex]){
            arr[insertIndex+1]=arr[insertIndex];
            insertIndex--;
        }
        //当退出while循环时,说明已经找到插入位置,insertIndex+1;
        arr[insertIndex+1]=insertVal;
        System.out.println("第一趟插入排序后的数组:");
        System.out.println(Arrays.toString(arr));

        //第二轮
        insertVal=arr[2];
        insertIndex=2-1;
        while(insertIndex>=0&&insertVal<arr[insertIndex]){
            arr[insertIndex+1]=arr[insertIndex];
            insertIndex--;
        }
        arr[insertIndex+1]=insertVal;
        System.out.println("第二趟插入排序后的数组:");
        System.out.println(Arrays.toString(arr));

        //第三轮
        insertVal=arr[3];
        insertIndex=3-1;
        while(insertIndex>=0&&insertVal<arr[insertIndex]){
            arr[insertIndex+1]=arr[insertIndex];
            insertIndex--;
        }
        arr[insertIndex+1]=insertVal;
        System.out.println("第三趟插入排序后的数组:");
        System.out.println(Arrays.toString(arr));*/
    }
}

希尔排序,也称缩小增量排序

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

采用交换法的希尔排序

实际上就是分组套冒泡排序

public class ShellSort {
    public static void main(String[] args) {
        int[] arr={8,9,1,7,2,3,5,4,6,0};
        shellSort(arr);
    }

    public static void shellSort(int[] arr){
        //使用交换法
        int temp=0;
        int count=0;
        for (int gap = arr.length/2; gap > 0; gap/=2) {
            for (int i = gap; i < arr.length; i++) {
                //遍历各组中所有的元素(共有gap组,每组length/gap有个元素),步长为gap
                for (int j = i-gap; j >=0 ; j-=gap) {
                    //如果当前元素大于加上步长后的那个元素,说明需要交换
                    if(arr[j]>arr[j+gap]){
                        temp=arr[j];
                        arr[j]=arr[j+gap];
                        arr[j+gap]=temp;
                    }
                }
            }
            count++;
            System.out.println("希尔排序第"+count+"轮="+Arrays.toString(arr));
        }


        /*//使用逐步推导的方式编写shell排序
        //10个数据进行三轮
        //希尔排序第一轮
        //第一轮将10个数据分成5组
        int temp=0;
        for (int i = 5; i < arr.length; i++) {
            //遍历各组中所有的元素(共有5组,每组有两个元素),步长5
            for (int j = i-5; j >=0 ; j-=5) {//为什么是j-=5????????
                //如果当前元素大于加上步长后的那个元素,说明需要交换
                if(arr[j]>arr[j+5]){
                    temp=arr[j];
                    arr[j]=arr[j+5];
                    arr[j+5]=temp;
                }
            }
        }
        System.out.println("希尔排序第一轮之后的情况:");
        System.out.println(Arrays.toString(arr));

        //第二轮将10个数据分成5/2=2组
        for (int i = 2; i < arr.length; i++) {
            //遍历各组中所有的元素(共有5组,每组有两个元素),步长5
            for (int j = i-2; j >=0 ; j-=2) {//为什么时j-=5
                //如果当前元素大于加上步长后的那个元素,说明需要交换
                if(arr[j]>arr[j+2]){
                    temp=arr[j];
                    arr[j]=arr[j+2];
                    arr[j+2]=temp;
                }
            }
        }
        System.out.println("希尔排序第二轮之后的情况:");
        System.out.println(Arrays.toString(arr));

        //第三轮将10个数据分成2/2=1组
        for (int i = 1; i < arr.length; i++) {
            //遍历各组中所有的元素(共有5组,每组有两个元素),步长5
            for (int j = i-1; j >=0 ; j-=1) {//为什么时j-=5
                //如果当前元素大于加上步长后的那个元素,说明需要交换
                if(arr[j]>arr[j+1]){
                    temp=arr[j];
                    arr[j]=arr[j+1];
                    arr[j+1]=temp;
                }
            }
        }
        System.out.println("希尔排序第三轮之后的情况:");
        System.out.println(Arrays.toString(arr));*/
    }
}

采用移动法的希尔排序

实际上是分组套插入排序

public class ShellSort {
    public static void main(String[] args) {
        /*int[] arr={8,9,1,7,2,3,5,4,6,0};
        shellSort2(arr);*/
        int[] arr=new int[80000];
        for (int i = 0; i <80000 ; i++) {
            arr[i]=(int)(Math.random()*8000000);//生成一个[0,8000000)之间的数
        }
        Date date1=new Date();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String date1Str=simpleDateFormat.format(date1);
        System.out.println("排序前的时间:"+date1Str);
        long start=System.currentTimeMillis();
        shellSort2(arr);
        long end=System.currentTimeMillis();
        System.out.println("耗时:"+(end-start));
        Date date2=new Date();
        String date2Str=simpleDateFormat.format(date2);
        System.out.println("排序后的时间:"+date2Str);
    }

    //移位式希尔排序
    public static void shellSort2(int[] arr){
        int count=0;
        //增量gap并逐步缩小
        for (int gap = arr.length/2; gap >0 ; gap/=2) {
            //从第gap个元素开始,逐个对其所在的组进行直接插入
            for(int i=gap;i<arr.length;i++){
                int j=i;
                int temp=arr[j];
                if(arr[j]<arr[j-gap]){
                    while(j-gap>=0&&temp<arr[j-gap]){//while循环是在找位置
                        //移动
                        arr[j]=arr[j-gap];
                        j-=gap;
                    }//当退出while循环后说明就给temp找到了插入位置
                    arr[j]=temp;
                }
            }
            count++;
            //System.out.println("希尔排序第"+count+"轮="+Arrays.toString(arr));
        }
    }
}

快速排序

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

package paixu;

import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;

/**
 * @author : sky
 * @version : 1.0
 */
public class QuickSort {
    public static void main(String[] args) {
        int[] arr={-9,78,0,23,-567,70,-1,900,4561};
        /*int[] arr=new int[8000000];
        for (int i = 0; i <8000000 ; i++) {
            arr[i]=(int)(Math.random()*8000000);//生成一个[0,8000000)之间的数
        }
        Date date1=new Date();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String date1Str=simpleDateFormat.format(date1);
        System.out.println("排序前的时间:"+date1Str);
        long start=System.currentTimeMillis();*/

        quickSort(arr,0,arr.length-1);

        /*long end=System.currentTimeMillis();
        System.out.println("耗时:"+(end-start));
        Date date2=new Date();
        String date2Str=simpleDateFormat.format(date2);
        System.out.println("排序后的时间:"+date2Str);*/
        System.out.println("快速排序");
        System.out.println(Arrays.toString(arr));
    }


    //快速排序

    /**
     *
     * @param arr  arr传进来的数组
     * @param left left指针,指向数组的最左边的值
     * @param right right指针,指向数组的最右边的值
     */
    public static void quickSort(int[] arr,int left,int right){
        int l=left;//左下标,即左边的索引
        int r=right;//右下标,即右边的索引
        int pivot=arr[(left+right)/2];//中间的基准值,即中轴值
        int temp=0;//临时变量,交换时使用
        //while循环的目的,是让比中轴值小的放到左边,比中轴值大的放到右边
        while(l<r){
            //在pivot左边一直找,找到大于等于pivot的值,才退出
            while(arr[l]<pivot){
                l+=1;
            }
            //在pivot右边一直找,找到小于等于pivot的值,才退出
            while(arr[r]>pivot){
                r-=1;
            }
            //如果l>=r说明pivot的左右两边的值,已经按照左边全部是小于等于pivot的值,右边全部是大于等于pivot的值
            if(l>=r){
                //如果满足这个条件的话就说明循环可以退出
                break;
            }
            //开始交换
            temp=arr[l];
            arr[l]=arr[r];
            arr[r]=temp;

            //这里的控制不太明白???????
            //如果交换完之后发现arr[l]==pivot值相等,需要r--,相当于前移
            if(arr[l]==pivot){
                r-=1;
            }
            //如果交换完之后发现arr[r]==pivot值相等,需要l++,相当于后移
            if(arr[r]==pivot){
                l+=1;
            }
        }
        //如果l==r,必须l++,r--,否则会出现栈溢出
        if(l==r){
            l+=1;
            r-=1;
        }
        //向左递归
        if(left<r){
            quickSort(arr,left,r);
        }
        //向右递归
        if(right>l){
            quickSort(arr,l,right);
        }
    }
}

归并排序

在这里插入图片描述
在这里插入图片描述

实际上合并共有4+2+1=7次

在这里插入图片描述

package paixu;

import com.sun.scenario.effect.impl.sw.sse.SSEBlend_SRC_OUTPeer;

import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;

/**
 * @author : sky
 * @version : 1.0
 */
public class MergeSort {
    public static void main(String[] args) {
        /*int[] arr={8,4,5,7,1,3,6,2};
        int[] temp=new int[arr.length];//归并排序需要一个额外的排序
        mergeSort(arr,0,arr.length-1,temp);
        System.out.println("归并排序后:"+ Arrays.toString(arr));
*/
        int[] arr=new int[8000000];
        int[] temp=new int[arr.length];
        for (int i = 0; i <8000000 ; i++) {
            arr[i]=(int)(Math.random()*8000000);//生成一个[0,8000000)之间的数
        }
        Date date1=new Date();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String date1Str=simpleDateFormat.format(date1);
        System.out.println("排序前的时间:"+date1Str);
        long start=System.currentTimeMillis();
        mergeSort(arr,0,arr.length-1,temp);
        long end=System.currentTimeMillis();
        System.out.println("耗时:"+(end-start));
        Date date2=new Date();
        String date2Str=simpleDateFormat.format(date2);
        System.out.println("排序后的时间:"+date2Str);
    }

    //合并的方法
    /**
     *
     * @param arr arr待排序的原始数组
     * @param left left左边有序序列的初始索引
     * @param mid mid中间索引,即右边数组的结束索引
     * @param right right右边索引
     * @param temp temp做中转的数组
     */
    public static void merge(int[] arr,int left,int mid,int right,int[] temp){
        //System.out.println("11");
        int i=left;//初始化i,左边有序序列的初始索引
        int j=mid+1;//初始化j,右边有序序列的初始索引
        int t=0;//指向temp数组的当前索引

        //1.先把左右两边(有序)的数据按照规则填充到temp数组,直到左右两边有序序列有一边处理完毕为止
        while(i<=mid && j<=right){//只要满足这个条件就继续
            //如果左边有序序列的当前元素小于等于右边有序序列的当前元素,即将左边的当前元素拷贝到temp数组中
            //然后t++,i++后移
            if(arr[i]<=arr[j]){
                temp[t]=arr[i];
                t+=1;
                i+=1;
            }else{//反之,将右边的当前元素拷贝到temp数组中
                temp[t]=arr[j];
                t+=1;
                j+=1;
            }

        }
        //2.把有剩余数据的一方一次填充到temp中
        while(i<=mid){//说明左边的有序序列还有剩余元素,就全部填充到temp
            temp[t]=arr[i];
            t+=1;
            i+=1;
        }
        while(j<=right){//说明右边的有序序列还有剩余元素,就全部填充到temp
            temp[t]=arr[j];
            t+=1;
            j+=1;
        }
        //3.将temp数组的元素拷贝到arr原数组
        //注意,并不是每次都拷贝所有数据
        t=0;
        int tempLeft=left;
        //System.out.println("templeft="+tempLeft+" right="+right);
        while(tempLeft<=right){//第一次合并时,tempLeft=0;right=1//第二次 tL=2;r=3//第三次 tL=0;r=3//第四次 tL=4;r=5
            //第五次 tL=6;r=7//第六次 tL=4;r=7
            //第七次最后一次才是tL=0;r=7
            arr[tempLeft]=temp[t];
            t+=1;
            tempLeft+=1;
        }

    }

    //分+合的方法
    //归并排序
    public static void mergeSort(int[] arr,int left,int right,int[] temp){
        if(left<right){
            int mid=(left+right)/2;//中间的索引
            //向左递归进行分解
            mergeSort(arr,left,mid,temp);
            //向右递归进行分解
            mergeSort(arr,mid+1,right,temp);
            //每分解一次就合并一次
            //合并
            merge(arr,left,mid,right,temp);
        }
    }
}

基数排序(桶排序)

稳定性排序是指:如果有两数相等,那么原先在前的那个数,排序完之后仍然在前
在这里插入图片描述
在这里插入图片描述

使用基数排序对{53,3,542,748,14,214}进行升序排序

第一轮:
在这里插入图片描述

第二轮:

在这里插入图片描述

第三轮:
在这里插入图片描述

轮数取决于最大的数的位数
在这里插入图片描述

package paixu;

import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;

/**
 * @author : sky
 * @version : 1.0
 */
public class RadixSort {
    public static void main(String[] args) {
        /*int[] arr={53,3,542,748,14,214};
        radixSort(arr);*/
        int[] arr=new int[8000000];
        int[] temp=new int[arr.length];
        for (int i = 0; i <8000000 ; i++) {
            arr[i]=(int)(Math.random()*8000000);//生成一个[0,8000000)之间的数
        }
        Date date1=new Date();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String date1Str=simpleDateFormat.format(date1);
        System.out.println("排序前的时间:"+date1Str);
        long start=System.currentTimeMillis();
        radixSort(arr);
        long end=System.currentTimeMillis();
        System.out.println("耗时:"+(end-start));
        Date date2=new Date();
        String date2Str=simpleDateFormat.format(date2);
        System.out.println("排序后的时间:"+date2Str);
    }

    //基数排序
    public static void radixSort(int[] arr){
        //要得到数组中最大的数的位数
        int max=arr[0];//假设第一个数就是最大的数
        for (int i = 1; i <arr.length ; i++) {
            if(arr[i]>max){
                max=arr[i];
            }
        }
        //最大的数是几位数
        int maxLength=(max+"").length();
        //第一轮排序:针对每个元素的个位进行排序处理
        //定义一个二位数组表示10个桶,每个桶就是一个一维数组
        //说明:
        //1.二位数组包含10个一维数组
        //2.为了防止在放入数的时候数据溢出,每个桶(一维数组)的大小定义为arr.length
        //3.基数排序是使用空间换时间的经典算法
        int[][] bucket=new int[10][arr.length];

        //为了记录每个桶中实际存放了多少个数据,定义一个一维数组来记录各个桶的每次放入数据的个数
        //即bucketElementCount[0],记录的就是bucket[0]桶里元素的个数
        int[] bucketElementCount=new int[10];

        //最终代码:
        for (int i = 0,n=1; i <maxLength ; i++,n*=10) {
            for(int j=0;j<arr.length;j++){
                //针对每个元素对应的位数进行处理,第一轮个位,第二轮十位,第三轮百位
                int digitOfElement=arr[j]/ n % 10;
                //放入到对应的桶中
                bucket[digitOfElement][bucketElementCount[digitOfElement]]=arr[j];
                bucketElementCount[digitOfElement]++;
            }

            //按照桶的顺序,取出数据并放入原来的数组
            int index=0;
            //遍历每一个桶,并将桶中的数据放入到原数组
            for(int k=0;k<bucket.length;k++){
                //如果桶中有数据,才取出到原数组
                if(bucketElementCount[k]!=0){
                    //循环该桶,即第k个一维数组
                    for(int l=0;l<bucketElementCount[k];l++){
                        //取出元素放入到arr中
                        arr[index]=bucket[k][l];
                        index++;
                    }
                }
                //第i+1轮处理后,需要将每个bucketElementCount[k]置0!!!!!
                bucketElementCount[k]=0;
            }
            //System.out.println("第"+(i+1)+"轮,对个位的排序处理:"+ Arrays.toString(arr));
        }


        /*for(int j=0;j<arr.length;j++){
            //取出每个元素的个位
            int digitOfElement=arr[j]%10;
            //放入到对应的桶中
            bucket[digitOfElement][bucketElementCount[digitOfElement]]=arr[j];
            bucketElementCount[digitOfElement]++;
        }

        //按照桶的顺序,取出数据并放入原来的数组
        int index=0;
        //遍历每一个桶,并将桶中的数据放入到原数组
        for(int k=0;k<bucket.length;k++){
            //如果桶中有数据,才取出到原数组
            if(bucketElementCount[k]!=0){
                //循环该桶,即第k个一维数组
                for(int l=0;l<bucketElementCount[k];l++){
                    //取出元素放入到arr中
                    arr[index]=bucket[k][l];
                    index++;
                }
            }
            //第一轮处理后,需要将每个bucketElementCount[k]置0!!!!!
            bucketElementCount[k]=0;
        }
        System.out.println("第1轮,对个位的排序处理:"+ Arrays.toString(arr));

        //第二轮,放十位
        for(int j=0;j<arr.length;j++){
            //取出每个元素的个位
            int digitOfElement=arr[j]/10%10;
            //放入到对应的桶中
            bucket[digitOfElement][bucketElementCount[digitOfElement]]=arr[j];
            bucketElementCount[digitOfElement]++;
        }

        //按照桶的顺序,取出数据并放入原来的数组
        index=0;
        //遍历每一个桶,并将桶中的数据放入到原数组
        for(int k=0;k<bucket.length;k++){
            //如果桶中有数据,才取出到原数组
            if(bucketElementCount[k]!=0){
                //循环该桶,即第k个一维数组
                for(int l=0;l<bucketElementCount[k];l++){
                    //取出元素放入到arr中
                    arr[index]=bucket[k][l];
                    index++;
                }
            }
            bucketElementCount[k]=0;
        }
        System.out.println("第2轮,对十位的排序处理:"+ Arrays.toString(arr));

        //第三轮,放百位
        for(int j=0;j<arr.length;j++){
            //取出每个元素的个位
            int digitOfElement=arr[j]/100%10;
            //放入到对应的桶中
            bucket[digitOfElement][bucketElementCount[digitOfElement]]=arr[j];
            bucketElementCount[digitOfElement]++;
        }

        //按照桶的顺序,取出数据并放入原来的数组
        index=0;
        //遍历每一个桶,并将桶中的数据放入到原数组
        for(int k=0;k<bucket.length;k++){
            //如果桶中有数据,才取出到原数组
            if(bucketElementCount[k]!=0){
                //循环该桶,即第k个一维数组
                for(int l=0;l<bucketElementCount[k];l++){
                    //取出元素放入到arr中
                    arr[index]=bucket[k][l];
                    index++;
                }
            }
            bucketElementCount[k]=0;
        }
        System.out.println("第3轮,对百位的排序处理:"+ Arrays.toString(arr));*/
    }
}

堆排序

在这里插入图片描述
在这里插入图片描述

堆排序思路

在这里插入图片描述

构建大顶堆时用的是数组
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

package paixu;

import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;

/**
 * @author : sky
 * @version : 1.0
 */
public class HeapSort {
    public static void main(String[] args) {
        //数组进行升序排序
        /*int[] arr={4,6,8,5,9};
        heapSort(arr);*/
        int[] arr=new int[8000000];
        for (int i = 0; i <8000000 ; i++) {
            arr[i]=(int)(Math.random()*8000000);//生成一个[0,8000000)之间的数
        }
        Date date1=new Date();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String date1Str=simpleDateFormat.format(date1);
        System.out.println("排序前的时间:"+date1Str);
        long start=System.currentTimeMillis();
        heapSort(arr);
        long end=System.currentTimeMillis();
        System.out.println("耗时:"+(end-start));
        Date date2=new Date();
        String date2Str=simpleDateFormat.format(date2);
        System.out.println("排序后的时间:"+date2Str);
    }

    //堆排序的方法
    public static void heapSort(int[] arr){
        int temp=0;
        System.out.println("堆排序");
        //分步完成
        /*adjustHeap(arr,1,arr.length);
        System.out.println(Arrays.toString(arr));//[4, 9, 8, 5, 6]
        adjustHeap(arr,0,arr.length);
        System.out.println(Arrays.toString(arr));//[9, 6, 8, 5, 4]*/
        
        //最终代码
        //将无序序列构建成一个大顶堆, 第一个非叶子节点的值为arr.length/2-1
        for (int i = arr.length/2-1; i >=0 ; i--) {
            adjustHeap(arr,i,arr.length);
        }

        //将堆顶元素与末尾元素交换,最大值放到数组最后
        for (int j = arr.length-1; j >0 ; j--) {
            //交换
            temp=arr[j];
            arr[j]=arr[0];
            arr[0]=temp;
            adjustHeap(arr,0,j);
        }
    }

    //将一个数组 (二叉树),调整成为一个大顶堆
    /**
     * 功能:完成将以i对应的非叶子节点的树,调整成大顶堆,即图解中的步骤一(2)
     * 即将{4,6,8,5,9}=> i=1 => 第一次调整为{4,9,8,5,6};
     * i=0  => 再次调整为 {9,6,8,5,4};
     * @param arr 待调整的数组
     * @param i 非叶子节点在数组中的索引
     * @param length 表示对多少个元素进行调整,length在逐渐减少
     */
    public static void adjustHeap(int[] arr,int i,int length){
        int temp=arr[i];//先取出当前元素的值,保存在临时变量
        
        //开始调整
        //k是i节点的左子节点
        for (int k = i*2+1; k <length ; k=k*2+1) {
            if(k+1<length && arr[k]<arr[k+1]){//说明左子节点的值小于右子节点的值
                k++;//k指向右子节点
            }
            if(arr[k]>temp){//如果子节点大于父节点
                arr[i]=arr[k];//把较大的值付给当前的节点
                i=k;//!!!然后让i指向k,继续循环比较
            }else{
                break;//因为是从最后一个非叶子节点走的,所以他之下的都是小的
            }
        }
        //当for循环结束后,我们已经将以i为父节点的树的最大值,放在了最顶上,即i的位置,此时是局部调整
        arr[i]=temp;//将temp的值放到调整后的位置
    }
}

在这里插入图片描述

计数排序

桶排序

k=10,如果log n>10,那么基数排序会更快一点

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值