关于“主键-次键”排序的三种方法比较。
2010-11-22 18:59
239 查看
自己给自己放了七天假,回家休息一下。在家懒,七天就写了300多行代码,还质量不高...
在《计算机编程艺术——vlo3》中(以下简称Art3),在排序内容前言的习题中谈到关于带主键和次键的排序问题,其实就类似与字符串的排序方式,即比完主键看次键1,再次键2...。三种方法:
A:先按主键排序,再在排完序的序列里将主键相同的划分为一个个区域,再比较次键1,递归的进行下去,直到次键全部比较完或区域中只剩下一个元素。
B:先以最小的次键n排序,再以次键n-1排序,...一直到主键。
C:排序时比较是以字典排序法比较,一次搞定。
以下是我的实现和测试代码:
代码
从测试结果来看,毫无疑问:肯定是第三种方法平均效率最高,但我一直以为方法B凭借着方法的简单性,要比方法A要快,可是实际上必不是如此...究其原因应该是B方法太呆板,无论源数据是什么情况全都是一股脑的从n键排到主键。看来再做事和做人的时候有时候也不能太呆板,凡事都有其解决之道,而不能一种方法走天下啊。呵呵,卖弄了卖弄了。
在《计算机编程艺术——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键排到主键。看来再做事和做人的时候有时候也不能太呆板,凡事都有其解决之道,而不能一种方法走天下啊。呵呵,卖弄了卖弄了。
相关文章推荐
- 关于-c#字符串三种逆转方法及性能比较的另外看法
- 三种排序方法的比较
- 关于C++中定义比较函数的三种方法小结
- <数据结构>——关于插入排序的三种方法
- 三种排序方法的比较
- 删除排序数组中的重复元素(三种方法的比较)
- 关于Hibernate的merge() attachDirty() attachClean()三种方法比较使用
- c++中的三种排序,比较基础,因为作为一个编程员总要会几种排序方法
- ASP.NET跳转页面的三种方法比较
- 快速排序三种实现方法
- iOS 视图实现圆角效果的三种方法及比较
- asp.net跳转页面的三种方法比较
- java java中subString、split、stringTokenizer三种截取字符串方法的性能比较
- java计算文件大小三种方法以及优缺点比较
- Java中三种比较常见的数组排序
- asp.net跳转页面的三种方法比较
- 深入C中常用的三种排序方法总结以及探讨分析
- 第二周项目1 比较三种交换值的方法
- Java 判断字符串是否为空的三种方法性能比较
- java 写文件的三种方法比较