排序算法及java实现

Posted 盖丽男

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了排序算法及java实现相关的知识,希望对你有一定的参考价值。

文章目录

简介

排序算是非常基础的算法,为什么我们需要排序算法呢?假设我们只有10个数,或者100个数,其实根本不需要研究这么多的排序算法,正常我们会使用的插入排序或者选择排序足够了,没必要发明快排,基数排序这些。
只有将需要排序的量非常大,我们才开始需要一些效率更高,更合适的排序算法。看一下常见的几种排序算法的效率:

来解释一下稳定性的意思,稳定性的意思是说,相等的数在排序后仍然保持排序前的相对顺序。

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

注意:排序算法的速度是有极限的,基于比较的排序算法的最优下界是 O ( n l o g n ) % O(nlogn) O(nlogn),至于为什么,我还没搞明白,可以看看这个:CBA理论, 为什么基于比较的排序方法的性能极限是O(nlogn)

冒泡排序

一般我们提起冒泡排序,都说它是最简单的排序,但是对我来说,实际生活中,我感觉使用插入排序或者选择排序其实更多,很少会直接想到冒泡排序,冒泡排序的操作过程就是,从第一个起,和后面的两两对比,然后如果后面的小于前面的,就进行交换,如此这般,循环直到所有数字顺序都正确。

/**
 * 比较相邻的元素。如果第一个比第二个大,就交换他们两个。
 * 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。
 * 针对所有的元素重复以上的步骤,除了最后一个。
 * 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
 */
public class BubbleSort 

    public static void main(String[] args) 
        int[] list= 81,94,11,96,12,35,17,95,28,58,41,75,15;
        System.out.println("排序前: "+ Arrays.toString(list));

        int count=13;
        bubbleSort(list,count);
        System.out.println("排序后: "+ Arrays.toString(list));
    

    private static void bubbleSort(int[] list, int count) 
        for (int i = list.length-1; i >0 ; i--) 
            boolean flag=true;

            for (int j = 0; j < i; j++) 
                if (list[j]>list[j+1])
                    flag=false;
                    int temp=list[j];
                    list[j]=list[j+1];
                    list[j+1]=temp;
                
            

            if (flag)
                return;
            
        

    

插入排序

插入排序就是,从第一个开始就当它有序,开始和后面的进行对比,当发现大小小于前面的时候,就一直找到对的位置放下这个数字。

/**
 *插入排序是一种最简单直观的排序算法,它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。
 *插入排序和冒泡排序一样,也有一种优化算法,叫做拆半插入。
 */
public class InsertionSort 

    public static void main(String[] args) 
        int[] list= 81,94,11,96,12,35,17,95,28,58,41,75,15;
        System.out.println("排序前: "+ Arrays.toString(list));

        int count=13;
//        int[] result=insertionSort(list,count);
        insertionSort(list);
//        System.out.println("排序后: "+ Arrays.toString(result));
        System.out.println("排序后: "+ Arrays.toString(list));
    

    private static int[] insertionSort(int[] list, int count) 
        int[] result= Arrays.copyOf(list, list.length);

        for (int i = 1; i < list.length; i++) 

            int j=i;
            while (j > 0 && list[i]<result[j-1]) 
                result[j]=result[j-1];
                j--;
            
            result[j]=list[i];
        

        return  result;
    


    public static void insertionSort(int[] arr)
        for(int i=1;i<arr.length;i++)
            int j=i;
            while(j>0 && arr[j] < arr[j - 1])
                arr[j] = arr[j]+arr[j-1];
                arr[j-1] = arr[j]-arr[j-1];
                arr[j] = arr[j]-arr[j-1];
                j--;
            
        
    


选择排序

我觉得选择排序最符合人的排序习惯,就是一轮一轮的找最小的,拿出来排队。


/**
 * 选择排序是一种简单直观的排序算法,无论什么数据进去都是 O(n²) 的时间复杂度。所以用到它的时候,数据规模越小越好。唯一的好处可能就是不占用额外的内存空间了吧。
 */
public class SelectionSort 

    public static void main(String[] args) 
        int[] list= 81,94,11,96,12,35,17,95,28,58,41,75,15;
        System.out.println("排序前: "+ Arrays.toString(list));

        int count=13;
        selectSort(list);
        System.out.println("排序后: "+ Arrays.toString(list));
    

    private static void selectioonSort(int[] list, int count) 
        for (int i = 0; i < list.length-1; i++) 
            int min=i;
            for (int j = i + 1; j < list.length; j++) 
                if(list[min]>list[j])
                    min=j;
                
            

            if (min!=i)
                int temp=list[i];
                list[i]=list[min];
                list[min]=temp;
            

        
    

    public static void selectSort(int[] arr) 
        for (int i = 0; i < arr.length-1; i++) 
            int min = i;
            for (int j = i + 1; j < arr.length; j++) 
                if (arr[j] < arr[min]) 
                    min = j;
                
            

            if (min != i) 
                arr[min]=arr[min]+arr[i];
                arr[i]=arr[min]-arr[i];
                arr[min]=arr[min]-arr[i];
            
        
    



希尔排序

