原文地址:点击打开链接
堆实现:采用一个和路数相等长度的数组模拟堆,每次都进行入堆和出堆操作。在堆中每个元素代表一路数据,其中保存有此数组已经访问到哪里的下标,每次在进行出堆操作,取出极值元素之后,我们更新相应的下标,之后再讲此元素入堆。
#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");
}