数据结构 JAVA描述(十二) 归并排序 链式基数排序

归并排序

    /**
     * @description 2-路归并排序算法  归并过程中引入数组temp[],第一趟由a归并到temp,第二趟由temp归并到a,如此反复直到n个记录为一个有序表
     *              返回的是a[]。不论是偶数趟还是奇数趟,最后都会mergepas(temp, a, s, n); 数据都会在a中
     * @return
     * @author liuquan
     * @date  2016年1月5日
     */
    public static int[] mergeSort(int[] before){
        int[] a= Arrays.copyOf(before, before.length);
        int s = 1; //s为已排序的子序列长度
        int n = a.length;
        int[] temp = new int[n];
        while(s < n){
            mergepas(a, temp, s, n);
            s *= 2;
            mergepas(temp, a, s, n);
            s *= 2;
        }
        return a;
    }

    /**
     * @description 一趟归并排序的算法
     * @param a
     * @param b
     * @param s s是待归并的有序子序列的长度
     * @param n n是待排序序列的长度
     * @author liuquan
     * @date  2016年1月5日
     */
    private static void mergepas(int[] a, int[] b, int s, int n){
        int p = 0;  //p为每一对待合并表的第一个元素的下标
        //首先两两归并长度均为s的有序表
        while(p + 2 * s - 1 <= n - 1){
            merge(a, b, p, p + s - 1, p + 2 * s -1);
            p += 2 * s;
        }
        //归并最后两个长度不相等的有序表
        if(p * s - 1 < n - 1){
            merge(a, b, p, p + s - 1, n - 1);
        }
        else{ //只剩余一个有序表了,直接复制到b中
            for(int i = p; i <= n - 1; i++){
                b[i] = a[a];
            }
        }
    }


    /**
     * @description 把两个相邻的有序表a[h……m]和a[m+1……t]归并成一个有序表 b[h……t] 
     * @author liuquan
     * @date  2016年1月5日
     */
    private static void merge(int[] a, int[] b, int h, int m, int t){
        int i = h, j = m +1, k = h;
        //将a中两个相邻子序列归并到b中
        while(i <= m && j <= t){
            if(a[i] <= a[j]){
                b[k++] = a[i++];
            }
            else{
                b[k++] = a[j++];
            }
        }
        //将剩余子序列复制到b中
        while(i <= m){
            b[k++] = a[i++];
        }
        while(j <= t){
            b[k++] = a[j++];
        }
    }

算法性能分析

  • 空间复杂度:O(n),存在一个辅助数组

  • 时间复杂度:归并趟数为[㏒₂ n],而每一对有序序列的归并时的比较次数均不大于记录的移动次数,而记录的移动次数=n,所以时间复杂度是O(n ㏒₂ n)

  • 算法稳定性:稳定


基数排序

假设n个记录的排序表中的每个记录包含d个关键字{k1,k2,……kd},排序的有序表是指表中任意两个记录a[i]和a[j]都满足有序关系:
(ki1,ki2,ki3……kid) < (kj1,kj2……kjd)
其中k1称为最主位关键字,kd称为最次位关键字

多关键字的排序有两种:

  • 最主位优先(Most Significant Digit First),简称MSD法

  • 最次位优先(Least Significant Digit First),简称LSD法

链式基数排序

在基数排序中,常使用d表示关键字的位数,用rd表示关键字可取值的种类数,例如:关键字为一个3位数,则d = 3,每一个关键字为数字,rd=10.

执行基数排序可采用链表的存储结构,用一个长度为n的单链表r存放待排序的n个记录,再使用两个长度为rd的一维数组f和e,分别存放rd个队列中指向队首结点和队尾结点的指针:

  • 形成初始链表
  • 将最小的关键字值作为当前关键字,即i=d
  • 执行第i趟分配和收集。链头和链尾分别由f[0……rd-1]和e[0……rd-1]指向,再将这rd个子序列头尾相连形成一个新的当前处理序列。
  • 将当前关键字向高位推进一位,即i = i-1;重复执行上面步骤,直到d位关键字处理完毕。

算法性能分析

  • 空间复杂度: 2*rd个队首和队尾的辅助空间,n个链表指针

  • 时间复杂度:O(d(n+rd))
    其中一趟分配的时间复杂度为0(n),一趟收集的时间复杂度为O(rd),共进行了d趟分配和收集,所以时间复杂度是O(d(n+rd))

  • 算法稳定性:稳定

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值