排序算法(三)归并、基数排序

本文深入解析归并排序与基数排序算法,详细阐述了归并排序的分治递归思想及其实现过程,同时介绍了基数排序作为桶排序的扩展,如何通过键值的位值进行高效排序。

归并排序

归并排序是一种利用分治递归思想排序的算法。这个算法的基本操作就是将两个有序表合并。因此在设计算法时要先将原数组划分到每组只有一个元素,这时就可以将每组都看成有序表,再将其依次合并,这里使用递归方法就能巧妙的解决。
在做合并操作的时候需要三个指针 leftPos,rightPos,和tempIndex分别指向左有序表首位置,右有序表首位置,和零时数组首位置。

import java.util.Arrays;

public class MergeSort {
    public static void main(String[] args) {
        int[] arr = new int[20];
        for(int i=0;i<20;i++){
            arr[i]=(int)(Math.random()*100);
        }
        System.out.println("排序前数组");
        System.out.println(Arrays.toString(arr));
        int[] temp =new int[arr.length];
        mergeSort(arr,temp,0,arr.length-1);
        System.out.println("排序后数组");
        System.out.println(Arrays.toString(arr));
    }
    //无序数组分解部分
    private static void mergeSort(int[] arr,int[] temp,int left,int right){
        int center =(left+right)/2;
        if(left<right){
            mergeSort(arr,temp,left,center);
            mergeSort(arr,temp,center+1,right);
            merge(arr,temp,left,center+1,right);
        }
    }
    //两个有序表合并部分
    private static void merge(int[]arr,int[] temp,int leftPos,int rightPos,int rightEnd ){
        int tempIndex = leftPos;
        int leftEnd = rightPos-1;
        int num = rightEnd-leftPos+1;
        //左侧有序数组,与右侧有序数组从各自首索引位置开始比较
        //小数存入temp数组,并将其索引和temp索引后移
        while (leftPos<=leftEnd && rightPos<=rightEnd){
            if(arr[leftPos]<=arr[rightPos]){
                temp[tempIndex]=arr[leftPos];
                leftPos++;
                tempIndex++;
            }else {
                temp[tempIndex]=arr[rightPos];
                rightPos++;
                tempIndex++;
            }
        }
        // 剩下的一侧直接复制到temp数组中
        while (leftPos<=leftEnd){
            temp[tempIndex]=arr[leftPos];
            leftPos++;
            tempIndex++;
        }
        while (rightPos<=rightEnd){
            temp[tempIndex]=arr[rightPos];
            rightPos++;
            tempIndex++;
        }
        //最后将temp数组拷贝回原数组中
        for(int i=0;i<num;i++,rightEnd--){
            arr[rightEnd]=temp[rightEnd];
        }
    }
}
结果:
排序前数组
[81, 90, 31, 79, 33, 2, 64, 98, 45, 13, 40, 54, 81, 47, 18, 91, 33, 15, 25, 14]
排序后数组
[2, 13, 14, 15, 18, 25, 31, 33, 33, 40, 45, 47, 54, 64, 79, 81, 81, 90, 91, 98]

基数排序

基数排序属于分配式排序,它是通过键值的各个位的值将要排序的元素分配至某些桶中,达到排序的作用。它是桶排序的扩展。
排序思路: 找出数组中最大数的长度,也就是位数,如arr={10,24,1,3,890,124,1111}最大数是1111,即要进行4轮排序。每轮排序按照个位,十位,百位,千位依次进行。创建10个桶,可以用二维数组实现bucket[10][arr.length],存储排序数组中的元素。再建立一个一维数组bucketCount【10] 记录每个桶中存放的元素个数。个位是1就放入bucket[1][bucketCount[k] ] 中。将所有元素放入桶中后,再将桶中元素按桶的顺序,依次取出,就得到第一轮排序后的数组。第二轮排序按照十位的数放入桶中,再取出,第三轮排序按照百位的数放入桶中再取出,直到所有轮排序结束,就得到最后的结果。

import java.util.Arrays;

public class RadixSort {
    public static void main(String[] args) {
       int[] arr = new int[10];
        for(int i=0;i<10;i++){
            arr[i]=(int)(Math.random()*100000);
        }
        System.out.println("排序前数组");
        System.out.println(Arrays.toString(arr));
        RadixSort(arr);
        System.out.println("排序后数组");
        System.out.println(Arrays.toString(arr));
    }
    private static void RadixSort(int[] arr){
        int max = arr[0];
        for(int i=1;i<arr.length;i++){
            if(max<arr[i]){
                max=arr[i];
            }
        }
        int maxLength = (max+"").length();
        int bucket[][] =new int[10][arr.length];
        int bucketCount[] = new int[10];
        //外循环控制排序轮数,等于最大数的长度
        for(int i=0, n=1;i<maxLength;i++,n*=10){
            //将数组元素按位数放入桶中
            for(int j=0;j<arr.length;j++){
                int digitOffElement = arr[j] /n %10;
                bucket[digitOffElement][bucketCount[digitOffElement]]=arr[j];
                bucketCount[digitOffElement]++;
            }

            //将桶中元素取出
            int index = 0;
            for(int k=0;k<bucket.length;k++){
                if(bucketCount[k]!=0){
                    for (int j=0;j<bucketCount[k];j++){
                        arr[index++]=bucket[k][j];
                    }
                }
                bucketCount[k]=0;
            }
        }
    }
}
排序前数组
[69653, 68330, 46350, 95244, 48707, 46300, 69834, 21745, 86273, 73735]
排序后数组
[21745, 46300, 46350, 48707, 68330, 69653, 69834, 73735, 86273, 95244]

基数排序是典型的用空间换时间的排序方法,它需要开辟额外的空间(桶)存储数据。上述的基数排序代码还不能解决有负数的情况。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值