Java七大排序算法

一、插入排序

1.直接插入排序
public class InsertionSort {
    /**
     * 直接插入排序:把待排序的序列,按其数据的大小逐个插入到前面已经排好序的有序序列中,直到所有的数据插入完为止,得到
     * 一个新的有序序列
     * @param arr
     */
    //以升序为例
    public static void insertSort(int[] arr){
        if(arr==null){
            return;
        }
        int temp=0;
        int i=0;
        int j=0;
        for ( i = 1; i < arr.length ; i++) {//与前面有序序列比较,找位置插入,从第二个数开始往前插入,因为第一个数肯定有序.
            for ( j = 0; j < i; j++) {//遍历比较这个数前面的有序序列.
                if(arr[i]<arr[j]){
                    break;
                }
            }
            //判断要插入,即提前结束循环了.
            if(j<i){
                //此时 j 下标为被插入位置,所以从 j 开始往后移一位.
                temp=arr[i];//记录要插入的值,因为后移时会被覆盖.
                for (int k = i; k > j ; k--) {//后移:从 i 位置开始,逐个被前一个值覆盖.
                    arr[k]=arr[k-1];
                }
                arr[j]=temp;
            }
        }
    }

    public static void main(String[] args) {
        //待排序数组
        int[] arr=new int[]{2,1,-3,32,6,4,33,10,-2,-1,5};
        insertSort(arr);
        System.out.println(Arrays.toString(arr));
    }
}

2.希尔排序
public class ShellSort {
    /**
     * 希尔排序(缩小增量排序 )其基本思想是:把记录按步长 gap(差距,间隙)分组,对每组记录采用直接插入排序方法进行排序。
     * 随着步长逐渐减小,所分成的组包含的记录越来越多,当步长的值减小到 1 时,整个数据合成为一组,构成一组有序记录,则完成排序.
     * 对直接插入排序的优化:前面是预排序,让数据先逐渐趋于有序,步长为 1 时,就是全部数据排序.
     * (少量的数据趋于有序-->大量的数据趋于有序-->全部数据有序)
     * @param arr
     */
    public static void shellSort(int[] arr){
        if(arr==null){
            return;
        }
        //一般初始化步长为数组长度的一半
        int gap = arr.length / 2;

        //步长逐渐减小
        while(gap>=1){
            //步长确定后,可知道步长为多少,就会分成多少组,
            for(int n=0 ;n<gap;n++){//每组分开进行排序,从第一组开始.
                //把插入排序的移动一位,改为移动 gap 位.
                int temp=0;
                int i=0;
                int j=0;
                for ( i = n+gap;  i < arr.length ; i+=gap) {//与前面有序序列比较,找位置插入,从第二个数开始往前插入,因为第一个数肯定有序.
                    for ( j = n; j < i; j+=gap) {//遍历比较这个数前面的有序序列.
                        if(arr[i]<arr[j]){
                            break;
                        }
                    }
                    //判断要插入,即提前结束循环了.
                    if(j<i){
                        //此时 j 下标为被插入位置,所以从 j 开始往后移一个 gap 位.
                        temp=arr[i];//记录要插入的值,因为后移时会被覆盖.
                        for (int k = i; k > j ; k-=gap) {//后移:从 i 位置开始,逐个被前一个值覆盖.
                            arr[k]=arr[k-gap];
                        }
                        arr[j]=temp;
                    }
                }
            }
            gap/=2;//调整步长/2.
        }
    }
    public static void main(String[] args) {
        //待排序数组
        int[] arr=new int[]{4,1,-3,342,6,4,33,10,-2,-1,5};
        shellSort(arr);
        System.out.println(Arrays.toString(arr));
    }

}

二、选择排序

1.直接选择排序
    public static void selectionSort(int[] arr) {
        if(arr==null){
            return;
        }
        int temp=0;
        int maxIndex=0;//最大值下标,每次先假设为0,则遍历从 1 开始.
        int times=0;//遍历次数
        for(times=0;times<arr.length-1;times++){
            for (int i = 1; i < arr.length-times; i++) { //arr.length-times-1 是最后一位
                if(arr[i]>arr[maxIndex]){
                    maxIndex=i;
                }
            }
            if(maxIndex!=arr.length-times-1){//(如果不是最后一位)与最后一位交换
                temp=arr[maxIndex];
                arr[maxIndex]=arr[arr.length-times-1];
                arr[arr.length-times-1]=temp;
            }
            maxIndex=0;//最大值下标重新假设为0
        }

    }
    public static void main(String[] args) {
        //待排序数组
        int[] arr=new int[]{4,1,-3,32,6,4,33,10,-2,-1,5};
        selectionSort(arr);
        System.out.println(Arrays.toString(arr));
    }


    }