希尔排序按其设计者希尔(Donald Shell)的名字命名,该算法由1959年公布。一些老版本教科书和参考手册把该算法命名为Shell-Metzner,即包含Marlene Metzner Norton的名字,但是根据Metzner本人的说法,“我没有为这种算法做任何事,我的名字不应该出现在算法的名字中。

希尔排序可以理解为在插入排序外面套了一层,每次不是相近的数字在比,而是间隔着比,主要是为了提高消灭逆序对的效率

/**
 * 希尔排序,也称递减增量排序算法,是插入排序的一种更高效的改进版本。但希尔排序是非稳定排序算法。
 * 希尔排序是基于插入排序的以下两点性质而提出改进方法的:
 * 插入排序在对几乎已经排好序的数据操作时,效率高,即可以达到线性排序的效率;
 * 但插入排序一般来说是低效的,因为插入排序每次只能将数据移动一位;
 * 希尔排序的基本思想是:先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录"基本有序"时,再对全体记录进行依次直接插入排序。
 */
public class ShellSort 

    public static void main(String[] args) 
        int[] list= 81,94,11,96,12,35,17,95,28,58,41,75,15;
        System.out.println("排序前: "+ Arrays.toString(list));

        int count=13;
        shellSort2(list,count);
        System.out.println("排序后: "+ Arrays.toString(list));
    


    private static void shellSort(int[] list, int count) 
        for (int D = count/2; D >0 ; D/=2) 
            for (int P = D; P < count; P++) 
                int temp=list[P];
                int i;
                for (i = P; i >= D && list[i-D] > temp; i-=D) 
                    list[i]=list[i-D];
                
                list[i]=temp;

            
        
    

    private static void shellSort2(int[] arr, int count) 
        for (int D = count/2; D >0 ; D/=2) 
            for(int i=D;i<arr.length;i++)
                int j=i;
                while(j>=D && arr[j] < arr[j - D])
                    arr[j] = arr[j]+arr[j-D];
                    arr[j-D] = arr[j]-arr[j-D];
                    arr[j] = arr[j]-arr[j-D];
                    j-=D;
                
            
        
    

归并排序

归并排序(英语:Merge sort,或mergesort),是创建在归并操作上的一种有效的排序算法,效率为
O ( n l o g n ) % O(nlogn) O(nlogn)(大O符号)。1945年由约翰·冯·诺伊曼首次提出。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用,且各层分治递归可以同时进行。

我觉得靠我的脑子想不出来归并排序这种东西,就是拆分到最小单位,1个或者两个,然后排好序返回来,有序的列表继续参与合并排序。

/**
 * 归并排序(Merge sort)是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。
 * 作为一种典型的分而治之思想的算法应用,归并排序的实现由两种方法:
 * 自上而下的递归(所有递归的方法都可以用迭代重写,所以就有了第 2 种方法);
 * 自下而上的迭代;
 */
public class MergeSort 
    public static void main(String[] args) 
        int[] list= 81,94,11,96,12,35,17,95,28,58,41,75,15;
        System.out.println("排序前: "+ Arrays.toString(list));

        int count=13;
        int[] result=sort(list);
        System.out.println("排序后: "+ Arrays.toString(result));
    


    private static int[] sort(int[] list)
        int middle = (int) Math.floor(list.length / 2);

        if(list.length<2)
            return list;
        
        int[] left=Arrays.copyOfRange(list,0,middle);
        int[] right=Arrays.copyOfRange(list,middle,list.length);

        return merge(sort(left),sort(right));
    

    private static int[] merge(int[] left, int[] right) 
        int[] result=new int[left.length+right.length];
        int i=0;
        while (left.length>0 && right.length>0)
            if (left[0]> right[0])
                result[i]=right[0];
                right=Arrays.copyOfRange(right,1,right.length);
            else 
                result[i]=left[0];
                left=Arrays.copyOfRange(left,1,left.length);
            
            i++;
        

        while (left.length>0)
            result[i++]=left[0];
            left=Arrays.copyOfRange(left,1,left.length);
        

        while (right.length>0)
            result[i++]=right[0];
            right=Arrays.copyOfRange(right,1,right.length);
        
        return result;
    

快速排序

由英国计算机科学家托尼·霍尔(Tony Hoare)于1959年想到的,1961年发表的,这个算法也成了今天世界计算机产业中使用最多的排序算法,霍尔因此获得了爵士头衔,也成为第一个获得这种头衔的科学家。


/**
 * 快速排序由于排序效率在同为O(N*logN)的几种排序方法中效率较高,因此经常被采用,再加上快速排序思想----分治法也确实实用
 * 快速排序是C.R.A.Hoare于1962年提出的一种划分交换排序。它采用了一种分治的策略,通常称其为分治法(Divide-and-ConquerMethod)。
 * 该方法的基本思想是:
 * 1.先从数列中取出一个数作为基准数。
 * 2.分区过程,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边。
 * 3.再对左右区间重复第二步,直到各区间只有一个数。
 */
public class QuickSort 

    public static void main(String[] args) 
        int[] list= 81,94,11,96,12,35,17,95,28,58,41,75,15;
        System<

以上是关于排序算法及java实现的主要内容,如果未能解决你的问题,请参考以下文章

算法基础——经典八大排序算法的Java及Python实现

常用排序算法及java语言实现

排序算法及java实现

常见排序算法及Java实现

常用排序算法及Java实现

排序算法及java实现