高等排序之归并排序

为什么会有如此多的排序方法呢,我们常使用的有冒泡、选择、快速排序,希尔排序等等。这是因为每一种排序方法有其特定的使用范围,尤其是对时间和空间复杂度要求高的算法中,很显然像冒泡这类的高复杂度的算法就无法胜任。对付此类问题则需要使用到高等排序方法。而归并排序就是其中之一。
归并排序理解其实也非常简单,就是将数组分割为包含n/2个元素局部数组,对每个数组继续执行归并排序。并通过Merge(合并)将两个已排序完毕的数组“整合”到一个数组。

在该算法中,最重要的就是合并两个已经排好序的数组,它是整个算法的基础。我们要将包含n1个元素的数组L和包含n2个元素的数组R合并到A中。若假设数组L和R都已按升序排好,我们要做的就是将L和R中的元素赋值到A中,并同时保证A中的元素升序排列。

通常,为了简化合并(merge)的实现,我们在L和R的末尾分别插入一个大于所有元素的标记。在比较L和R的过程中,势必会遇到与标记相比较的情况,只要将标记设的足够大,且比较次数限制在(n2+n1)之内,就可以防止两个标记做比较,又可防止i、j分别超过n1、n2。
下面给出该归并排序的伪代码:

merge(A,left,mid,right)
    n1=mid-left
    n2=right-mid
    生成L[0...n1],R[0...n2]
    for i=0 to n1-1
      L[i]=A[left+i]
    for i=0 to n2-1
      R[i]=A[mid+i]
    L[n1]=INFTY
    L[n2]=INFTY
    i=0
    j=0
    for k=left to right-1
      if L[i]<=R[i]
        A[k]=L[i]
        i=i+1
      else
        A[k]=R[j]
        j=j+1
        
     //局部数组只剩一个元素时,不做处理直接结束,否则计算局部数组中间位置mid,
     //将left到mid视为前半部分,mid 到right视为后半部分。再进行MergeSort(分割)
    mergeSort(A,left,right)            //分割数组
      if left+1 < right
        mid=(left+right)/2;
        mergeSort(A,left,mid)
        mergeSort(A,mid,right)
        mergeSort(A,left,mid,right)
        
//mergeSort的三个参数分为为数组A以及表示其局部数组范围的变量left,right。left指局部数组的
//开头,right指局部数组末尾+1的位置。

一般来说,归并排序n个数据会分为log2n层。由于每层执行merge的总复杂为O(n),因此归并排序的整体复杂度为O(nlogn)。
此外,归并排序包含不相邻元素之间的比较,但并不会直接交换。在合并数组时,若遇到相同元素,只需保证前半部分数组由于后半部分数组,相同元素的顺序就不会改变。因此,其是一种稳定的排序算法。但在处理过程中,除用于保存输入数据的数组之外,还需要临时占用一部分内存空间.

下面完整代码是归并排序的例子:

#include <iostream>
using namespace std;
#define MAX 500000
#define SENTINEL 2000000000

int L[MAX/2+2],R[MAX/2+2];
int cnt;
void merge(int A[],int n,int left,int mid,int right){
  int n1=mid-left;
  int n2=right-mid;
  for(int i=0;i<n1;i++) L[i]=A[left+i];
  for(int i=0;i<n2;i++) R[i]=A[mid+i];
  L[n1]=R[n2]=SENTINEL;
  int i=0,j=0;
  for(int k=left;k<right;k++){
    cnt++;
    if(L[i]<=R[j]){
      A[k]=L[i++];
    }
    else{
      A[k]=R[j++];
    }
  }
}
void mergeSort(int A[],int n,int left,int right){
  if(left+1<right){
    int mid=(left+right)/2;
    mergeSort(A,n,left,mid);
    mergeSort(A,n,mid,right);
    merge(A,n,left,mid,right);
  }
}
int main(){
  int A[MAX],n;
  cnt=0;
  cin>>n;
  for(int i=0;i<n;i++) cin>>A[i];
  mergeSort(A,n,0,n);
  for(int i=0;i<n;i++){
    if(i)std::cout << " ";
    cout<<A[i];
  }
  cout<<endl;
  cout<<cnt<<endl;
  return 0;
}

到此,归并排序内容基本介绍完毕。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一倾而尽

你的鼓励将是我最大的动力,谢谢

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值