二路归并排序及其改进方法

本文探讨了二路归并排序的算法原理,包括如何进行序列的归并和排序过程。同时,提出了一个改进方法,首先扫描原始序列,将其划分为多个有序子序列,如(1,3,4),(2,5,8),(7),然后对这些子序列分别进行归并排序。关键在于使用队列来存储子序列的起始元素,确保排序的顺序性。整个算法基于不带头节点的单链表实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

二路归并排序的算法
归并:

void merge(elemtype a[],int low,int mid, int high){
//mid将a分成左右low-mid,mid+1-high两部分
 int i,j,k;
 elemtype b[high-low+1];//辅助数组b的长度为high-low+1
 for(i=low;i=high;i+) b[i]=a[i];//复制a到b
 i=low;j=mid+1;k=low;
 while(i<=mid&&j<=high){
  if(b[i]<=b[j])
   a[k++]=b[i++];
  else a[k++]=b[j++];
 }
 while(i<=mid) a[k++]=b[i++];
 while(j<=high) a[k++]=b[j++];
}

排序

void mergesort(elemtype a[],int low,int high){
 if(low<high){
  int mid=(low+high)/2;
  mergesort(a,low,mid);
  mergesort(a,mid+1,high);
  merge(a,low,mid,high);
 }
}
 //注意:该算法是递归算法,第一趟归并不一定是两两归并,有可能会出现头两个归并后再和第三个归并。 

改进:先对原始序列扫描一次,并把序列划分成各个有序子序列,
如1,3,4,2,5,8,7划分成(1,3,4),(2,5,8),(7)。再对各个子序列归并排序。
如何划分?划分就是要记下每个子序列的首尾,为了能够按顺序记录,我们用队列存储各子序列的头元素。
本算法用不带头节点的单链表结构。

void merge(linklist la,linklist lb,linklist &lc){ 
 lnode *pa,*pb,*pc;
 if(la&&lb){//选lc的第一个元素
  if(la->data<=lb->data){
   lc=la;pa=la->next;pb=lb;
  }
  else{
   lc=lb;pa=la;pb=lb->next;
  }
 }//因为是不带头节点的,所以第一个元素应该特殊处理
 pc=lc;
 while(pa&&pb){//选la与lb的较小者,并用lc把这些较小节点的指针域连接起来
  if(pa->data<=pb->data){
   pc->next=pa;pc=pa;pa=pa->next;
  }
  else{
   pc->next=pb;pc=pb;pb=pb->next;
  }
 }
 //直接把剩余部分的指针连接到lc的尾部
 if(pa) pc->next=pa;
 if(pb) pc->next=pb;
}

void mergesort(linklist &r){
//先划分
 initqueue(Q);
 lnode *s,*t;
 s=r;
 enqueue(Q,s);//第一个元素入队
 while(s->data<=s->next->data) s=s->next;
 if(s){
  t=s->next;//防止断链
  enqueue(Q,t);//将有序子序列的头元素入队
  s->next=null;
 }
//排序
 while(!empty(Q)){
  dequeue(Q,t);
  if(empty(Q)) break;//单个子序列无法归并,退出
  dequeue(Q,s);
  merge(t,s,r);
  enqueue(Q,r);//归并后把新的子序列的首节点入队
 }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值