代码改变世界

归并排序(MergeSort)两种实现方式比较

2011-09-11 20:47  java线程例子  阅读(644)  评论(0编辑  收藏  举报

前面我写的归并排序实现,虽然原理上没什么问题,但算法实现不是很理想,今天没什么事情,重新优化了一下,这里比较一下:

1) 第1种方式,我采用了辅助存储来进行归并,代码如下:

private void MergeSort1(int[] A, int iS, int iE)
        {
            if (iS == iE)
            {
                count++;
                return;
            }
            int iE1 = (iS + iE) / 2;
            int iS2 = iE1 + 1;
            MergeSort1(A, iS, iE1);
            MergeSort1(A, iS2, iE);
            //针对两个排好序的段(iS-iE1,iS2-iE)进行整理
            int i1 = iS, j1 = iS2;
            //这里的归并采用辅助存储空间的方式.
            int[] Result = new int[iE - iS + 1];
            int b = 0;
            while(true)
            {
                count++;
                if (j1 <= iE && i1 <= iE1)
                {
                    if (A[i1] <= A[j1])
                    {
                        Result[b] = A[i1];
                        i1++;

                    }
                    else
                    {
                        Result[b] = A[j1];
                        j1++;
                    }
                }
                else if (j1 <= iE & i1 > iE1)
                {
                     Result[b] = A[j1];
                        j1++;
                   
                  
                }
                else if (j1 > iE & i1 <= iE1)
                {
                    Result[b] = A[i1];
                    i1++;

                }
                else
                {
                    break;
                }
                b++;
            }

            //将结果回写到原数组,这是必须的,否则结果不对.
            for (int j = iS; j <= iE; j++)
            {
                A[j] = Result[j - iS];
                count++;
            }
        
        }

2)第2种方式,归并时没有采取辅助存储,代码如下:

private void MergeSort2(int[] A, int iS, int iE)
        {
            if (iS == iE)
            {
                count++;
                return;
            }
            int iE1 = (iS + iE) / 2;
            int iS2 = iE1 + 1;
            MergeSort2(A, iS, iE1);
            MergeSort2(A, iS2, iE);
            //针对两个排好序的段(iS-iE1,iS2-iE)进行整理归并
            int i1 = iS, j1 = iS2;
            //因为都存放在数组的iS->iE段中,而且从小到大,从左到右存放。
            //最大整理次数为iE-iS,但一般只要整理完其中一段后即可.
            while (true)
            {
                //左边段当前值小于等于右边段最小值,则不需要移动,左边段指针i1右移一位即可。
                if (A[i1] <= A[j1])
                {
                    count++;
                    i1++;//右移
                    //因为两个段都是排序的,左边段如果整理完毕,则左边段不再需要整理
                    if (i1 >= j1)
                    {
                        break;
                    }
                }
                else
                {
                    //如果左边段大于右边段,则需要移位处理.
                    //将j1移到i1处,原来的i1到j1-1整体右移一位.
                    int tmp = A[i1];
                    A[i1] = A[j1];
                    for (int b2 = j1; b2 > i1 + 1; b2--)
                    {
                        A[b2] = A[b2 - 1];
                        count++;
                    }
                    A[i1 + 1] = tmp;
                    i1++; j1++;
                }
                //因为两个段都是排序的,右边段如果整理完毕,则左边段不再需要整理
                if (j1 > iE)
                {
                    break;
                }
            }
        }

两种方式,在速度上相差非常大,我测试后发现,Count计数的差距可达10倍,说明归并时采用上述的插入排序,虽然节省了空间,但时间上损失非常大(因为归并插入排序是的时间复杂度是的2次方级)。第1中方式采用了辅助存储,T(n)=2n,时间复杂度是线性的。实际上,如果归并算法的归并排序如果不借助辅助存储空间,而是移位的话,性能不比纯粹的插入排序好多少。归并排序在时间上和空间上比起快速排序来说,还是差很多。因此归并排序的实现还是要借助辅助存储空间,才会真正发挥其优势。