七种基于比较的排序,基于Java实现,收藏一下?

Posted Java_程_序_员

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了七种基于比较的排序,基于Java实现,收藏一下?相关的知识,希望对你有一定的参考价值。

一.总览

二.基于比较的排序算法

1.简单插入排序(重点)

注意:区间较小时,最快 原理: 一组数据array[],认为以下标i为分界,[0,i+1)认为有序,[i+1,array.length)无序,从无序数据中每次取出一个数据,插入有序数据中

代码实现:

 public static void insertSort(long []array)
        //数据一共有array.length个
        //所以,子操作需要执行array.length次
        //减不减一都可以,减一认为第一个数已经有序
        for (int i = 0; i <array.length-1 ; i++) 
            //有序[0,i+1)  例如刚开始[0,1)有序
            //无序[i+1,array.length)
            //抓取出来的数是[i+1]

            long key=array[i+1];
            int j=0;
            //依次在有序区间进行比较
            for ( j = i; j>=0 ; j--) 
                //[j]就是需要和key比较的数
                /**
                 * key<array[j]   把array[j]往后移 继续往前比较
                 * key==array[j]  把key放入array[j]的后边
                 * key>array[j]   把key放入array[j]的后边
                 */
                if(key<array[j])
                    array[j+1]=array[j];
                else 
                    break;
                
            
            array[j+1]=key;

        
    

性能分析:

2.冒泡排序(重点)

原理:

在无序区间,通过相邻数的比较,将最大的数冒泡到无序区间的最后,持续这个过程,直到数组整体有序

无序区间:[0,array,length-i)

有序区间:[array.length-i,array.length)

从下标j开始,将其与下标j+1依次比较,如果大于,交换。

代码实现:

public static void bubblingSort(long []array)
    //外层循环,需要多少次冒泡的过程
        for (int i = 0; i <array.length ; i++) 
            //无序区间:[0,array,length-i)
            //有序区间[array.length-i,array.length)

            //假设数组已经有序
            boolean isSorted=true;

            //冒泡过程
            //只在无序区间中进行
            //循环到无序区间的倒数第二个数,然后倒数第二会和倒数第一再比较
            for (int j  = 0; j  <array.length-i-1 ; j ++) 
                if(array[j]>array[j+1])
                  swap(array, j, j+1);
                  //交换过,说明数组无序
                    isSorted=false;
                
            

            //如果数组有序,退出循环
            if(isSorted)
                break;
            
        
    

    public static void swap(long []array,int i,int j)
     long t=array[i];
     array[i]=array[j];
     array[j]=t;
    

性能分析:

3.简单选择排序

**原理:

每一次从无序区间选出最大(或最小)的一个元素,存放在无序区间的最后(或最前),直到全部待排序的数据元素排完 。

以选取最大为例:

无序区间[0,array.length-i)

有序区间[array.length-i,array.length)

动态图为选取最小为例:

代码实现:

//选择排序

    /**
     *选择大的数
     * 前面为有序区间,后面为无序区间
     * 再无序区间中遍历,找到最大的数,和无序区间的最后一个数进行交换
     */
    public static void selectSort(long[]array)
        //一共多少次选择的过程
        for (int i = 0; i <array.length ; i++) 
            //无序区间:[0,array.length-i)
            //有序区间:[array.length-i,array.length)
            //记录无序区间最后一个值的下标和值
            int maxindex=array.length-i-1;
            long key=array[array.length-i-1];
            for (int j = 0; j <array.length-i ; j++) 
                if(array[j]>key)
                    maxindex=j;
                    key=array[j];
                
            
            //期望maxIndex指向无序区间的最大值的下标
            //交换最大数所在下标和无序区间最后一个数的下标
            swap(array, maxindex, array.length-i-1);
        
    

    public static void swap(long[]array,int i,int j)
        long t=array[i];
        array[i]=array[j];
        array[j]=t;
    

性能分析:

4.堆排序

原理: 基本原理也是选择排序,只是不在使用遍历的方式查找无序区间的最大的数,而是通过堆来选择无序区间的最大的数。
注意:排升序要建大堆,排降序要建小堆,否则不行

代码实现:

