工作快2年了,大学搞算法搞得还算可以,可是毕竟工作之后接触的东西,能用上高级算法的地方少之又少
最近复习了一下数据结构和算法,结合最近学的一些知识,我对快速排序这个算法有了一个新的想法
那就是,将数据按一定区域划分,比如按50W以下,50W-500W,500W-5000W,5000W以上划分4个区域
然后再结合OpenMP的优化指令,启动4个线程去排序这4个区域的数据
那么如果数据划分到区域比较均匀的话,每个区域的数据排序时间期望就是 4 * (n/4) * lg(n/4),时间肯定比n*lgn快不少
关于OpenMP学习的,可以参考IBM写的文章:http://www.ibm.com/developerworks/cn/aix/library/au-aix-openmp-framework/
以下是我的一些测试结果,贴给大家看一下:
数据分布结构:
data01.in:
50W以下数据:427
500W以下数据:2606
5000W以下数据:16118
5000W以上数据:80849
data02.in:
50W以下数据:4041
500W以下数据:25638
5000W以下数据:160216
5000W以上数据:810105
data03.in:
50W以下数据:20157
500W以下数据:128289
5000W以下数据:799429
5000W以上数据:4052125
data04.in:
50W以下数据:40933
500W以下数据:255923
5000W以下数据:1598082
5000W以上数据:8105062
data05.in:
50W以下数据:81315
500W以下数据:511307
5000W以下数据:3193321
5000W以上数据:16214057
data06.in:
50W以下数据:121769
500W以下数据:770166
5000W以下数据:4793358
5000W以上数据:24314707
data07.in:
50W以下数据:162871
500W以下数据:1023665
5000W以下数据:6388110
5000W以上数据:32425354
请按任意键继续. . .
使用了OpenMP优化的qsort结果
data01.in:
总共耗时:32
读入数据时间:18
排序所用时间:14
data02.in:
总共耗时:343
读入数据时间:170
排序所用时间:173
data03.in:
总共耗时:1785
读入数据时间:814
排序所用时间:971
data04.in:
总共耗时:3610
读入数据时间:1614
排序所用时间:1996
data05.in:
总共耗时:7343
读入数据时间:3213
排序所用时间:4130
data06.in:
总共耗时:11187
读入数据时间:4851
排序所用时间:6336
data07.in:
总共耗时:14994
读入数据时间:6464
排序所用时间:8530
请按任意键继续. . .
没有使用OpenMP优化的qsort结果
data01.in:
总共耗时:33
读入数据时间:18
排序所用时间:15
data02.in:
总共耗时:340
读入数据时间:159
排序所用时间:181
data03.in:
总共耗时:1781
读入数据时间:787
排序所用时间:994
data04.in:
总共耗时:3617
读入数据时间:1552
排序所用时间:2065
data05.in:
总共耗时:7361
读入数据时间:3118
排序所用时间:4243
data06.in:
总共耗时:11206
读入数据时间:4670
排序所用时间:6536
data07.in:
总共耗时:15086
读入数据时间:6190
排序所用时间:8896
请按任意键继续. . .
从结果来看,好像并没有什么差异,有可能是编译器自动就会做优化,把运算过程自动交到其他线程去处理吧
也有可能是由于数据分布不均匀,导致效果不明显,不过无论如何,OpenMP版快速排序最多也就退化到原本快速排序应有的效率而已
而且编写难度也没有增加太多,这种思路还是值得探究的
最后,附上我写的一些程序,以供大家研究:
OpenMP版快速排序:
#include <stdio.h>
#include <stdlib.h>
#include <omp.h>
#include <time.h>
void qsort(int lt,int rt,int * number);
int number[100000];
int * range[4];
inline int getRange(int num)
{
if (num > 50000000) return 3; // >5000W
if (num > 5000000) return 2; // >500W
if (num > 500000) return 1; // >50W
return 0;
}
int main()
{
for (int i=0;i<4;++i)
{
range[i] = new int[50000000];
}
int n,num,j,len;
char file[100];
FILE * fileIn;
for (int Case=1;Case<8;++Case) {
sprintf(file,"data%02d.in",Case);
//freopen(file,"r",stdin);
fileIn = fopen(file,"r");
for (int i=0;i<4;++i)
{
range[i][0] = 0;
}
clock_t begin_time = clock();
fscanf(fileIn,"%d",&n);
for (int i=1;i<=n;++i)
{
//读数分类
fscanf(fileIn,"%d",&num);
j = getRange(num);
len = ++range[j][0];
range[j][len] = num;
}
clock_t read_finish = clock();
//openmp分布处理
omp_set_num_threads(4);
#pragma omp parallel for
for (int i=0;i<4;++i)
{
qsort(1,range[i][0],range[i]);
}
clock_t sort_finish = clock();
printf("data%02d.in:\n",Case);
printf("50W以下数据:%d\n",range[0][0]);
printf("500W以下数据:%d\n",range[1][0]);
printf("5000W以下数据:%d\n",range[2][0]);
printf("5000W以上数据:%d\n",range[3][0]);
printf("总共耗时:%d\n",sort_finish - begin_time);
printf("读入数据时间:%d\n",read_finish - begin_time);
printf("排序所用时间:%d\n",sort_finish - read_finish);
fclose(fileIn);
}
for (int i=0;i<4;++i)
{
delete [] range[i];
}
system("pause");
return 0;
}
void qsort(int lt,int rt,int * number)
{
if (rt <= lt) return;
int mid = (lt + rt) >> 1;
int midVal = number[mid];
int i = lt,j = rt;
int tmp;
do
{
while (i < rt && number[i] < midVal) ++i;
while (j > lt && number[j] > midVal) --j;
if (i <= j)
{
tmp = number[i];
number[i] = number[j];
number[j] = tmp;
++i;
--j;
}
}while (i <= j);
if (i < rt) qsort(i,rt,number);
if (lt < j) qsort(lt,j,number);
}
正常快速排序:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
void qsort(int lt,int rt,int * number);
int number[50000000];
int main()
{
int n,num,j,len;
char file[100];
FILE * fileIn;
for (int Case=1;Case<8;++Case) {
sprintf(file,"data%02d.in",Case);
//freopen(file,"r",stdin);
fileIn = fopen(file,"r");
clock_t begin_time = clock();
fscanf(fileIn,"%d",&n);
for (int i=1;i<=n;++i)
{
fscanf(fileIn,"%d",number+i);
}
clock_t read_finish = clock();
qsort(1,n,number);
clock_t sort_finish = clock();
printf("data%02d.in:\n",Case);
printf("总共耗时:%d\n",sort_finish - begin_time);
printf("读入数据时间:%d\n",read_finish - begin_time);
printf("排序所用时间:%d\n",sort_finish - read_finish);
fclose(fileIn);
}
system("pause");
return 0;
}
void qsort(int lt,int rt,int * number)
{
if (rt <= lt) return;
int mid = (lt + rt) >> 1;
int midVal = number[mid];
int i = lt,j = rt;
int tmp;
do
{
while (i < rt && number[i] < midVal) ++i;
while (j > lt && number[j] > midVal) --j;
if (i <= j)
{
tmp = number[i];
number[i] = number[j];
number[j] = tmp;
++i;
--j;
}
}while (i <= j);
if (i < rt) qsort(i,rt,number);
if (lt < j) qsort(lt,j,number);
}
数据生成器:
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
int main()
{
int n,total;
scanf("%d",&n);
srand(time(0));
freopen("data.in","w",stdout);
printf("%d\n",n);
for (int i=0;i<n;++i)
{
printf("%d ",rand() * rand());
}
putchar('\n');
fclose(stdout);
return 0;
}