【算法】使用链接表改进归并排序算法

算法思想的理解与分析

内容为针对归并排序的递归层次和元素频繁移动改进归并排序算法,在排序容量较小时直接使用链接表版本的插入排序,从而克服低层递归调用所带来的消耗过大的问题;容量较大时采用链接表版本的归并排序。传统归并排序算法使用了辅助数组B(1:n),算法在这附加空间上竭力地工作,在每次调用merge方法时,把存放在B(low:high)中的结果复制回A(low:high)去,我们考虑,使用一个以整数表示的链接信息数组link来替换暂时存放元素的辅助数组B,这样就可以节省一些附加空间。链接表中数值的意义为下一个元素的下标位置,因此链接表可以看作一个指针序列,链接表的归并不必移动元素本身,只要改变相应的链值即可,用0表示表的结束。

实现该算法使用了三个方法:insertSort方法、merge1方法和mergeSort1方法:

insertSort方法为链接表版本的插入排序,参数为要排列序列的起点和终点坐标,作用为更新link数组。首先定义一个head指针指向序列开头,在head的后一个起遍历整个序列,如果第i个位置的值小于head位置的值,就将link[i]的值置为head,即将head链接在当前i位置之后,再把head的值更新为当前位置i;如果第i个位置的值大于head位置的值,就从head开始在link数组中依次往后找,直到找到尚未链接的或者找到比当前i位置的值小的最大数为止,如果找到尚未链接的,就将当前位置i赋值给link数组中找到的尚未链接的位置,如果找到比当前i位置的值小的最大数,就将link数组的该值赋给link[i],意即将当前值链接在比当前值小的最大的数之后,再将i的值赋给link数组中找到的位置。

merge1方法的作用为使用链接表归并已排序的集合,参数为p、r和q,q和r是全程数组link(1:n)中两个表的指针,这两个表用来获取全程数组A(1:n)中已排序元素的子集合,该方法执行后构造出一个由p指示的新表,利用此表可以得到按非降序把A中元素排序好的元素表。首先找到p、r两个表开头中较小的作为新开头,之后对两个表的元素一一比较,选择较小的链接在开头后边,如果其中一个表结束了而另一个表还没结束,就将没结束的部分直接连接在后边。

mergeSort1方法利用辅助数组link(low:high)将全程数组A(low:high)按非降序排序。如果待排序序列的长度小于16,就直接调用insertSort方法进行插入排序,否则将待排序序列均分为两份,分别递归地调用mergeSort1方法进行排序。

package improvedMerge;

import java.util.Random;
import java.util.Scanner;

public class merge {

    //作用:插入排序,更新link数组并返回link数组头指针
    static int insertSort(int start, int end, int a[], int link[]){
        int head= start;
        for(int i=start+1;i<=end;i++){
            if (a[i] <= a[head]) //如果当前位置的值小于head位置的值
            {
                link[i] = head;//将head连到当前位置的后面
                head = i;//将当前位置作为新的head
            }
            else
            {
                int j = head;//从head开始找
                while ((link[j] != -1) && (a[link[j]] <= a[i]))
                    j = link[j];//从head顺着link往后找,直到找到未连接的或者找到比当前值小 的最大值为止

                if (link[j] == -1)//如果找到了未连接的
                    link[j] = i;

                else //如果找到的是比当前值小的最大值
                {//则将当前值插到这个值后面
                    link[i] = link[j];
                    link[j] = i;
                }
            }
        }
        return head;
    }

    static int merge1(int q, int r, int link[], int a[])
    {
        int head;

        //找到两个开头中,最小的作为新开头
        if (a[q] > a[r]) {
            head = r;
            r = link[r];
        }
        else {
            head = q;
            q = link[q];
        }

        int k = head;
        int i = q, j = r;
        while (i != -1 && j != -1) {
            if (a[i] < a[j]) {
                link[k] = i;
                k = i;
                i = link[i];
            }
            else {
                link[k] = j;
                k = j;
                j = link[j];
            }
        }
        if (i == -1)
            link[k] = j;
        else
            link[k] = i;

        return head;
    }
    static int mergeSort1(int low, int high, int a[], int link[])
    {
        if (high - low + 1 < 16)
        {
            int p = insertSort(low, high,a,link);
            return p;
        }
        else
        {
            int mid = (low + high) / 2;
            int q = mergeSort1(low, mid,link,a);
            int r = mergeSort1(mid + 1, high,link,a);
            return merge1(q, r,a,link);
        }
    }

    public static void main(String[] args) {
        int length = 0;
        int begin = 0;
        Scanner sc=new Scanner(System.in);
        Random rd=new Random();

        System.out.println("输入随机生成的数据个数:");;
        length=sc.nextInt();

        int a[] = new int[length];//待排序数组
        int b[]= new int[length];//存放排好序的数组
        int link[] = new int[length];//链接表

        //用随机数填充待排序数组
        System.out.println("排序前:");
        for (int i = 0; i < length; ++i) {
            a[i] = (rd.nextInt()) % 100;
            System.out.print(a[i]+" ");//输出未排序的数组
            link[i] = -1;//这里用-1初始化链接表,使得待排序数组下标可被全部利用
        }
        System.out.println();
        //基于链接表的归并排序
        begin = mergeSort1(0, length - 1,a,link);

        //将原数组按link的次序放入数组b中,同时输出
        int i = 0;
        System.out.println("排序后:");
        for (int j = begin; j != -1; j = link[j]) {
            b[i++] = a[j];
            System.out.print(a[j] + " ");
        }
    }
}
  • 2
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

WiIsonEdwards

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值