为了完成二维数据快速分类,最先使用的是hash分类。

前几天我突然想,既然基数排序的时间复杂度也不高,而且可能比hash分类更稳定,所以不妨试一下。

在实现上我依次实现:

1、一维数组基数排序

基本解决主要问题,涵盖排序,包含改进的存储分配策略。

如果用链表来实现,大量的函数调用将耗费太多时间。

2、二维数组基数排序

主要是实现和原有程序的集成。

一、数据结构

下面是存储节点的主数据结构。

typedef struct tagPageList{
int * PagePtr;
struct tagPageList * next;
}PageList; typedef struct tagBucket{
int * currentPagePtr;
int offset;
PageList pl;
PageList * currentPageListItem;
}Bucket;

链表内是存储的一个4KB页面的指针。

每4KB页面可以存储最多1024个记录序号,如果是一维数组排序,那就直接存储数组元素了。

二、算法

基数排序可以分为MSD或者LSD。这里用的是LSD。

伪代码如下:

for i= to sizeof(sorted-element-type){
for each sorted-num{
cell = sorted-num
bucketIdx = (cell>>*i)&0xff
bucket[bucketIdx] = cell
}
combine linked list nodes to overwrite original array
}

C代码实现:

int main(){
HANDLE heap = NULL;
Bucket bucket[BUCKETSLOTCOUNT];
PageList * pageListPool;
int plpAvailable = ;
int * pages = NULL;
int * pagesAvailable = NULL;
int * objIdx;
unsigned short * s; time_t timeBegin;
time_t timeEnd; heap = HeapCreate(HEAP_NO_SERIALIZE|HEAP_GENERATE_EXCEPTIONS, *, );
if (heap != NULL){
pages = (int * )HeapAlloc(heap, , (TFSI/PAGEGRANULAR + BUCKETSLOTCOUNT + ) * );
pageListPool = (PageList *)HeapAlloc(heap, , (TFSI/PAGEGRANULAR + ) * sizeof(PageList));
s = (unsigned short *)HeapAlloc(heap, , TFSI*sizeof(unsigned short));
objIdx = (int *)HeapAlloc(heap, , TFSI * sizeof(int));
}
MakeSure(pages != NULL && pageListPool != NULL && objIdx != 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); timeBegin = clock(); for (int t=; t<sizeof(short); t++){
FillMemory(pages, (TFSI/PAGEGRANULAR + BUCKETSLOTCOUNT + ) * , 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);
} int bucketIdx;
for (int i=; i<TFSI; i++){
bucketIdx = (s[objIdx[i]]>>t*)&0xff;
MakeSure(bucketIdx < );
//save(bucketIdx, objIdx[i]);
bucket[bucketIdx].currentPagePtr[ bucket[bucketIdx].offset ] = objIdx[i];
bucket[bucketIdx].offset++;
if (bucket[bucketIdx].offset == PAGEGRANULAR){
bucket[bucketIdx].currentPageListItem->next = &pageListPool[plpAvailable];
plpAvailable++;
MakeSure(plpAvailable < TFSI/PAGEGRANULAR + );
bucket[bucketIdx].currentPageListItem->next->PagePtr = pagesAvailable;
bucket[bucketIdx].currentPageListItem->next->next = NULL; bucket[bucketIdx].currentPagePtr = pagesAvailable;
bucket[bucketIdx].offset = ;
pagesAvailable += PAGEGRANULAR;
MakeSure(pagesAvailable < pages+(TFSI/PAGEGRANULAR + BUCKETSLOTCOUNT + ) * ); bucket[bucketIdx].currentPageListItem = bucket[bucketIdx].currentPageListItem->next;
}
} //update objIdx index
int start = ;
for (int i=; i<; i++){
PageList * p;
p = &(bucket[i].pl);
while (p){
for (int t=; t<PAGEGRANULAR; t++){
int idx = p->PagePtr[t];
if (idx != TERMINATOR){
objIdx[start] = idx;
start++;
}
if (idx == TERMINATOR) break;
}
p = p->next;
}
}
} 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);
HeapDestroy(heap); return ;
}

三、测试结果。

i7 3632QM @2.2GHz ==>TB 3.2GHz/ 8G RAM/  win8 64bit/VS2012 win32 release

1024*1024*100,1亿个随机生成 short 型数据。
1.438000(s) consumed in generating random numbers
4.563000(s) consumed in radix sort 
12.719000(s) consumed in qsort
7.641000(s) consumed in std::sort

1024*1024*5   500万随机生成 short 型数据。
0.078000(s) consumed in generating random numbers
0.172000(s) consumed in radix sort 
0.656000(s) consumed in qsort
0.390000(s) consumed in std::sort

1024*500
0.000000(s) consumed in generating random numbers
0.015000(s) consumed in radix sort 
0.063000(s) consumed in qsort
0.047000(s) consumed in std::sort

四、讨论

二维数据分类上,性能相当于hash分类 约 1/3 。

比库例程稍快,慢的主要原因还是存储器,如果只是解决一维数组的话,调整下可以更快。

但对于二维数组多个线程同时操作,排序是不可接受的。

Radix Sort的更多相关文章

  1. 基数排序(radix sort)

    #include<iostream> #include<ctime> #include <stdio.h> #include<cstring> #inc ...

  2. 经典排序算法 - 基数排序Radix sort

    经典排序算法 - 基数排序Radix sort 原理类似桶排序,这里总是须要10个桶,多次使用 首先以个位数的值进行装桶,即个位数为1则放入1号桶,为9则放入9号桶,临时忽视十位数 比如 待排序数组[ ...

  3. [Algorithms] Radix Sort

    Radix sort is another linear time sorting algorithm. It sorts (using another sorting subroutine) the ...

  4. 排序算法七:基数排序(Radix sort)

    上一篇提到了计数排序,它在输入序列元素的取值范围较小时,表现不俗.但是,现实生活中不总是满足这个条件,比如最大整形数据可以达到231-1,这样就存在2个问题: 1)因为m的值很大,不再满足m=O(n) ...

  5. [MIT6.006] 7. Counting Sort, Radix Sort, Lower Bounds for Sorting 基数排序,基数排序,排序下界

    在前6节课讲的排序方法(冒泡排序,归并排序,选择排序,插入排序,快速排序,堆排序,二分搜索树排序和AVL排序)都是属于对比模型(Comparison Model).对比模型的特点如下: 所有输入ite ...

  6. 基数排序(Radix Sort)

    基数排序(Radix Sort) 第一趟:个位 收集: 第二趟:十位 第三趟:百位 3元组 基数排序--不是基于"比较"的排序算法 递增就是把收集的过程返过来 算法效率分析 需要r ...

  7. 【算法】基数排序(Radix Sort)(十)

    基数排序(Radix Sort) 基数排序是按照低位先排序,然后收集:再按照高位排序,然后再收集:依次类推,直到最高位.有时候有些属性是有优先级顺序的,先按低优先级排序,再按高优先级排序.最后的次序就 ...

  8. 学习算法-基数排序(radix sort)卡片分类(card sort) C++数组实现

    基数排序称为卡片分类,这是一个比较早的时间越多,排名方法. 现代计算机出现之前,它已被用于排序老式打孔卡. 说下基数排序的思想.前面我有写一个桶式排序,基数排序的思想是桶式排序的推广. 桶式排序:ht ...

  9. [Algorithm] Radix Sort Algorithm

    For example we have the array like this: [, , , , , ] First step is using Counting sort for last dig ...

随机推荐

  1. 深入了解Json Web Token之概念篇

    https://www.freebuf.com/articles/web/180874.html http://www.ruanyifeng.com/blog/2018/07/json_web_tok ...

  2. PHP漏洞全解—————9、文件上传漏洞

    本文主要介绍针对PHP网站文件上传漏洞.由于文件上传功能实现代码没有严格限制用户上传的文件后缀以及文件类型,导致允许攻击者向某个可通过 Web 访问的目录上传任意PHP文件,并能够将这些文件传递给 P ...

  3. Redis未授权访问反弹shell

    Redis未授权访问反弹shell 目标主机:10.104.11.178 攻击机:kali 攻击步骤: 1.与目标主机连接 root@kali:~# /usr/redis/redis-cli -h 1 ...

  4. Python Numpy Array

    Numpy 是Python中数据科学中的核心组件,它给我们提供了多维度高性能数组对象. Arrays Numpy.array   dtype 变量 dtype变量,用来存放数据类型, 创建数组时可以同 ...

  5. css 断行省略号,隐藏,fixed定位

    text-overflow(clip | elipsis)(显示省略号| 不显示省略号) white-space:nowrap    强制文字不断行 word-break:break-all;     ...

  6. 转 Comparison of Red Hat and Oracle Linux kernel versions and release strings

    Originally derived from Red Hat Enterprise Linux (RHEL), Oracle Linux (OL) contains minor difference ...

  7. java多线程(四)

    一个例子: Account.java 客户实体类 package com.asiainfo.test.thread8; /** * 账户类 * @author luke * */ public cla ...

  8. org.apache.subversion.javahl.ClientException: Working copy is not up-to-date

    之前因为将项目中的一个文件删除了,然后添加了新的文件,svn提交的时候报错. 提示:Working copy is not up-to-date 解决办法:对应的项目上右键然后选择team,然后选择u ...

  9. C# winform文件批量转编码 选择文件夹

    C# winform文件批量转编码 选择文件夹 打开指定目录 private void btnFile_Click(object sender, EventArgs e) { OpenFileDial ...

  10. C#注册URL协议,使用浏览器打开本地程序,类似网页上点了QQ交谈打开本地QQ客户端程序

    本教程适用于Windows系统 从浏览器上打开本地程序,主要用到了本地URL协议,其实主要就是改注册表 先建立一个项目,我建的是控制台项目 在Program.cs写2个静态方法用来添加注册表.移除注册 ...