归并排序

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

       算法思想(升序排列):

         设对于无序序列含n个元素的无序序列array,共需lg(n)+1趟归并。

         第1趟归并后n个元素产生n/2个文件(即n/2次归并),每个文件含有2个元素;第2趟归并后你n/2个文件产生n/4个文件,每个文件含有4个元素;……

         每一趟归并时对相邻的两个文件进行比较,将文件中较小元素存入额外申请的序列,并对该文件做自减操作,直到某个文件中元素为0个,最后将含有剩余元素的文件整体插入到额外序列的末尾。

        每一趟归并中使用三指针:left指向某个文件的第一个元素,mid只向该文件的最后一个元素(即两个文件的中间元素),right只向该文件后面文件的最后一个元素。

         最后一趟归并后只剩余一个文件,共含n个元素。

        需要注意的是, 对于每一趟归并:

         1、如果所含的文件个数为奇数,则漏过最后一个文件,不对其归并

         2、如果所含的文件个数为偶数,则该趟归并的最后两个文件中的right指针要只向n,即最后一个元素(在程序处理时可在循环中先漏过最后两个文件,在循环之外单独处理)       

程序(C++): 

#include <iostream>
#include <string>
using namespace std;
void merge_sort(int v[],int left,int right,int mid){
  int *arr=new int[right-left+1];
  int i=left,j=mid+1;
  int k=0;
  while(i<=mid&&j<=right){
       if(v[i]<v[j]){  arr[k]=v[i];i++; }
       else{  arr[k]=v[j];j++; }
        k++;
  }
  while(i<=mid){
      arr[k]=v[i];i++;k++;
  }
  while(j<=right){
      arr[k]=v[j];j++;k++;
  }
  k=0;
  for(i=left;i<=right;i++){
     v[i]=arr[k];k++;
  }
  delete []arr;
}
void merge(int v[],int n){
 int files=n,i=1,left,right,mid,every=1;
 while(files>1){                         //如果文件数大于1,继续归并
    if(files%2!=0){                     //如果文件数为奇数,只比较前files-1个文件,
        left=0;right=2*every-1;mid=(left+right)/2;
        for(int j=0;j<(files-1)/2;j++){                 //前files-1个文件共需比较(files-1)/2次
            merge_sort(v,left,right,mid);
            left=left+2*every;right=right+2*every;mid=(left+right)/2;
        }
     }else{                     //如果文件数为偶数,共需比较files/2次
             left=0;right=2*every-1;mid=(left+right)/2;
             for(int j=0;j<(files/2)-1;j++){
                    merge_sort(v,left,right,mid);
                    left=left+2*every;right=right+2*every;mid=(left+right)/2;
             }

            //进行该趟最后两个文件的比较
             right=n-1;
             mid=(files-1)*every-1;
             left=mid-every+1;
             merge_sort(v,left,right,mid);
     }
    files=files/2+files%2; //计算每趟归并后产生的文件数

    every=2*every;       //计算每个文件中含有元素的个数
 }
}
int main(){

  Int a[10]={9,8,7,6,5,4,3,2,1,0};

  merge(a,10);

  for(int i=0;i<n;i++)

    cout<<a[i]<<' ';
  return 0;
}
 


 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值