常见排序算法

冒泡排序

算法描述
步骤1: 比较相邻的元素。如果第一个比第二个大,就交换它们两个;
步骤2: 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对,这样在最后的元素应该会是最大的数;
步骤3: 针对所有的元素重复以上的步骤,除了最后一个;
步骤4: 重复步骤1~3,直到排序完成。
图解
冒泡算法
代码

static void bubbleSort(int[] arr)//冒泡排序
    {
        int temp;
        for (int i=1;i<arr.length;i++)//冒泡的次数
            for(int j=0;j<arr.length-i;j++)//冒出第i大的数,放在length-i位置
            {
                if(arr[j]>arr[j+1])
                {
                    temp=arr[j];
                    arr[j]=arr[j+1];
                    arr[j+1]=temp;
                }
            }
        return ;
    }

选择排序

算法描述
步骤1:初始状态:无序区为R[1…n],有序区为空;
步骤2:第i趟排序(i=1,2,3…n-1)开始时,当前有序区和无序区分别为R[1…i-1]和R(i…n)。该趟排序从当前无序区中-选出关键字最小的记录 R[k],将它与无序区的第1个记录R交换,使R[1…i]和R[i+1…n)分别变为记录个数增加1个的新有序区和记录个数减少1个的新无序区;
步骤3:n-1趟结束,数组有序化了。
图解
在这里插入图片描述
代码

 static void selectionSort(int[] arr)//选择排序
    {
        int temp,min;
            for(int i=0;i<arr.length-1;i++)//i为起始、想要位置
            {
                //寻找最小值
                min=i;
                for(int j=i+1;j<arr.length;j++)
                {
                    if (arr[min] > arr[j])
                        min = j;
                }
                //替换最小值
                if(min!=i)
                {
                    temp=arr[min];
                    arr[min]=arr[i];
                    arr[i]=temp;
                }
            }
        return ;
    }

插入排序

算法描述
步骤1: 从第一个元素开始,该元素可以认为已经被排序;
步骤2: 取出下一个元素,在已经排序的元素序列中从后向前扫描;
步骤3: 如果该元素(已排序)大于新元素,将该元素移到下一位置;
步骤4: 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置;
步骤5: 将新元素插入到该位置后;
步骤6: 重复步骤2~5。
图解
在这里插入图片描述
代码

 static void insertSort(int[] arr)//插入排序
    {
        int insert;//要插入的值
        for(int i=0;i<arr.length;i++)//i为要插入的值
       {
           insert=arr[i];
           for(int j=i-1;j>=0;j--)
           {
               if(arr[j]<insert)//找到插入的位置
               {
                   arr[j+1]=insert;
                   break;
               }
               else if(j!=0)//未找到位置,但是还可以再找,后移
               {
                   arr[j+1]=arr[j];
               }
               else//未找到位置,不可以再找,后移,插入
               {
                   arr[j+1]=arr[j];
                   arr[j]=insert;
               }
           }
       }
        return ;
    }

希尔排序

算法描述
步骤1:选择一个增量序列t1,t2,…,tk,其中ti>tj,tk=1;
步骤2:按增量序列个数k,对序列进行k 趟排序;
步骤3:每趟排序,根据对应的增量ti,将待排序列分割成若干长度为m 的子序列,分别对各子表进行直接插入排序。仅增量因子为1 时,整个序列作为一个表来处理,表长度即为整个序列的长度。
图解
在这里插入图片描述
代码

 public static void shellSort(int arr[])//希尔排序
    {
        int insert;//要插入的值
        for(int num = arr.length/2;num>0;num/=2)//分组的数量
        {
            for(int k = 0;k<num;k++)//分组起点k
            {
                //插入排序
                for(int i=k;i<arr.length;i+=num)//i 为要插入的点
                {
                    insert=arr[i];
                    for(int j=i-num;j>=0;j-=num)//j 为向前遍历的位置
                    {
                        if(insert>arr[j])//找到插入点
                        {
                            arr[j+num]=insert;
                            break;
                        }
                        else if(j<num)//没找到插入点,仍可向前找
                        {
                            arr[j+num]=arr[j];
                            arr[j]=insert;
                            break;

                        }
                        else //没找到插入点,且不能向前找了
                        {
                            arr[j+num]=arr[j];
                        }
                    }
                }
            }
        }
    }

快速排序

描述
步骤1:从数列中挑出一个元素,称为 “基准”(pivot );
步骤2:重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作;
步骤3:递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。
图解
在这里插入图片描述
代码

    public static void quickSort(int arr[],int l,int r){
     if(l>=r)
         return;
     int LIFT=l;
     int RIGHT=r;
         int temp=arr[l];
         while (l<r)
         {
            while(l<r&&arr[r]>=temp)
                r--;
             arr[l]=arr[r];
             while (l<r&&arr[l]<=temp)
                 l++;
             arr[r]=arr[l];
         }
            arr[l]=temp;

         quickSort(arr,LIFT,l-1);
         quickSort(arr,l+1,RIGHT);

    }

测试代码

使用的是最坏情况

static void printArray(int[] arr)//打印数组
    {
        for (int e:arr)
        {
            System.out.print(e+" ");
        }
        System.out.println();
    }
    public static void main(String[] args)
     {
        int []arr1=new int[200000];
        int []arr2=new int[200000];
        int []arr3=new int[200000];
        int []arr4=new int[200000];
        int []arr5=new int[200000];
        for(int i=200000;i>=1;i--)
        {
            arr1[200000-i]=i;
            arr2[200000-i]=i;
            arr3[200000-i]=i;
            arr4[200000-i]=i;
            arr5[200000-i]=i;
        }
        long startTime,endTime;
        //冒泡排序
        startTime=System.currentTimeMillis();   //获取开始时间
        bubbleSort(arr1);
        endTime=System.currentTimeMillis(); //获取结束时间
        System.out.println("冒泡排序程序运行时间:" + (endTime - startTime) + "ms");    //输出程序运行时间

        //选择排序
        startTime=System.currentTimeMillis();   //获取开始时间
        selectionSort(arr2);
        endTime=System.currentTimeMillis(); //获取结束时间
        System.out.println("选择排序程序运行时间:" + (endTime - startTime) + "ms");    //输出程序运行时间

        //插入排序
        startTime=System.currentTimeMillis();   //获取开始时间
        insertSort(arr3);
        endTime=System.currentTimeMillis(); //获取结束时间
        System.out.println("插入排序程序运行时间:" + (endTime - startTime) + "ms");    //输出程序运行时间

        //希尔排序
        startTime=System.currentTimeMillis();   //获取开始时间
        shellSort(arr4);
        endTime=System.currentTimeMillis(); //获取结束时间
        System.out.println("希尔排序程序运行时间:" + (endTime - startTime) + "ms");    //输出程序运行时间

        //快速排序
        startTime=System.currentTimeMillis();   //获取开始时间
        quickSort(arr5,0,arr2.length-1);
        endTime=System.currentTimeMillis(); //获取结束时间
        System.out.println("快速排序程序运行时间:" + (endTime - startTime) + "ms");    //输出程序运行时间
    }

性能

在这里插入图片描述

总结

使用快排时,由于是递归调用,要注意栈的深度,很容易栈溢出。
解决方法:设置JVM参数:-Xss20m
同样是最坏情况,希尔排序的性能好得让我吃惊,快排速度也不错。
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值