public class HeapSort 
    public static void heapSort(long[]array,int size)
       //1.建大堆
          bulidHeap(array,size);
        //2.进行选择的过程,一共需要array.length-1组
        for (int i = 0; i <array.length-1 ; i++) 
            //无序区间:[0,array.length-i)
            //有序区间:[array.length-i,array.length)
            swap(array,0,array.length-i-1);
            //此时无序区间:[0,array.length-i-1)
            //无序区间的个数为array.length-i-1
            adjustDown(array,array.length-i-1,0);
        
    
    //交换
    public static void swap(long[]array,int i,int j)
        long t=array[i];
        array[i]=array[j];
        array[j]=t;
    
    //建大堆
    public static void bulidHeap(long []array,int size)
        int lastNodeIndex=size-1;
        int lastParentIndex=(lastNodeIndex-1)/2;
        for (int i = lastParentIndex; i >=0 ; i--) 
            adjustDown(array,size,i);
        

    
    //向下调整
    public static void adjustDown(long[]array,int size,int index)
        while (true)
            //堆是完全二叉树,一定有左孩子
            int leftIndex=index*2+1;
            //如果没有左孩子,则为叶子结点,直接return
            //等于size也超出了数组下标范围
            if(leftIndex>=size)
                return;
            
            //找最大的孩子
            int maxIndex=leftIndex;
            int rightIndex=leftIndex+1;
            //如果右孩子存在且右孩子的值大于左孩子,则将最大值的下标改为右孩子
            if(rightIndex<size&&array[rightIndex]>array[leftIndex])
               maxIndex=rightIndex;
            
            //比较maxIndex和index位置的值,如果maxIndex大,则交换,否则retrun
            if(array[maxIndex]<=array[index])
                return;
            
            swap(array, maxIndex, index);
            index=maxIndex;
        
    

性能分析:

5.希尔排序

原理:

分组插入排序

希尔排序法的基本思想是:先选定一个整数,把待排序文件中所有记录分成个组,所有

距离为的记录分在同一组内,并对每一组内的记录进行插入排序。然后,取,重复上述分组和排序的工作。当到达=1时,所有记录在统一组内排好序。

步骤:

1.分为gap组,认为gap之前的都是有序的(每组一个数)

2.对分好的每一个组,在组内进行插入排序

代码实现:

//希尔排序(带间隔的插入排序)
public class ShellSort 
    public static void shellSort(long[]array)
        int gap=array.length/2;

        while (true)
            insertSortWithGap(array, gap);
            if(gap==1)
                break;
            
            gap=gap/2;
        
    

    public static void insertSortWithGap(long[]array,int gap)
        //分为gap组,认为gap之前的都是有序的(每组一个数)
        for (int i =gap; i <array.length ; i++) 
            //记录需要比较的值
          long key=array[i];
          int j=0;
          //对每组的值进行插入排序,每组间隔为gap个
            for (j =i-gap; j >=0 ; j=j-gap) 
                if(key<=array[j])
                    array[j+gap]=array[j];
                else 
                    break;
                
            
            array[j+gap]=key;
        
    

性能分析:

6.快速排序(重点)

原理: 快速排序原理:

partition分割原理:Hover法

步骤: 1.选择一个数key(一般选最左边)
2.做partition分隔(小的放左边,大的放右边)
3.分别做左右两个小区间按相同的方式处理(递归)
4.知道(小区间有序:区间数的个数size<=1)

代码实现:


