您的位置:首页 > 其它

关于“主键-次键”排序的三种方法比较。

2010-11-22 18:59 239 查看
自己给自己放了七天假,回家休息一下。在家懒,七天就写了300多行代码,还质量不高...

在《计算机编程艺术——vlo3》中(以下简称Art3),在排序内容前言的习题中谈到关于带主键和次键的排序问题,其实就类似与字符串的排序方式,即比完主键看次键1,再次键2...。三种方法:

  A:先按主键排序,再在排完序的序列里将主键相同的划分为一个个区域,再比较次键1,递归的进行下去,直到次键全部比较完或区域中只剩下一个元素。

  B:先以最小的次键n排序,再以次键n-1排序,...一直到主键。

  C:排序时比较是以字典排序法比较,一次搞定。

以下是我的实现和测试代码:

代码

/*对于具有主键(唯一)和次键(>=0)的排序,有三种方式:
1.先对主键进行排序进行分组,在每个分组内再依次对各个次键进行排序分组
2.先对优先级最低的键进行排序,然后再逐步上升
3.对于排序的元素比较方式是字典排序法

注意:要使三种排序的结果一致,前提条件是排序是稳定的。

实验表明三种方案中,C(字典排序法)是最稳定的,效率最高的。
*/
//for timeval and gettimeofday
#include<sys/time.h>

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

#define A 1
#define B 2
#define C 3

typedef
struct
{
int keys[100];
}elem;

//记录三种策略的总时间(单位usec)
unsigned int total_A_u=0;
unsigned int total_B_u=0;
unsigned int total_C_u=0;

typedef int (*msort_func)(void* a,void* b,int at);

//merge sort 保证排序的稳定性
//参数:
//    array为代排序的序列
//    n序列元素的个数
//    size序列元素的大小
//    f为比较函数
//
void msort(elem** array,size_t n,int key_num,msort_func f);

//模拟情形1:已经排好序的序列,但序列中的元素数值是随机的
void sorted_random(elem** pe,unsigned int n,int key_num);
//模拟情景2:完全反序
void res_sorted_random(elem** pe,unsigned int n,int key_num);
//模拟情景3:完全随机
void unsorted(elem** pe,unsigned int n,int key_num);

//分析函数:统计分析每一种情形下的三种排序方法的复杂度:
//    1.比较次数
//    2.总时间
void analysis(elem** pe,unsigned int n,int key_num,int type);

void print_keys(elem** pe,int n,int key_num)
{
int i,j;
for(i=0;i<n;i++)
{
printf("The %dth element is:",i+1);
for(j=0;j<key_num;j++)
{
printf("%d ",pe[i]->keys[j]);
}
printf("\n");
}
}

int sort_func(void* a ,void * b,int at)
{
elem *x = (elem*)a;
elem *y = (elem*)b;
return (x->keys[at]-y->keys[at]);
}

int main()
{
unsigned int elem_num;
scanf("%u",&elem_num);
elem **pelems =  (elem**)malloc(sizeof(elem*)*elem_num);
int i;
for(i=0;i<elem_num;i++)
pelems[i]=(elem*)malloc(sizeof(elem));
int key_num;
for(key_num=10;key_num<=30;key_num++)
{
sorted_random(pelems,elem_num,key_num);
printf("SORTED:\n");
print_keys(pelems,elem_num,key_num);
analysis(pelems,elem_num,key_num,A);
analysis(pelems,elem_num,key_num,B);
analysis(pelems,elem_num,key_num,C);

res_sorted_random(pelems,elem_num,key_num);
printf("RES SORTED\n");
print_keys(pelems,elem_num,key_num);
analysis(pelems,elem_num,key_num,A);
analysis(pelems,elem_num,key_num,B);
analysis(pelems,elem_num,key_num,C);

unsorted(pelems,elem_num,key_num);
printf("RANDOM\n");
print_keys(pelems,elem_num,key_num);
analysis(pelems,elem_num,key_num,A);
analysis(pelems,elem_num,key_num,B);
analysis(pelems,elem_num,key_num,C);

printf("Total time of A:%ld B:%ld C:%ld\n",total_A_u,total_B_u,total_C_u);
}
for(i=0;i<elem_num;i++)
free(pelems[i]);
free(pelems);
return 0;
}

void msort(elem** array,size_t n,int key_num,msort_func f)
{
if(n<=1)
return;
int mid = n/2;
msort(array,mid,key_num,f);
msort(array+mid,n-mid,key_num,f);

elem** tmp = (elem**)malloc(n*sizeof(elem*));
int i,j,k;
k=i=0;j=mid;
while(i<mid && j<n)
{
//[i] > [j]
if(f(array[i],array[j],key_num)>0)
{
tmp[k]=array[j];
j++;
}
//[i] <= [j]
else
{
tmp[k]=array[i];
i++;
}
k++;
}
if(k!=n)
{
if(i<mid)
{
while(i<mid)
tmp[k++]=array[i++];
}
else
{
while(j<n)
tmp[k++]=array[j++];
}
}
for(i=0;i<n;i++)
array[i]=tmp[i];
}

inline unsigned int gen_rand(unsigned int last)
{
static unsigned int add=0;
add+=last;
srand(time(NULL)+(add));
return rand();
}

