归并排序 hdu 3743

归并排序

百科名片

归并(Merge)排序法是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,每个子序列是有序的。然后再把有序子序列合并为整体有序序列。

  归并排序
  归并排序是建立在归并操作上的一种有效的 排序 算法。该算法是采用 分治法 (Divide and Conquer)的一个非常典型的应用。
  将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为2-路归并。

编辑本段归并操作

  归并操作(merge),也叫归并算法,指的是将两个已经排序的序列合并成一个序列的操作。
  如 设有数列{6,202,100,301,38,8,1}
  初始状态: [6] [202] [100] [301] [38] [8] [1] 比较次数
  i=1 [6 202 ] [ 100 301] [ 8 38] [ 1 ] 3
  i=2 [ 6 100 202 301 ] [ 1 8 38 ] 4
  i=3 [ 1 6 8 38 100 202 301 ] 4
  总计: 11次

编辑本段算法描述

  归并操作的工作原理如下:
  申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
  设定两个指针,最初位置分别为两个已经排序序列的起始位置
  比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
  重复步骤3直到某一指针达到序列尾
  将另一序列剩下的所有元素直接复制到合并序列尾


与快速排序的比较

  归并排序是稳定的排序.即相等的元素的顺序不会改变.如输入记录 1(1) 3(2) 2(3) 2(4) 5(5) (括号中是记录的关键字)时输出的 1(1) 2(3) 2(4) 3(2) 5(5) 中的2 和 2 是按输入的顺序.这对要排序数据包含多个信息而要按其中的某一个信息排序,要求其它信息尽量按输入的顺序排列时很重要.这也是它比 快速排序 优势的地方.

用途

1、排序

  (速度仅次于快速排序,但较稳定)

2、求逆序对数

  具体思路是,在归并的过程中计算每个小区间的逆序对数,进而计算出大区间的逆序对数(也可以用树状数组来求解)

ht示例代码

  归并排序
  归并排序具体工作原理如下(假设序列共有n个元素):
  将序列每相邻两个数字进行归并操作(merge),形成floor(n/2)个序列,排序后每个序列包含两个元素
  将上述序列再次归并,形成floor(n/4)个序列,每个序列包含四个元素
  重复步骤2,直到所有元素排序完毕

归并模板(+ 算逆序数对数)
逆序对,就是诸如 i<j 且 a[i]>a[j] 这样的数对 (i,j)
#include <iostream>
using namespace std;

const int size = 1000;

int invers=0;//求逆序数
int tmpArr[size];//额外空间,用来暂存 

void Copy(int a[], int b[], int low, int high) 
{
     for (int i = low; i <= high; ++i) a[i] = b[i]; 
}

void Merge(int a[], int b[], int low, int high)
{
     int mid = (low + high)/2;
     int i, j, k;//i指向[low,mid],j指向[mid+1,high]中的元素 
     for (i = low, j = mid+1, k = low; i <= mid && j <= high; k++)
     {
         if (a[i] < a[j]) b[k] = a[i++];//[low,mid]段中的第i个元素a[i]小于 [mid+1,high]段中的a[j],他应该放在前面,所以放入b[]中 
         else 
         {             
             //前面的数大于后面的数,有逆序数
             //invers +=  ??
             if (a[i] > a[j])
                invers += mid-i+1; //a[i] > a[j], 则a中[i,mid]部分都会大于a[j] 
             b[k] = a[j++];//只有放入了b[]后,i或j才++ 
         }         
     }
     while (i <= mid) b[k++] = a[i++];
     while (j <= high) b[k++] = a[j++];
     Copy(a, b, low, high);//将排好序的元素从b中复制给a 
}

void MergeSort(int a[], int low, int high)
{
     if (low >= high) return ;//递归出口,当区间左值大于等于右值,就不用排序了 
     int mid = (low + high)/2;//将区间[low,high]分成[low,mid],[mid+1, high]两段分别排序 
     MergeSort(a, low, mid); //或者分为[low,mid-1]和[mid,high],本程序采用前者 
     MergeSort(a, mid+1, high); 
     Merge(a, tmpArr, low, high);//将排好序的 [low,mid],[mid+1, high]两段合并 
    // Copy(a, tmpArr, low, high);//
}

int main()
{
    int arr[size], N, i;    
        
    while (cin>>N)
    {
          invers = 0;
          for (i = 0; i < N; ++i)
              cin >> arr[i];
          MergeSort(arr,0,N-1); 
          for (i = 0; i < N-1; ++i)
              cout << arr[i] << " ";
          cout << arr[i] << endl;
          cout << "inverse number is " << invers << endl; 
    }    
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值