public class QuickSort 
    public static void quickSort(long[]array)
        //排序的区间为lowIndex到highIndex
        quickSortInteral(array,0,array.length-1);
    

    private static void quickSortInteral(long[]array,int lowIndex,int highIndex)
        //记录区间内数的个数
        //区间是[lowIndex,highIndex]
        int size=highIndex-lowIndex+1;
        //当区间内个数小于等于一时,区间有序
        if(size<=1)
            return;
        

        //1.选择其中一个数出来(最左边)->array[lowIndex]
        //2.执行partition(分隔),小的数放左,大的数放右

        //keyIndex是经过partition后,选出来的数的最终下标
        int keyIndex=partitionHover(array,lowIndex,highIndex);

        //keyIndex左边: 左边的lowIndex=lowIndex,highIndex=keyIndex-1
        //keyIndex右边: 右边的lowIndex=keyIndex+1,highIndex=highIndex

        //分别左左右区间相同处理->递归
        quickSortInteral(array, lowIndex, keyIndex-1);
        quickSortInteral(array, keyIndex+1, highIndex);

    
    //区间为array[lowIndex,highIndex]
    //1.选择array[lowIndex]作为特殊的数
    //2.需要遍历整个区间(不能遗漏任何数),与选择出来的数进行比较
    //3.保证小于等于的在最左边,大于等于的数在最右边(但没有顺序要求)
    private static int partitionHover(long []array,int lowIndex,int highIndex)
       int leftIndex=lowIndex;
       int rightIndex=highIndex;
       //选择的数是最左边的
        //注意:选择最左边的数key,要让rightIndex先动起来,不然右边全小于key的情况不好考虑
        long key=array[lowIndex];
        while (leftIndex<rightIndex)
            while (leftIndex<rightIndex&&array[rightIndex]>=key)
                //当右边的值大于key,rightIndex继续往左走
                rightIndex--;
            
            while (leftIndex<rightIndex&&array[leftIndex]<=key)
                //当左边的值小于key,leftIndex继续往右走
                leftIndex++;
            
            //当leftIndex和rightIndex都停下来时,交换
            swap(array, leftIndex, rightIndex);

            //当leftIndex和rightIndex相遇时,循环结束
        
        //交换开始选中的值leftIndex和上述停止相遇的值lowIndex
        swap(array, leftIndex, lowIndex);

        //返回选中的key值当前的位置
        return leftIndex;

    

    private static void swap(long[]array,int i,int j)
        long t=array[i];
        array[i]=array[j];
        array[j]=t;
    

性能分析:

时间复杂度:每次partition的时间为O(n),然后乘以二叉树的高度

7.归并排序(二路归并)(重点)

原理: 归并思想:

数组合并思想:
创建一个新数组,数组大小个原数组大小相等
遍历将左边和右边两个有序区间,并比较。如同打擂台,小的数放入新数组
最后将新创建的数组复制到原数组即可

整体思想:

代码实现:

//归并排序
public class MergeSort 
    public static void mergeSort(long[]array)
        mergeSortInternal(array,0,array.length);

    

    //区间范围是左闭右开
    //array[lowIndex,highIndex)
    private static void mergeSortInternal(long[] array, int lowIndex, int highIndex) 

        int size=highIndex-lowIndex;
        if(size<=1)
            return;
        
        int middleIndex=(highIndex+lowIndex)/2;
        //区间被分成左右两份
        //左区间:[lowIndex,middleIndex)
        //右区间: [middleIndex,highIndex)

        //递归
        mergeSortInternal(array, lowIndex, middleIndex);
        mergeSortInternal(array, middleIndex, highIndex);

         //左右两个区间都有序
        mergeLeftAndRight(array,lowIndex,middleIndex,highIndex);

    

    //合并两个有序区间
    private static void mergeLeftAndRight(long[] array, int lowIndex, int middleIndex, int highIndex) 
        //两个区间数的总数
        int size=highIndex-lowIndex;
        long[]extraArray=new long[size];

        //遍历(三个下标,一个数组一个)
        int leftIndex=lowIndex;
        int rightIndex=middleIndex;
        int extraIndex=0;

        //两个队伍都有人
        while (leftIndex<middleIndex&&rightIndex<highIndex)
            //加等于保证稳定性
            if(array[leftIndex]<=array[rightIndex])
                extraArray[extraIndex]=array[leftIndex];
                leftIndex++;
            else 
                extraArray[extraIndex]=array[rightIndex];
                rightIndex++;
            
            extraIndex++;
        

        //直到有个队伍没有人
        if(leftIndex<middleIndex)
            //左边队伍有人
            while (leftIndex<middleIndex)
                extraArray[extraIndex++]=array[leftIndex++];
            
        else 
            //右边队伍有人
            while (rightIndex<highIndex)
                extraArray[extraIndex++]=array[rightIndex++];
            
        

        //最后把数据从extraArray新数组搬回去
        //新数组extraArray[0,size)
        //搬回去的下标范围[lowIndex,highIndex)
        for (int i = 0; i <size; i++) 
            array[i+lowIndex]=extraArray[i];
        
    


性能分析:

三.性能总结

四.jdk中提供的排序方法

五.海量数据的排序

以上是关于七种基于比较的排序,基于Java实现,收藏一下?的主要内容,如果未能解决你的问题,请参考以下文章

基于比较的七种常见排序算法

基于比较的七种常见排序算法

数据结构 用java实现七种排序算法。

Java实现七种排序算法,你get到了吗?

七种经典排序算法最全攻略

Java实现快速排序