void sorted_random(elem** pe,unsigned int n,int key_num)
{
int at =0;
for(;at<key_num;at++)
{
int highest = 10000;
unsigned int remain = n;
int now =0;
unsigned int last =0;
while(remain)
{
last=gen_rand(last);
if((last%highest)<remain)
{
pe[n-remain]->keys[at]=now;
remain--;
}
else
{
now++;
highest--;
}
}
}
}

void res_sorted_random(elem** pe,unsigned int n,int key_num)
{
int at =0;
for(;at<key_num;at++)
{
int highest = 10000;
unsigned int remain = n;
int now =0;
unsigned int last=0;
while(remain)
{
last=gen_rand(last);
if((last%highest)<remain)
{
pe[remain-1]->keys[at]=now;
remain--;
}
else
{
now++;
highest--;
}
}
}
}
void unsorted(elem** pe,unsigned int n,int key_num)
{
int at =0;
for(;at<key_num;at++)
{
int highest = 10000;
int i;
unsigned int last=0;
for(i=0;i<n;i++)
{
last=gen_rand(last);
pe[i]->keys[at]=(last%highest);
}
}
}

void plan_A(elem** pelems,unsigned int n,int key_num,int now)
{
if(now==key_num || n==1)
return;
msort(pelems,n,now,sort_func);
int group_val = (*pelems)->keys[now];
int i=1;
elem** group=pelems;
elem** end = pelems+n;
while(group+i!=end)
{
if(pelems[i]->keys[now]==group_val)
{
i++;
}
else
{
plan_A(group,i,key_num,now+1);
group+=i;
i=1;
if(group!=end)
group_val = (*group)->keys[now];
}
}
}
void plan_B(elem** pelems,unsigned int n,int key_num)
{
elem ** tpelems = (elem**)malloc(sizeof(elem*)*n);
int i;
for(i=0;i<n;i++)
tpelems[i]=pelems[i];
int now = key_num-1;
while(now>=0)
{
msort(tpelems,n,now,sort_func);
now--;
}

print_keys(tpelems,n,key_num);
free(tpelems);
}
int sort_func_C(void* a,void* b,int key_num)
{
elem* x = (elem*)a;
elem* y = (elem*)b;
int i;
for(i=0;i<key_num;i++)
{
if(x->keys[i]!=y->keys[i])
return (x->keys[i]-y->keys[i]);
}
return 0;
}
void plan_C(elem** pelems,unsigned int n,int key_num)
{
elem ** tpelems = (elem**)malloc(sizeof(elem*)*n);
int i;
for(i=0;i<n;i++)
tpelems[i]=pelems[i];

msort(tpelems,n,key_num,sort_func_C);
print_keys(tpelems,n,key_num);
free(tpelems);
}

void analysis(elem** pelems,unsigned int n,int key_num,int type)
{
struct timeval tv1;
struct timeval tv2;
unsigned long micro_time_passed;
switch(type)
{
case A:
{
gettimeofday(&tv1,NULL);

elem ** tpelems = (elem**)malloc(sizeof(elem*)*n);
int i;
for(i=0;i<n;i++)
tpelems[i]=pelems[i];

plan_A(tpelems,n,key_num,0);

print_keys(tpelems,n,key_num);
free(tpelems);

gettimeofday(&tv2,NULL);

micro_time_passed=(tv2.tv_sec-tv1.tv_sec)*1000+(tv2.tv_usec-tv1.tv_usec)/1000;
total_A_u+=(tv2.tv_usec-tv1.tv_usec + (tv2.tv_sec-tv1.tv_sec)*1000000);
printf("plan A cost %ld micro seconds sec:%ld usec %ld\n",micro_time_passed,(tv2.tv_sec-tv1.tv_sec),(tv2.tv_usec-tv1.tv_usec));
break;

}
case B:
{
gettimeofday(&tv1,NULL);

plan_B(pelems,n,key_num);

gettimeofday(&tv2,NULL);

micro_time_passed=(tv2.tv_sec-tv1.tv_sec)*1000+(tv2.tv_usec-tv1.tv_usec)/1000;

total_B_u+=(tv2.tv_usec-tv1.tv_usec + (tv2.tv_sec-tv1.tv_sec)*1000000);
printf("plan B cost %ld micro seconds sec:%ld usec %ld\n",micro_time_passed,(tv2.tv_sec-tv1.tv_sec),(tv2.tv_usec-tv1.tv_usec));
break;
}
case C:
{
gettimeofday(&tv1,NULL);

plan_C(pelems,n,key_num);

gettimeofday(&tv2,NULL);

micro_time_passed=(tv2.tv_sec-tv1.tv_sec)*1000+(tv2.tv_usec-tv1.tv_usec)/1000;

total_C_u+=(tv2.tv_usec-tv1.tv_usec + (tv2.tv_sec-tv1.tv_sec)*1000000);
printf("plan C cost %ld micro seconds sec:%ld usec %ld\n",micro_time_passed,(tv2.tv_sec-tv1.tv_sec),(tv2.tv_usec-tv1.tv_usec));
break;
}
}
}


  从测试结果来看,毫无疑问:肯定是第三种方法平均效率最高,但我一直以为方法B凭借着方法的简单性,要比方法A要快,可是实际上必不是如此...究其原因应该是B方法太呆板,无论源数据是什么情况全都是一股脑的从n键排到主键。看来再做事和做人的时候有时候也不能太呆板,凡事都有其解决之道,而不能一种方法走天下啊。呵呵,卖弄了卖弄了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: