归并排序

CLRS: 将原问题分解为几个规模较小但类似于原问题的子问题,递归地求解这些子问题,然后再合并这些子问题的解来建立原问题的解。

归并排序利用了分治法的思想,对数组元素进行切分,递归地排序左右部分数组,然后再将两部分进行合并,最终达到排序的目的。此算法的时间复杂度是O(nlgn)。

此算法的大体思路为:

  • 将待排序的数组划分为左右两个部分,分别递归地进行归并排序
  • 当划分到只有一个元素时,返回
  • 对划分的两个部分进行合并,即分别从已排序的两个部分中依次取最小值,放入原数组

有可能某个部分的值先被放入原数组,因此需要判断,当某个部分被取完时,另一个部分直接将剩下的元素放入原数组。但是如果每次循环都判断是否有部分被取完,会影响效率。因此可在两个部分的末尾添加哨兵元素,用于标记,阻绝再从此部分中取走元素。
具体做法:
复制左右两部分的元素到L[]和R[]中,L和R的长度需要至少比左右部分的元素长度大1。然后再将有效值后一个元素设置为哨兵值,如10000,保证此数大于待排序的所有数。即假如左部分中有已排序元素1 2 3,则L长度至少为4,元素值分别为1 2 3 10000。当某一个部分元素取完时,即L中有效的原始取完时,此时L中元素再与R中进行比较,则必然有10000>R[j],因此会选取R中有效元素放入原数组。最后当L和R中所有有效元素都取完时,循环停止,L和R中的10000不会进入到原数组,而破坏数据。

实现如下:

#include<iostream>
using namespace std;

//对由mid切分的左右块(low~mid和mid+1~high)进行合并
void merge(int* arr,int low,int mid,int high){
  int m=mid-low+1;  //左边块长度
  int n=high-mid;  //右边块长度

  //左边块的容器。因为C++需要在编译时知道数组长度,因此不能L[m],故设置为100。可根据需要自行设定
  int L[100]={0};
  int R[100]={0};  //右边块的容器
  for(int i=0;i<m;i++)
    L[i]=arr[low+i];  //复制左边块
  for(int j=0;j<n;j++)
    R[j]=arr[mid+j+1];  //复制右边块
  L[m]=10000;  //哨兵,避免每次循环都判断是否L或R已空
  R[n]=10000;
  int i=0;  //左边块的索引
  int j=0;  //右边块的索引

  //对左右块的“首”元素循环判断,并将小的值添加到目的数组arr中
  for(int k=low;k<=high;k++){
    if(L[i]<=R[j]){
      arr[k]=L[i];
      i++;  //添加的是左边块的“首”元素,需要索引i+1,以指向左边块下一个元素
    }
    else{
      arr[k]=R[j];
      j++;  //同上
    }
  }
}

//归并排序,将数组中下标从low到high(包括)的元素进行排序
void merge_sort(int* arr,int low,int high){
  if(low<high){  //当元素至少还有两个时,进行递归归并排序
    int mid=(low+high)/2;  //获取中间索引
    merge_sort(arr,low,mid);  //递归排序左部分
    merge_sort(arr,mid+1,high);  //递归排序右部分
    merge(arr,low,mid,high);  //合并两个部分
  }
  //low==high,则只有一个元素,不进行排序,直接返回
  //low>high,错误
}

int main(){
  int arr[10]={5,4,3,2,1,8,7,6,5,4};
  merge_sort(arr,0,9);
  for(int i=0;i<10;i++)
    cout<<arr[i]<<" ";
  cout<<endl;
  return 0;
}

RESULT:
1 2 3 4 4 5 5 6 7 8
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值