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

来源:互联网 发布:曲面电视优缺点知乎 编辑:程序博客网 时间:2024/06/11 01:22

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

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);//归并后把新的子序列的首节点入队 }}