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 ...
随机推荐
- Android 选择本地图片的demo
https://github.com/lipanquan/SelectLocalPhoto
- 9 Strings
1 Strings 1.1 Strings and GStrings Groovy允许你使用2种不同类型的字符串类型,分别是java.lang.String和groovy.lang.GS ...
- linux面试题:删除一个目录下的所有文件,但保留一个指定文件
面试题:删除一个目录下的所有文件,但保留一个指定文件 解答: 假设这个目录是/xx/,里面有file1,file2,file3..file10 十个文件 [root@oldboy xx]# touch ...
- python17 多线程学习
多线程 多任务可以由多进程完成,也可以由一个进程内的多线程完成. 我们前面提到了进程是由若干线程组成的,一个进程至少有一个线程. 由于线程是操作系统直接支持的执行单元,因此,高级语言通常都内置多线程的 ...
- CentOS 7安装Perl环境
平台信息 Description: CentOS Linux release 7.6.1810 (Core) 安装步骤 安装支持 $ yum install perl* #安装perl相关支持 $ y ...
- 办公开发环境(外接显示屏,wifi热点)
笔记本电脑怎样外接显示器 https://jingyan.baidu.com/article/3c48dd34495247e10ae35879.html?qq-pf-to=pcqq.c2c 怎样在Wi ...
- 基于Python实现邮件发送
import smtplibfrom email.mime.text import MIMETextemail_host = 'smtp.163.com' # 邮箱地址email_user = 'sz ...
- Cloudera Manager卸载笔记
1.通过管理平台分别停止组件服务和Cloudera Management Service 2.通过管理平台注销并移除Parcles (在控制台注销并移除,无论是安装的Parcles还是未安装的Parc ...
- mongodb 用户权限控制
MongoDB已经使用很长一段时间了,基于MongoDB的数据存储也一直没有使用到权限访问(MongoDB默认设置为无权限访问限制),今天特地花了一点时间研究了一下,研究成果如下: 注:研究成果基于W ...
- C# 十进制与二进制、十六进制、八进制之间的转换
1.十进制 转 二进制 将十进制数不断地除2,将所有余数倒叙填写,即可得到所需二进制数据. public static string DecimalToBinary(int vDecimal) { / ...