zoukankan      html  css  js  c++  java
  • 归并排序

     拿出读书时写的C代码,现在看发现看不懂了,原因是当时学数据结构时没写清具体的思路,这次为避免同样问题,把自己具体理解的过程写下来,特别是一些细节,这样以后用到时可以省下不少时间.

       从上到下两路归并

      归并:
    有两个有序序列(即已经排序过的)A,B, 那么可以通过以下方法将A,B序列合并成序列C.
    取A,B的第一个元素进行比较,将较小的元素存入C,接着取下一个元素(存入C后那个元素序列的下一个),直到A,B其中一个序列为空,那么将另外一个不为空的序列余下元素复制到C中,这样就得到一个有序的C序列,其元素来自A,B两序列.

     以上描述可以用下面的C代码表示:
     -----------------------------------------

    // r为待排序数组指针,buffer为辅助空间,其大小应该满足:

    // buffer.Length >=r.Length

    void merge(int *r, int *buffer, int l, int m, int h)
    {

       int k;
       int i,j;
       //  L (这里大写) 为第一个序列的开始下标,h为第二个序列的结束下标
      //  m 为 (L+h)/2 的值, 因此 L~M 为第一个序列的地址范围,M+1 ~ h 为第二个序列的范围

       for(i=l,k=l,j=m+1; i<=m && j<=h;k++)
         {
           if(r[i] < r[j]) buffer[k]=r[i++];
           else buffer[k]=r[j++];
         }

       //复制余下元素到辅助空间
       while(i<=m)
          buffer[k++]=r[i++];
       while(j<=h)
          buffer[k++]=r[j++];
    }

     归并排序将待排序序列看作一个由r.Length( r为数组指针)个有序序列组成的集合(每个序列开始只有一个元素,因此这个只有一个元素序列必然是有序的), 我们将集合中的序列两两合并(归并,使用上面的方法)形成较大的序列(2个元素),
    而集合长度则变为原来的一半,如此往复下去,最后集合包含2个待排序的有序序列,归并这两个序列即得到排序的结果.

    代码( C描述)
    -------------------------------
    void msort(int *r, int *buffer,int l,int h)
    {
      //声明函数原形
      void merge(int *r, int *buffer, int l, int m, int h); 
      void copy(int * r, int *buffer, int l, int h);
      int m;

      if(l < h) //保证区间至少包括2个元素,只含一个元素的取间已经有序了
          { m=(l+h)/2;
            msort(r,buffer,l,m); //排序左边
            msort(r,buffer,m+1,h); //排序右边
            merge(r,buffer,l,m,h); //合并左右两个有序序列
            copy(r,buffer,l,h); //将辅助空间中已经排序的元素复制回到r空间
          }

    }

    说明:
      上面的递归操作第一次输入的L,h是数组r 的上下标(0,n-1),递归在L=H时开始反回,第一次反回后, H-L=1(2个元素的区间,实际上上H=1,L=0)因此有m=(h+l)/2=(L+L+1)/2=L (整数相除 3/2=1,5/2=2),这样m+1=h ,msort(r,buffer,m+1,h) 调用直接返回(排序右边的操作),
    而merge(r,buffer,L,M,h)将归并含2个元素的区间的两个序列(每个序列有一个元素).完成后返回上一层.(这里是0跟1元素排序完成后返回).

    另外这里先左还是先右效果是一样的

    记的当时学习时是将每次调用的各变量跟过程一一写在纸上,逐步演推下来,这样就比较清楚了.

     关键点:
        1. 两个有序序列的合并
        2.递归调用的返回条件设置,具体调用的推演
                3.  两个整数相除后的结果是取最接近这个实数,但不大于这个实数的整数,(比方 5/2=2.5 ,取2为结果)

    下面是C#中使用泛型实现的归并排序类:

    ------------------------------------------

    public class MergeSort<T>
        {
            private static readonly MergeSort<T> _instance = new MergeSort<T>();

            public static void Sort(T[] array, IComparer<T> comparer)
            {
                _instance.MSort(array, comparer);
            }
            private void Merge(T[] array, T[] buffer, int L, int m, int h,IComparer<T> comparer)
            {
                int k, i, j;
                for (i = L, k = L, j = m + 1; i <= m && j <= h; k++)
                {
                    if (comparer.Compare(array[i], array[j]) < 0) buffer[k] = array[i++];
                    else buffer[k] = array[j++];
                }
                while (i <= m)
                    buffer[k++] = array[i++];
                while (j <= h)
                    buffer[k++] = array[j++];

                for (i = L; i <= h; i++)
                {
                    array[i] = buffer[i];
                }

            }
            private void MSort(T[] array, IComparer<T> comparer)
            {
                T[] buffer = new T[array.Length];
                int L = 0;
                int h = array.Length - 1;
                Sort(array, buffer, L, h,comparer);
            }
            private void Sort(T[] array, T[] buffer, int L, int h, IComparer<T> comparer)
            {
                int m = 0;
                if (L < h)
                {
                    m = (L + h) / 2;
                    Sort(array, buffer, L, m,comparer);
                    Sort(array, buffer, m + 1, h,comparer);
                    Merge(array, buffer, L, m, h,comparer);
                }
            }

        }
    客户端调用代码示例

    ------------------------------------

            private void button1_Click(object sender, EventArgs e)
            {
                int[] t ={ 1, 8, 23, 234, 2, 6, 7, 77, 18, 21 };
                MergeSort<int>.Sort(t, new IntComparer());
                foreach (int i in t)
                {
                    textBox1.Text += i + ",";
                }
                textBox1.Text= textBox1.Text.TrimEnd(",".ToCharArray());
                textBox1.Text += Environment.NewLine;
               

                string[] r ={ "A", "C", "B", "F", "K", "Z" };
                MergeSort<string>.Sort(r, new StringComparer());
                foreach (string item in r)
                {
                    textBox1.Text += item + ",";
                }

                textBox1.Text= textBox1.Text.TrimEnd(",".ToCharArray());
                textBox1.Text += Environment.NewLine;
                string[] R ={ "X", "X", "P", "J", "K" };
                MergeSort<string>.Sort(R, new StringComparer());
                foreach (string item in R)
                {
                    textBox1.Text += item + ",";
                }
                textBox1.Text = textBox1.Text.TrimEnd(",".ToCharArray());
                textBox1.Text += Environment.NewLine;
            }
           
            public class StringComparer : IComparer<string>
            {
                public int Compare(string x, string y)
                {
                    return string.Compare(x, y, true);
                }
            }
            public class IntComparer : IComparer<int>
            {
                public int Compare(int x, int y)
                {
                    return x - y;
                }

            }

    --------------------------------------
    从下到上两路归并
    自下到上的两路归并排序消除了递归调用,首先按段长为1进行两两归并,接着按段长为2进行两两归并,这样按照1,2,4,8,16....的长度归并下去直到得到等长度的完整序列,在归并时需要考虑最后元素个数在不足两个段长时,或不足一个段长时的处理,MSort中采用在两个数组里互相拷的办法虚拟地消除复制过程.
    下面是C#的泛型实现代码,客户端调用参考上面的

    --------------------------------------------------

      public class MergeSortB<T>
        {
            private static readonly MergeSortB<T> _instance = new MergeSortB<T>();

            public static void Sort(T[] array, IComparer<T> comparer)
            {
                _instance.MSort(array, comparer);
            }
            private void Merge(T[] a, T[] b, int L, int m, int h, IComparer<T> comparer)
            {
                int k, i, j;
                for (i = L, k = L, j = m + 1; i <= m && j <= h; k++)
                {
                    if (comparer.Compare(a[i], a[j]) < 0) b[k] = a[i++];
                    else b[k] = a[j++];
                }
                while (i <= m)
                    b[k++] = a[i++];
                while (j <= h)
                    b[k++] = a[j++];
            }
            private void MSort(T[] a,IComparer<T> comparer)
            {
              
                int n = a.Length;
                T[] b = new T[n];
                int s = 1;//段长开始为1,段长将按1,2,4,8,16...这样的方式增长
                //s>=n时表示排序完成了,即段长达到数组长度
                //for(s;s<n;s*=2)
                //{
                //  MergePass(a,b,s,n,comparer);
                //采用这个形式时需要在Merge中将元素从辅助空间中复制回数组中
                //具体参考上面递归实现的Merge方法,另外MergePass也需要做相应修改
                //}

                while (s < n)
                {
                    MergePass(a, b, s, n, comparer);
                    s += s;
                    //保证最终把b中的元素复制到A
                    MergePass(b, a, s, n, comparer);
                    s += s;
                }
            }
            private void MergePass(T[] a, T[] b, int s, int n,IComparer<T> comparer)
            {
                int i = 0;
                while (i + 2 * s < n)
                {
                    // i 为当前位置,加上2倍的段长就是后一组(2段)的开始下标了
                    //当前位置下标加上段长是下一段第一个元素的下标(i+s),
                    //故第一段
                    Merge(a, b, i, i + s - 1, i + 2 * s - 1,comparer);
                    i += 2 * s;

                }
                //剩余的元素,不足两个分段长度,但大于或等于一个段长度[s,2s-1]
                if (i + s < n)
                {
                    Merge(a, b, i, i + s - 1, n - 1, comparer);
                }
                else //剩余元素小于一个段长度,有可能为零个[0,s-1]
                {
                     //这里也有可能是用来把b中的全部元素复制回a,
                     //这时候i是0,参考MSort
                    while (i < n) 
                   {
                        b[i] = a[i++];
                    }
                }
        
            }
        }


     

     参考
    数据结构-排序: 两路归并排序算法

    http://haoxiai.net/bianchengyuyan/cyuyan/11929.html

  • 相关阅读:
    数据库的数据同步
    IDEA连接数据库自动生成实体类
    异常日记(一)
    高16位,低16位是什么
    springboot整合rabbitmq
    springBoot使用教程
    分布式框架Dubbo入门
    Spring注解驱动开发04(给容器中注册组件的方式)
    Spring注解驱动开发03(按照条件注册bean)
    Spring注解驱动开发02(作用域和懒加载)
  • 原文地址:https://www.cnblogs.com/wdfrog/p/1368890.html
Copyright © 2011-2022 走看看