MSD_radix_sort

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

MSD的基本手法就是不断切片。
每一步都是把整体数据切割成256片,如上图所示,实际情况切片未必均匀,有的slice内可能一个元素也没有。

接下来对于每个切片怎么办呢?
答案是继续切,对于特殊数据来讲,切片过程可以很快结束,这样就可以实现比LSD更快的速度。

这里面最困难的地方就是如何存储每个slice的头和尾。
如果采用下述方式,应该是行不通的。
这个方式需要做数组元素插入,还要跟踪中间数据,因此没具体考虑。

我真正采用的是下表:


表中第一项表示第一个元素开启一个类别,紧跟的0表示此元素和上面的1是同一类。
至于2表明在切片过程中是一个孤立的元素,后续就没必要再切片了。
这个方式可以大大简化编码。

 

二、伪代码。

for each slice
    if slice-tag == 2 continue;
    if slice-tag == 1
        slice it;
        update bookkeeping
int main(){
    HANDLE heap = NULL;
    Bucket bucket[BUCKETSLOTCOUNT];
    PageList * pageListPool;
    int plpAvailable = 0;
    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, 1024*1024, 0);
    if (heap != NULL){
        pages = (int * )HeapAlloc(heap, 0, (TFSI/PAGEGRANULAR + BUCKETSLOTCOUNT + 8) * PAGEAMOUNT);
        pageListPool = (PageList *)HeapAlloc(heap, 0, (TFSI/PAGEGRANULAR + 8) * sizeof(PageList));
        s = (unsigned short *)HeapAlloc(heap, 0, TFSI*sizeof(unsigned short));
        objIdx = (int *)HeapAlloc(heap, 0, TFSI * sizeof(int));
        classifier = (__int8 *)HeapAlloc(heap, 0, (TFSI+8)*sizeof(__int8));
    }
    MakeSure(pages != NULL && pageListPool != NULL && objIdx != NULL && classifier != NULL);

    for(int i=0; i<TFSI; i++) objIdx[i]=i;
    timeBegin = clock();
    for (int i=0; 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[0] = 1;
    classifier[TFSI] = 1;
    
    timeBegin = clock();

    bool no_need_further_processing = false;
    for (int t=sizeof(short)-1; t>=0; t--){
        int bucketIdx;
        int slice_pointer = 0;
        int slice_base = 0;
        int flagCounter = 0;

        if (no_need_further_processing) break;

        //classifier: 1 new catagory
        //classifier: 2 completed catagory process
        while (slice_pointer < TFSI){
            if (classifier[slice_pointer] == 2){
                slice_base = slice_pointer;
                classifier[slice_base] = 0;
                while (classifier[slice_pointer] == 0){
                    slice_pointer++;
                    flagCounter++;
                }
                classifier[slice_base] = 2;

                if (flagCounter == TFSI) no_need_further_processing = true;
                continue;
            }
            
            if (classifier[slice_pointer] == 1){
                FillMemory(pages, (TFSI/PAGEGRANULAR + BUCKETSLOTCOUNT + 8) * PAGEAMOUNT, 0xff);
                SecureZeroMemory(pageListPool, (TFSI/PAGEGRANULAR + 8) * sizeof(PageList));
                pagesAvailable = pages;
                plpAvailable = 0;

                for(int i=0; i<256; i++){
                    bucket[i].currentPagePtr = pagesAvailable;
                    bucket[i].offset = 0;
                    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] = 0;
                while (classifier[slice_pointer] == 0){
                    //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 = 0;
                        pagesAvailable += PAGEGRANULAR;
                        
                        bucket[bucketIdx].currentPageListItem = bucket[bucketIdx].currentPageListItem->next;
                    }

                    slice_pointer++;
                }
                classifier[slice_base] = 1;

                //update classifier;
                //update objIdx index
                int start = slice_base;
                for (int i=0; i<256; i++){
                    PageList * p;
                    p = &(bucket[i].pl);
                    //classifier: 1 new catagory
                    //classifier: 2 complete catagory process
                    classifier[start] = 1;

                    int counters = 0;
                    while (p){
                        for (int t=0; 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 == 1) classifier[start-1] = 2;
                }
                //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, 0, pages);
    HeapFree(heap, 0, pageListPool);
    HeapFree(heap, 0, s);
    HeapFree(heap, 0, objIdx);
    HeapFree(heap, 0, classifier);
    HeapDestroy(heap);

    return 0;
}

 

三、测试

1024*1024*100 个短整型。

时间  5.438s

看到这里就知道杯具了,比LSD还慢。

如果应用到二维表,会更惨不忍睹。试了下果然如此。

四、讨论

如果哪位有更好的方法,欢迎讨论。

或者,基数排序只是一个花瓶?

 

 

 

 

转载于:https://www.cnblogs.com/servo/p/3371038.html

### 基数排序算法解释 基数排序是一种非比较型整数排序算法,其原理在于将整数按位分割成不同的数字,然后按照每位数字分别进行排序。具体来说,基数排序可以分为最低有效位优先(Least Significant Digit First, LSD)和最高有效位优先(Most Significant Digit First, MSD)。对于正整数而言,通常采用LSD方式。 #### 算法流程 1. 获取数组中的最大值以确定最大的位数。 2. 对于每一位上的数值(从低位到高位),利用计数排序作为子程序来稳定地排序整个数组。 3. 将处理后的数据重新组合形成最终有序序列。 这种方法的时间复杂度为线性的 \(O(nk)\),其中 n 是输入大小而 k 表示键长度,在固定范围内性能优于基于比较的传统排序方法[^3]。 #### Java 实现代码 以下是Java版本的基数排序实现: ```java import java.util.Arrays; public class RadixSort { public static void main(String[] args) { int[] array = {170, 45, 75, 90, 802, 24, 2, 66}; System.out.println("Original Array: " + Arrays.toString(array)); radixsort(array); System.out.println("Sorted Array: " + Arrays.toString(array)); } private static void radixsort(int[] input){ final int RADIX = 10; // Declare and initialize bucket[] List<Integer>[] buckets = new ArrayList[RADIX]; for (int i = 0; i < buckets.length; i++) { buckets[i] = new ArrayList<Integer>(); } boolean maxLength = false; int tmp = -1, placement = 1; while (!maxLength) { maxLength = true; // split input between lists for(Integer i : input) { tmp = i / placement; buckets[tmp % RADIX].add(i); if(maxLength && tmp > 0) { maxLength = false; } } // empty lists into input array int a = 0; for (int b = 0; b < RADIX; b++) { for(Integer i : buckets[b]) { input[a++] = i; } buckets[b].clear(); } // move to next digit placement *= RADIX; } } } ``` 此段代码展示了如何通过多次调用内部使用的桶分配机制完成对给定整数列表的有效排序过程[^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值