2.堆排序
public class Heapsort {
    /**
     * 堆排序:升序 -->建大根堆,降序-->建小根堆.
     * 先建堆,然后进行堆删除.其中都涉及向下调整.
     * @param arr
     */
    public static void heapSort(int[] arr){
        //先建堆,以升序为例,建大根堆.
        //建堆:找倒数第一个非叶子节点(即是倒数第二层的最后一个非叶子节点),从该节点位置开始往前一直到根节点,遇到一个节点,应用向下调整.
        for (int i = (arr.length-1-1)>>2; i>=0; i--) {
            shiftDown(arr,i,arr.length);
        }
        //然后进行堆删除
        //堆删除:把根节点与最后一个节点交换,将新的根节点向下调整.(向下调整时要忽略已经换到后面的数)
        //每删除(交换)一次就会排序好一个数,所以排序 n 个数 要遍历 n-1 次.
        int len=arr.length;
        int temp=0;
        for (int i = 0; i < arr.length-1; i++) {//次数
            //交换首尾
            temp=arr[0];
            arr[0]=arr[len-1];
            arr[len-1]=temp;
            //向下调整
            len--;// 忽略已经换到后面的数
            shiftDown(arr,0,len);
        }
    }

    /**
     * 向下调整,调整为大根堆.
     */
    public static void shiftDown(int[] arr,int parent,int len){
        if(arr==null){
            return;
        }
        int temp=0;
        int child=2*parent+1;//首先得有左孩子
        while(child<len){
            //判断有无右孩子及比较左右孩子大小
            if(child+1<len && arr[child+1]>arr[child]){
                //如果有右孩子且比左孩子大
                child++;//则更新成右孩子.
            }
            //然后比较父节点与孩子节点
            if(arr[child]>arr[parent]){
                //交换
                temp=arr[child];
                arr[child]=arr[parent];
                arr[parent]=temp;
                //把交换了的孩子节点作为新的父节点向下调整.
                parent=child;
                child=2*parent+1;
            }
            else{
                //不用交换则已经是堆结构
                break;
            }
        }

    }
    public static void main(String[] args) {
        //待排序数组
        int[] arr=new int[]{4,1,-3,32,6,4,33,10,-2,-1,5};
        heapSort(arr);
        System.out.println(Arrays.toString(arr));
    }
}

三、交换排序

1.冒泡排序
public class BubbleSort {
    /**
     * 冒泡排序:依次往后比较两两相邻的数字,反序则交换,用双重循环来实现。
     * 以升序为例,每一次比较都会让所有较小的数字往前冒一位,
     * 所以最坏的情况就是最小的数字在最后一位,要把它冒到第一位,则最多要两两相邻比较 arr.length-1次.
     *而且每比较一次都会让一个较大的数字沉底,则后面数据会有序无需参与比较.
     * 另外,如果在一次两两相邻比较过程中没有发生交换,则表示数据已经处于正序,停止循环。
     */
    public static void bubbleSort(int[] arr){
        if(arr==null){
            return;
        }
        int temp=0;
        boolean flag=true;//做标记,没有发生交换,则停止循环.
        for (int i = 0; i < arr.length-1 && flag; i++) {//往后两两相邻比较次数
            flag=false;
            for(int j=0;j<arr.length-i-1;j++){//比较
                if(arr[j]>arr[j+1]){
                    temp=arr[j];
                    arr[j]=arr[j+1];
                    arr[j+1]=temp;
                    flag=true;
                }
            }

        }
    }

    public static void main(String[] args) {
        //待排序数组
        int[] arr=new int[]{4,1,-3,32,6,4,33,10,-2,-1,5};
        bubbleSort(arr);
        System.out.println(Arrays.toString(arr));
    }
}

