MSD_radix_sort
一、这次是在上一次尝试基础上进行的,预期是达到上次性能的9倍。

MSD的基本手法就是不断切片。
每一步都是把整体数据切割成256片,如上图所示,实际情况切片未必均匀,有的slice内可能一个元素也没有。
接下来对于每个切片怎么办呢?
答案是继续切,对于特殊数据来讲,切片过程可以很快结束,这样就可以实现比LSD更快的速度。
这里面最困难的地方就是如何存储每个slice的头和尾。
如果采用下述方式,应该是行不通的。
这个方式需要做数组元素插入,还要跟踪中间数据,因此没具体考虑。
我真正采用的是下表:

表中第一项表示第一个元素开启一个类别,紧跟的0表示此元素和上面的1是同一类。
至于2表明在切片过程中是一个孤立的元素,后续就没必要再切片了。
这个方式可以大大简化编码。
二、伪代码。
for each slice
if slice-tag == continue;
if slice-tag ==
slice it;
update bookkeeping
int main(){
HANDLE heap = NULL;
Bucket bucket[BUCKETSLOTCOUNT];
PageList * pageListPool;
int plpAvailable = ;
int * pages = NULL;
int * pagesAvailable = NULL;
int * objIdx;
unsigned short * s;
__int8 * classifier = NULL;
time_t timeBegin;
time_t timeEnd;
heap = HeapCreate(HEAP_NO_SERIALIZE|HEAP_GENERATE_EXCEPTIONS, *, );
if (heap != NULL){
pages = (int * )HeapAlloc(heap, , (TFSI/PAGEGRANULAR + BUCKETSLOTCOUNT + ) * PAGEAMOUNT);
pageListPool = (PageList *)HeapAlloc(heap, , (TFSI/PAGEGRANULAR + ) * sizeof(PageList));
s = (unsigned short *)HeapAlloc(heap, , TFSI*sizeof(unsigned short));
objIdx = (int *)HeapAlloc(heap, , TFSI * sizeof(int));
classifier = (__int8 *)HeapAlloc(heap, , (TFSI+)*sizeof(__int8));
}
MakeSure(pages != NULL && pageListPool != NULL && objIdx != NULL && classifier != NULL);
for(int i=; i<TFSI; i++) objIdx[i]=i;
timeBegin = clock();
for (int i=; i<TFSI; i++) s[i] = rand();
timeEnd = clock();
printf("\n%f(s) consumed in generating numbers", (double)(timeEnd-timeBegin)/CLOCKS_PER_SEC);
SecureZeroMemory(classifier, TFSI*sizeof(__int8));
classifier[] = ;
classifier[TFSI] = ;
timeBegin = clock();
bool no_need_further_processing = false;
for (int t=sizeof(short)-; t>=; t--){
int bucketIdx;
int slice_pointer = ;
int slice_base = ;
int flagCounter = ;
if (no_need_further_processing) break;
//classifier: 1 new catagory
//classifier: 2 completed catagory process
while (slice_pointer < TFSI){
if (classifier[slice_pointer] == ){
slice_base = slice_pointer;
classifier[slice_base] = ;
while (classifier[slice_pointer] == ){
slice_pointer++;
flagCounter++;
}
classifier[slice_base] = ;
if (flagCounter == TFSI) no_need_further_processing = true;
continue;
}
if (classifier[slice_pointer] == ){
FillMemory(pages, (TFSI/PAGEGRANULAR + BUCKETSLOTCOUNT + ) * PAGEAMOUNT, 0xff);
SecureZeroMemory(pageListPool, (TFSI/PAGEGRANULAR + ) * sizeof(PageList));
pagesAvailable = pages;
plpAvailable = ;
for(int i=; i<; i++){
bucket[i].currentPagePtr = pagesAvailable;
bucket[i].offset = ;
bucket[i].pl.PagePtr = pagesAvailable;
bucket[i].pl.next = NULL;
pagesAvailable += PAGEGRANULAR;
bucket[i].currentPageListItem = &(bucket[i].pl);
}
slice_base = slice_pointer;
classifier[slice_base] = ;
while (classifier[slice_pointer] == ){
//for each slice element, push_back to pages;
unsigned char * cell = (unsigned char *)&s[objIdx[slice_pointer]];
bucketIdx = cell[t];
//save(bucketIdx, objIdx[i]);
bucket[bucketIdx].currentPagePtr[ bucket[bucketIdx].offset ] = objIdx[slice_pointer];
bucket[bucketIdx].offset++;
if (bucket[bucketIdx].offset == PAGEGRANULAR){
bucket[bucketIdx].currentPageListItem->next = &pageListPool[plpAvailable];
plpAvailable++;
bucket[bucketIdx].currentPageListItem->next->PagePtr = pagesAvailable;
bucket[bucketIdx].currentPageListItem->next->next = NULL;
bucket[bucketIdx].currentPagePtr = pagesAvailable;
bucket[bucketIdx].offset = ;
pagesAvailable += PAGEGRANULAR;
bucket[bucketIdx].currentPageListItem = bucket[bucketIdx].currentPageListItem->next;
}
slice_pointer++;
}
classifier[slice_base] = ;
//update classifier;
//update objIdx index
int start = slice_base;
for (int i=; i<; i++){
PageList * p;
p = &(bucket[i].pl);
//classifier: 1 new catagory
//classifier: 2 complete catagory process
classifier[start] = ;
int counters = ;
while (p){
for (int t=; t<PAGEGRANULAR; t++){
int idx = p->PagePtr[t];
if (idx != TERMINATOR){
objIdx[start] = idx;
start++;
counters++;
}
if (idx == TERMINATOR) break;
}
p = p->next;
}
if (counters == ) classifier[start-] = ;
}
//update objIdx index
} //if (classifier[slice_pointer] == 1)
} //while (slice_pointer < TFSI)
} //for (int t=sizeof(short)-1; t>=0; t--)
timeEnd = clock();
printf("\n%f(s) consumed in generating results", (double)(timeEnd-timeBegin)/CLOCKS_PER_SEC);
//for(int i=0; i<TFSI; i++) printf("%d\n", s[objIdx[i]]);
HeapFree(heap, , pages);
HeapFree(heap, , pageListPool);
HeapFree(heap, , s);
HeapFree(heap, , objIdx);
HeapFree(heap, , classifier);
HeapDestroy(heap);
return ;
}
三、测试
1024*1024*100 个短整型。
时间 5.438s
看到这里就知道杯具了,比LSD还慢。
如果应用到二维表,会更惨不忍睹。试了下果然如此。
四、讨论
如果哪位有更好的方法,欢迎讨论。
或者,基数排序只是一个花瓶?
MSD_radix_sort的更多相关文章
- 读写ini文件
C# 使用文件流来读写ini文件 背景 之前采用ini文件作为程序的配置文件,觉得这种结构简单明了,配置起来也挺方便.然后操作方式是通过WindowsAPI,然后再网上找到一个基于WindowsAPI ...
随机推荐
- hdu1686 KMP 求在字符串A中字符串B出现的次数
Oulipo Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Subm ...
- Go语言基础之1--标识符、关键字、变量和常量、数据类型、Go的基本程序结构、Golang的特性
一.前言 当我们项目较为简单时,我们在src目录下新建一个该项目目录,里面存放源码文件即可,见下图: 当我们一个项目较为复杂时,我们可以在src目录下新建一个该项目目录,在针对该项目不同模块创建不同目 ...
- 18-----BBS论坛
BBS论坛(十八) 18.首页轮播图实现 (1)front/css/front_base.css .main-container{ width: 990px; margin: 0 auto; over ...
- perf命令
@(Linux基础)[perf命令] perf命令 ---- 简介 Perf是内置于Linux内核源码树中的性能剖析(profiling)工具,它基于事件采样原理,以性能事件为基础,支持针对处理器相关 ...
- 使用PyCharm实现远程编写并调试代码
使用PyCharm实现远程编写并调试代码 版权声明:本文为博主原创文章,转载请注明出https://www.cnblogs.com/wenqiangit/p/9771947.html 因为工作中使用的 ...
- Hadoop2.X分布式集群部署
本博文集群搭建没有实现Hadoop HA,详细文档在后续给出,本次只是先给出大概逻辑思路. (一)hadoop2.x版本下载及安装 Hadoop 版本选择目前主要基于三个厂商(国外)如下所示: 基于A ...
- java 多线程 yield方法的意义
Thread.yield( )方法: 使当前线程从执行状态(运行状态)变为可执行态(就绪状态).cpu会从众多的可执行态里选择,也就是说,当前也就是刚刚的那个线程还是有可能会被再次执行到的,并不是说一 ...
- pat1066. Root of AVL Tree (25)
1066. Root of AVL Tree (25) 时间限制 100 ms 内存限制 65536 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHEN, Yue An A ...
- Emacs学习笔记1
Emacs笔记-Emacs基本的文本操作 使用命令时要在minibuffer缓冲区中 关于文件 注意 在对单词的操作中C开头的控制范围要比M开头的控制范围要下 对于文件的撤销操作, 不要使用C-x, ...
- HDU 5441——Travel——————【并查集+二分查界限】
Travel Time Limit: 1500/1000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)Total Su ...