MSD_radix_sort

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

MSD_radix_sort

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

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

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

我真正采用的是下表:

MSD_radix_sort
表中第一项表示第一个元素开启一个类别,紧跟的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还慢。

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

四、讨论

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

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

 

 

 

 

你可能感兴趣的:(sort)