so true

心怀未来,开创未来!
随笔 - 160, 文章 - 0, 评论 - 40, 引用 - 0
数据加载中……

一个较为复杂的二路归并算法

/*

作者:bacoo
日期:2008年9月21日

一个比较复杂的二路归并排序算法,完成由小到大的排序功能

算法摒除了最初始的“从两路头部依次取出数据,经过比较后输出较小值”方法;

而是找出“头大”的一路,然后把另一路分成许多片断,然后插入到“头大”的那路中,

这里面寻找插入点使用了二分法查找以提高效率,

需要说明的是,该算法在两部“交错”不是很严重的情况下有较好的效率。

*/

#include <iostream>
using namespace std;

int find2fenfa(int a[],int h,int t,int num){//利用二分法来查找num的位置,要求在[h,t]之间
 while(h<t){
  int m=(h+t)/2;
  if(num==a[m]){
   return m;
  }
  else if(num<a[m])
   t=m-1;
  else
   h=m+1;
 }
 return h;//这只给出一个推荐位置,也即最相关位置,在后续应用该结果时,需要做分析处理
}

void movedata(int a[],int pos,int h,int t){//该函数用于将[h,t]区间内的数据移动到pos指定的插入位置
 int s;
 if(pos>t){//插入点在后方
  for(int i=t;i>=h;i--){
   s=a[i];
   for(int j=i;j<pos-1;j++){
    a[j]=a[j+1];
   }
   a[--pos]=s;
  }
 }
 else if(pos<h){//插入点在前方
  for(int i=h;i<=t;i++){
   s=a[i];
   for(int j=i;j>pos;j--){
    a[j]=a[j-1];
   }
   a[pos++]=s;
  }
 }
}

void merge2(int a[],int h1,int t1,int h2,int t2)//该函数用于两路合并,h和t分别表示头部和尾部
{
 if( h1>t1 || h2>t2 )return;
 int i_pos=-1,s_end=-1;
 if(a[h1]<=a[h2]){//确保都是为一个大数查找插入的位置
  i_pos=find2fenfa(a,h1,t1,a[h2]);
  a[i_pos]<=a[h2] ? i_pos++ : i_pos;//根据推荐位置对应的数值大小来调整合适的插入点
  if(i_pos>t1)return;//已经有序,不必再合并了
  s_end=find2fenfa(a,h2,t2,a[i_pos]);//为待插入的部分找到一个终点,起始点已经由h2来标记了
  a[s_end]>=a[i_pos] ? s_end-- : s_end;//微调,很必要的
  movedata(a,i_pos,h2,s_end);
  merge2(a,i_pos+s_end-h2,s_end,s_end+1,t2);
 }else{
  i_pos=find2fenfa(a,h2,t2,a[h1]);
  a[i_pos]<=a[h1] ? i_pos++ : i_pos;
  if(i_pos>t2){
   movedata(a,h1,h2,t2);
   return;
  }
  s_end=find2fenfa(a,h1,t1,a[i_pos]);
  a[s_end]>=a[i_pos] ? s_end-- : s_end;
  movedata(a,i_pos,h1,s_end);
  merge2(a,h1,t1-(s_end-h1+1),t1-s_end+h1,t2);
 }
}

void sort_2way(int a[],int len){//两路归并,这个函数主要是为merge2函数每次分配合适的两路
 int x=1;//表示当前进行的两路归并中的“路的长度”
 int h1,t1,h2,t2;
 while(x<=len){
  for(int i=0;i<len;i+=2*x){
   h1=i;
   h2=i+x;
   t1=h2-1;
   t2=h2+x-1;
   if(h2>=len)continue;
   else{
    if(t2>=len){
     merge2(a,h1,t1,h2,len-1);
     break;
    }else
     merge2(a,h1,t1,h2,t2);
   }
  }
  x*=2;
 }
}

void main(){
 int a[10];
 int len=sizeof(a)/sizeof(a[0]);
 for(int i=0;i<len;i++)a[i]=rand()%100;

 sort_2way(a,len);
 
 for(i=0;i<len;i++)cout<<a[i]<<endl;
 
}

 

单次运行结果为:

0
24
34
41
58
62
64
67
69
78
Press any key to continue

posted on 2008-09-21 01:21 so true 阅读(492) 评论(2)  编辑  收藏 所属分类: C&C++

评论

# re: 一个较为复杂的二路归并算法  回复  更多评论   

首先声明一下:我是本文的作者。
写完这个代码之后,到网上检索了一下二路归并算法的实现,大多数都是最原始的那种做法,而其还需要辅助数组,其实我觉得也可以完全不用辅助数组,不过这就是空间与时间的矛盾之处,因为不用辅助数组的话需要大量的移动数据,造成时间复杂度的提高。

后来我回顾了一下我给出的算法,虽然编写调试了很长时间才最终成功,但是依然很欣慰,好似还没有其他人这么做,难道我有如此聪明?不至于吧,呵呵,反正窃喜一下,凌晨2点,睡觉去^_^
………………
2008-09-21 02:03 | bacoo

# re: 一个较为复杂的二路归并算法  回复  更多评论   

好聪明的作者!长见识了!
请问在哪高就啊?
2008-10-04 19:51 | yball

只有注册用户登录后才能发表评论。


网站导航: