归并排序

来源:互联网 发布:linux安装rpm文件 编辑:程序博客网 时间:2024/06/07 05:18

逆序数:序列中逆序对的个数。

例如:9 1 0 5 4

由于要把它排列为上升序列,上升序列的有序就是后面的元素比前面的元素大,而对于序列9 1 0 5 4

9后面却有4个比9小的元素,因此9的逆序数为4

1后面只有1个比1小的元素0,因此1的逆序数为1

0后面不存在比他小的元素,因此0的逆序数为0

5后面存在1个比他小的元素4, 因此5的逆序数为1

4是序列的最后元素,逆序数为0

因此序列9 1 0 5 4的逆序数 t=4+1+0+1+0 = 6。


/*

归并排序是用分治思想,分治模式在每一层递归上有三个步骤:

分解:将n个元素分成个含n/2个元素的子序列。

解决:用合并排序法对两个子序列递归的排序。

合并:合并两个已排序的子序列已得到排序结果。

*/


将数组A[1...size],划分为A[1...mid] 和 A[mid+1...size].

那么逆序对数的个数为 f(1, size) = f(1, mid) + f(mid+1, size) + s(1, mid, size),这里s(1, mid, size)代表左值在[1---mid]中,右值在[mid+1, size]中的逆序对数。由于两个子序列本身都已经排序,所以查找起来非常方便。

void Merge(int Left,int Middle,int Right)
{
         int n1=Middle-Left+1;
         int n2=Right-Middle;
         for(int i=1;i<=n1;i++)
                L[i]=A[Left+i-1];             
         for(int i=1;i<=n2;i++)
                R[i]=A[Middle+i];
         L[n1+1]=M;           // M是比较大的数。
         R[n2+1]=M;
         int i=1;int j=1;
         for(int k=Left;k<=Right;k++)
         {
                 if(L[i]<=R[j])
                           A[k]=L[i++];     
                 else
                 {
                           A[k]=R[j++];
                           cunt+=n1-i+1;       //cunt为全局变量。最后cunt即为逆序对的个数。
                 }
         }

}                                     

递归的合并排序,如果子数组中至多有一个元素,当然是已排好,否则分解。

void Merge_sort(int Left,int Right)
{
          int Middle;
          if(Left<Right)
          {
                      Middle=(Left+Right)/2; 
                      Merge_sort(Left,Middle);             // 二分分解左部分
                      Merge_sort(Middle+1,Right);          // 二分分解有部分
                      Merge(Left,Middle,Right);            //合并两部分
          }
  
}


  
设数组为A,关键是在合并的时候,用数组L 和 R 表示左右两个子数组,因为逆序对的个数f(A) = f(L) + f(R) + s(L,R);

其中f(L) 和 f(R) 分别表示L 内部 和R内部的逆序对个数,s(L.R)表示大数在L,小数在R的逆序对。

因为L和R是已经排好序的,故其实只需求s(L,R).这个可以在合并L和R依次进行比较的时候算出。


for(k = p;k <= r;k ++)
{
          if(L[i]<=R[j]) 
                  a[k] = L[i++];
          else           
//如果L最上面的数大于R的,那么L[i]及后面的数可以和R[j]构成n1-i+1个逆序对
          {        
                  a[k] = R[j++];
                  count +=(n1 -i + 1);        //累加
          }
}

归并排序的代码:

void merge(int p,int q,int r){
          int n1 = q-p+1,n2 = r-q;
          int i,j,k;
          for(i = 1;i <= n1; i++)
                   L[i] = a[p+i-1];
          for(j = 1;j <= n2; j++)
                   R[j] = a[q+j];
          L[n1+1] = INF;
          R[n2+1] = INF;
          i = 1;j = 1;
          for(k = p;k <= r;k ++){
                   if(L[i]<=R[j])
                             a[k] = L[i++];
                   else{
                             a[k] = R[j++];
                             count +=(n1 -i + 1);
                   }
          }
}
void merge_sort(int p,int r){
          if(p<r){
                   int q = (p+r)/2;
                   merge_sort(p,q);
                   merge_sort(q+1,r);
                   merge(p,q,r);
          }
}


0 0