2.快速排序
public class QuickSort {
    /**
     * 快速排序
     * 基本思想为:任取待排序元素序列中的某元素作为基准值,按照该排序码将待排序集合分割成两子序列,
     * 左子序列中所有元素均小于基准值,右子序列中所有元素均大于基准值.(以升序为例)
     * 然后最左右子序列重复该过程,直到所有元素都排列在相应位置上为止
     * @param arr
     * @param left
     * @param right
     */
    //递归,利用左右双指针
    public static void quickSort(int[] arr, int left, int right){
        if(arr==null){
            return;
        }
        //递归终止条件
        if(left>=right){
            return;
        }
        int base=arr[left];        //选定最左边为基准值
        int l=left;
        int r=right;

        //比较和移动数据,一次循环是右左交替移动
        while(l<r){
           //右
            while( l<r && arr[r]>=base){
                r--;
            }
            if(l==r){//判断上面循环是否是因为l==r而停止,是则终止整个大的循环,不是则遇到了要移动的数据.
                break;
            }
            arr[l]=arr[r];
            //左
            while( l<r && arr[l]<base){
                l++;
            }
            if(l==r){//判断上面循环是否是因为l==r而停止,是则终止整个大的循环,不是则遇到了要移动的数据.
                break;
            }
            arr[r]=arr[l];
        }

        arr[l]=base;//此时l==r 就是基准值的位置

        //左边递归
        quickSort(arr,left,l-1);
        //右边递归
        quickSort(arr,l+1,right);

    }

    public static void main(String[] args) {
        //待排序数组
        int[] arr=new int[]{4,0,-3,342,6,4,23,10,-2,-1};
        quickSort(arr,0,arr.length-1);
        System.out.println(Arrays.toString(arr));
    }
}

四、归并排序

public class MergeSort {
    /**
     *
     * 以升序为例
     */

    //合并两两相邻的被分段数列
    public static void mergeSort(int[] arr,int f,int mid,int s){
        //f--mid 为第一段,mid+1--s 为第二段.
        int i=f;
        int j=mid+1;
        int k=0;
        //用一个新数组放置合并的新数据
        int[] arr2= new int[s-f+1];
        //比较合并两段数据
        while(i<=mid && j<=s){
            if(arr[i]<=arr[j]){
                arr2[k]=arr[i];
                k++;
                i++;
            }
            else {
                arr2[k]=arr[j];
                k++;
                j++;
            }
        }
        //如果其中一段没放完
        while(i<=mid){
            arr2[k]=arr[i];
            k++;
            i++;
        }
        while(j<=s){
            arr2[k]=arr[j];
            k++;
            j++;
        }
        //将数据覆盖原来数组下标位置.
        k=0;
        for (int l = f; l <=s; l++) {
            arr[l]=arr2[k];
            k++;
        }
    }

    //分段
    public static void mergeDiv(int[] arr,int gap){
        //从 0 下标开始,到gap-1为第一段,gap 到 2gap-1 为第二段,依次往后...
        int i;
        for (i = 0; i+2*gap-1<arr.length;  i+=(2*gap)) {//每次都要分个数相等的两段过去合并
            mergeSort(arr,i,i+gap-1,i+2*gap-1);
        }
        //上面循环终止,后面剩下不足以分成两段相等的数据
        if(arr.length-1>(i+gap-1) && i+2*gap-1>arr.length-1 ){//判断后面数据:剩下一段+不足一段
            mergeSort(arr,i,i+gap-1,arr.length-1);
        }
    }

    /**
     * 自下而上的归并(可以看作已经分解好了,向上合并即可):(从每段为 1 个数开始)不断地每两段合并成一段往上合并
     * (我这里按个数相等的两段去合并)
     * (要处理一个问题即后面剩下不足以分成两段相等的数据:
     * 只剩下不足一段(上一步长时合并成的,有序),或刚好一段,它是有序的,不用操作.
     * 剩下一段+不足一段也要合并)
     * @param arr
     */
    public static void sort(int[] arr){
        if(arr==null){
            return;
        }
        //让数组分段
        for(int gap=1;gap<arr.length;gap*=2){//让步长从 1 开始,逐步乘以 2,而且步长不能大于数组长度.
            mergeDiv(arr,gap);
        }
    }

    /**
     * 递归的归并:
     * 将数组不断往下对半分,分到只剩下两个开始往上合并
     * @param arr
     */
    public static void sort2(int[] arr,int left,int right){
        if(arr==null){
            return;
        }
        //递归结束条件
        if(left==right){
            return;
        }
        //对半拆分
        int l=left;
        int m=(left+right)/2;
        int r=right;
        //递归,拆分成左右两边,左右两边再继续分别拆分
        sort2(arr,l,m);//左边
        sort2(arr,m+1,r);//右边
        //合并
        mergeSort(arr,l,m,r);
    }

    public static void main(String[] args) {
        //待排序数组
        int[] arr=new int[]{4,1,-3,32,6,4,5312,10,-2,-1,5};
        int[] arr2=new int[]{4,6,2,52,3,3,5,6,234,0,7};

        //sort(arr);//自下而上的归并
        sort2(arr,0,arr2.length-1);
        System.out.println(Arrays.toString(arr));
    }
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值