多路归并

原文地址:点击打开链接

堆实现:采用一个和路数相等长度的数组模拟堆,每次都进行入堆和出堆操作。在堆中每个元素代表一路数据,其中保存有此数组已经访问到哪里的下标,每次在进行出堆操作,取出极值元素之后,我们更新相应的下标,之后再讲此元素入堆。


#include  <stdio.h>
 #include <stdlib.h>
 #define N   150
 typedef  struct  data1
 {
         int  data;
         //int  pos; //没用
 }data;

typedef  struct  wrap_data
 {
   int  offset;
   data  *p;
 }wrap_data;

wrap_data * min_heap[N]={0};
 int count=1;
 int left(int i)
 {
         return  2*i;
 }
 int right(int i)
 {
         return  2*i+1;
 }


 void insert(wrap_data  *point_a)
 {
         wrap_data * temp;
         //int  pos_temp;
         int p, num;

        min_heap[count]=point_a;
         num=count;
         while(num/2)
         {
                 p=num/2;  
                 if((min_heap[num]->p+min_heap[num]->offset)->data<(min_heap[p]->p+min_heap[p]->offset)->data)
                 {
                         temp=min_heap[num];min_heap[num]=min_heap[p];min_heap[p]=temp;

                }
                 else
                 {
                         break;
                 }
                 num=p;
         }
         count++;
         if(count>N)count=N;
 }


 wrap_data * pop()
 {
         wrap_data * temp,*result=min_heap[1];
         int exchange;
         int  label=1;
         min_heap[label]=min_heap[count-1];
         while(left(label)<=count-1)
         {
                 if(right(label)<=count-1)
                 {
                   if((min_heap [left (label)]->p+min_heap[left(label)]->offset)  ->data <
                      (min_heap [right (label)]->p+ min_heap[ right(label)]->offset)->data )
                                 exchange=left (label) ;
                         else
                                 exchange= right (label);    
                 }
                 else
                         exchange=left (label) ;

                if((min_heap[exchange]->p+ min_heap[exchange]->offset)->data<
                    (min_heap[label]->p+ min_heap[label]->offset)->data)
                 {
                         temp=min_heap[exchange];min_heap[exchange]=min_heap[label];min_heap[label]=temp;
                 }
                 else
                         break;
                 label=exchange;
         } 
         count--; 
         return  result;
 }
 int  empty()
 {
         return  !(count-1);
 }

void  main()
 {
 #define  PATH  5
 #define  LENGTH  10

        wrap_data *result;
         int i=0,j=0;
         wrap_data a[PATH]={0};

        for(i=0;i<PATH;i++)
         {

          a[i].p=(data*) calloc (LENGTH , sizeof (data ));
                 a[i].offset=0;
                 for(j=0;j<LENGTH;j++)
                  {
  
                     (a[i].p+j)->data=(i*i+j)%40;

                  }
                 insert(&a[i]);
         }

        for(i=0;i<PATH;i++)
           {
             for(j=0;j<LENGTH;j++)
               {
                 printf("%d  ", (a[i].p+j)->data);
               }
             printf("\n");
           }

        while(!empty())
         {
                 result=pop();
                 printf("%d  ",(result->p+result->offset)->data);
                 result->offset++;
                 if ( result ->offset>=LENGTH)
                   {
                   }
                 else
                   {
                     insert(result);
                   } 

                //              printf("%d \n",result->data);
         }

}

败者树实现

败者树使用类似堆的数据结构,只不过只有一半是存着数组,其余的都是保存的比较结果。如图(这个是胜者树的图)只有底下三个存着有效数组元素,其余的是比较的结果,加快操作的。每次我们修改的仅仅是树中指向数组的下标。当下标变了以后,因为up函数用到了这个下标,所以会导致再次调用时数组的更改。也就是每次都是从最下面变了的元素往上面更改。因为只有变了的元素会影响到结果。所以从这条路径往上走,就可以了。这个up函数每次返回的都是修改后的树顶元素。

1. 这个程序目前只考虑到是完全二叉树的叶子节点的情况。

2.每个有序序列的末尾都加上了一个MAX_BIG来表示最终的结束,这样做是为了简化程序设计,不然当一个序列的最后一个元素被合并到目的序列时候,不知道该往败者树里面加什么。

0  1  2  3  4  5  6  7  8  999999999  
 1  2  3  4  5  6  7  8  9  999999999  
 4  5  6  7  8  9  10  11  12  999999999  
 9  10  11  12  13  14  15  16  17  999999999  
  0   1   1   2   2   3   3   4   4   4   5   5   5   6   6   6   7   7   7   8   8   8   9   9   9   10   10   11   11   12   12   13   14   15   16   17  

 

¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥

#include  <stdio.h>
 #include <stdlib.h>

typedef  struct  wrap_data
 {
         int  offset;
         int  path;
         int  *data;
 }wrap_data;


 int choosevec(int path)
 {
         if(path<=4)
         {
                 return 4;
         } 
         else if (path<=8)
         {
                 return 8;
         }
         else if(path<=16)
         {
                 return  16;
         }
         else
         {
                 return 32;
         }
 }

wrap_data **vec;
 int  vecsize;

wrap_data  *  up ( int num )
 {
         int  i,j,k;
         wrap_data  *first,*second;
         i=num;
         second=vec[i];
         while(i)
         {
                 j=i/2;
                 first=vec[j];

                if(!first)
                 {
                         vec[j]=second;
                         if (!j)
                         {
                                 return second;
                         }
                         else
                         {
                                 return NULL;
                         }
                 }
                 if ( first->path==second->path)
                 {
                         i=j;
                 }
                 else if ( *( second->data + second->offset )>  *( first->data + first->offset )) 
                 {
                         vec[j]=second;
                         second=first;
                         i=j; 

                }
                 else 
                 {
                         i=j;
                 }
         }
         return  second;
 }

int  main()
 {
 #define  PATH  4
 #define  LENGTH  10
 #define   MAX_BIG   999999999

        wrap_data *result;
         int i=0,j=0,k=0;
         wrap_data a[PATH]={0};

        vecsize=2*    choosevec(PATH);
         vec=(wrap_data **)calloc( vecsize ,sizeof (wrap_data*)); 

        for(i=0;i<PATH;i++)
         {
                 a[i].data=(int*) calloc (LENGTH , sizeof (int ));
                 a[i].offset=0;
                 a[i].path=i;
                 for(j=0;j<LENGTH;j++)
                 {

                        *(a[i].data+j)=(i*i+j)%40;

                }
                 *(a[i].data+LENGTH-1)=MAX_BIG;
         }
         for(i=0;i<PATH;i++)
         {
                 for(j=0;j<LENGTH;j++)
                 {
                         printf("%d  ", *(a[i].data+j));
                 }
                 printf("\n");
         }
         k=vecsize/2;
         for(i=0;i<PATH;i++)
         {
                 vec[k+i]=&a[i];
         }
         for(i=0;i<PATH;i++)
         {
                 result=up(i+k);
                 if(!result)
                 {
                 }
                 else
                 {
                         break;
                 }
         }
         while(result)
         {
                 if (MAX_BIG == *(result->data+result->offset))
                 {
                         break;
                 }
                 printf(" %d  ", *(result->data+result->offset));   
                 result->offset++;  
                 result=up(result->path+k);
         }
         printf("\n");

}


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值