合并排序——二路合并排序

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了合并排序——二路合并排序相关的知识,希望对你有一定的参考价值。

  • 什么是合并排序

合并排序就是将两个或多个有序表合并成一个有序表,将两个有序表合并成一个有序表称为二路合并

  • 算法描述 :

二路合并排序的基本思想是:对于两个有序表合并,初始时, 把含有n个结点的待排序序列看作有n个长度为1的有序子表所组成,将它们依次两两合并,得到长度为2的若干有序子表,再对这些子表进行两两合并,一直重复到长度为n,排序完成。

  • 合并排序过程:

初始序列:

技术分享图片

 

二路合并排序需要较大的辅助空间,辅助空间的大小与待排序序列一样多。

(1)将14个原数据看成14个长度为1的有序表(只有一个数据,肯定是有序的)

(2)将14个有序表两两合并,即将1,2合并3,4合并.....如果后面有单独一个元素的,就单独放在那里,直接进入下一遍合并

技术分享图片

(3)经过第一遍的合并,得到长度为2的有序表序列,再将这些长度为2的有序表序列进行两两合并。

技术分享图片

(4)经过第二遍合并之后,得到长度为4的有序表的序列,再将这些长度为4的有序表进行两两合并。

技术分享图片

(5)  经过上面的合并,得到长度为8的有序表,再将这些长度为8的有序表进行两两合并。

 

技术分享图片

 

  • 合并相邻有序表 :

如果需合并的两个有序表分别保存于数组A中,其中一个序列保存在下标s~m的数组元素中,另一个序列保存在下标从m+1~n的数组元素中。合并把结果保存在数组R中。用变量i,j分别指向两个系列中需要比较的元素,变量k指向数组R中的序号,表示下一个要保存的数据的位置。

(1)  取第1个系列的第i个元素A[i],与第2个系列的第1个元素比较A[j]。

(2)  若A[i]<=A[j],则将A[i]复制到R[k]中,使i和k分别增加1.

(3)若A[i]>A[j],则将A[j]复制到R[k]中,使j和k分别增加1

(4)重复步骤1~3,直到一个序列复制完为止。

(5)将另一个序列中比较的数据复制到R的剩余位置。

//a[low...mid]a[mid+1,high]  b[low...high]

   void Merge(int a[],int b[],int low,int mid,int high){

      int i=low;

      int j=mid+1;

      int k=low;

     

      while(i<=mid && j<=high){

         if(a[i]<=a[j]){

            b[k++]=a[i++];

         }else{

            b[k++]=a[j++];

         }

      } private static void merge(int a[],int temp[],int low,int mid,int high){

   int i=low;

   int j=mid+1;

   int k=0;

  

   while(i<=mid && j<=high) {

      if(a[i]<=a[j]) {

         temp[k++]=a[i++];

      }else {

         temp[k++]=a[j++];

      }

   }

   while(i<=mid) {

      temp[k++]=a[i++];

   }

   while(j<=high) {

      temp[k++]=a[j++];

   }

   k = 0;

   // temp中的元素全部拷贝到原数组中

   while (low <= high) {

      a[low++] = temp[k++];

   }

}

 

  • 归并排序:

(1)  二路归并排序将a[low...high]中的记录归并排序后放入temp[low...high]中。当序列长度等于1时,递归结束,否则:

a)     将当前序列一分为二,求出分裂点mid=(low+high)/2

b)    对子序列a[low..mid]递归,进行归并排序,结果放入temp[low...mid]

c)     对子序列a[mid+1,high],进行归并排序,结果放入temp[mid+1,high]

d)    调用Merge将有序的两个子序列a[low..mid]与a[mid+1,high]归并为一个有序的序列temp[low...high]

/**

 * sort

 */

public static void sort(int a[],int temp[],int low,int high) {

   if(low<high) {

       int mid=(low+high)/2;

       sort(a,temp,low,mid);

       sort(a,temp,mid+1,high);

       merge(a,temp,low,mid,high);

   }

}

  • 算法实例:

public class MergeSort {

   /**

    * 相邻有序子序列进行合并

    *   a[low...mid] a[mid+1,high]

    */

   private static void merge(int a[],int temp[],int low,int mid,int high){

      int i=low;

      int j=mid+1;

      int k=0;

     

      while(i<=mid && j<=high) {

         if(a[i]<=a[j]) {

            temp[k++]=a[i++];

         }else {

            temp[k++]=a[j++];

         }

      }

      while(i<=mid) {

         temp[k++]=a[i++];

      }

      while(j<=high) {

         temp[k++]=a[j++];

      }

      k = 0;

      // temp中的元素全部拷贝到原数组中

      while (low <= high) {

         a[low++] = temp[k++];

      }

   }

  

   public static void sort(int a[],int temp[],int low,int high) {

      if(low<high) {

          int mid=(low+high)/2;

          sort(a,temp,low,mid);

          sort(a,temp,mid+1,high);

          merge(a,temp,low,mid,high);

      }

   }

   public static void sort(int []arr){

        int []temp = new int[arr.length];//在排序前,先建好一个长度等于原数组长度的临时数组,避免递归中频繁开辟空间

        sort(arr,temp,0,arr.length-1);

    }

   public static void main(String[] args) {

      int arr[]= {56,41,26,32,55,75,2,63,12,19,58,77,34,95};

      sort(arr);

      System.out.println("排序结果:"+Arrays.toString(arr));

     

      /*

      测试,合并有序子序列

      int arr[]= {1,3,5,2,4,6};

      int temp[]=new int[arr.length];

      merge(arr, temp, 0, 2,   arr.length-1);

     

      System.out.println("排序结果:"+Arrays.toString(arr));

      System.out.println("排序结果:"+Arrays.toString(temp));

      */

   }

}



以上是关于合并排序——二路合并排序的主要内容,如果未能解决你的问题,请参考以下文章

归并排序法和基数排序法

合并K个排序链表

简述二路归并排序,并分析其算法复杂性.

Java排序之归并排序

AcWing34:合并两个排序的链表

AcWing34:合并两个排序的链表