算法的理論學習可右轉Creeper_LKF大佬的洛穀日報html
一個優化算法理論時間複雜度的實例點這裏c++
另外一個實例點這裏算法
時間複雜度\(O(n)\),算常數的話要乘位長。數組
蒟蒻參考了Creeper_LKF大佬的模板,並在通用性上面稍微提高了一點。能夠兼容全部存儲整數的基本類型,以及在此基礎上構建的結構體類型(多關鍵字排序時,優先級高的關鍵字默認須要在結構體中靠後)。緩存
函數原型函數
template<typename T> void Radixsort(T*fst,T*lst,T*buf,int*op)
T
即爲待排序的類型名,fst
lst
爲首尾指針(和sort
同樣),buf
爲緩衝區指針,op
爲操做列表。學習
\(op[i]\)提供類型的第\(i\)個字節的比較方式,具體來講有\(5\)種取值。
\(-1\):該字節不是排序的關鍵字。
\(0\):以該字節爲基準從小到大排序。
\(1\):以該字節爲基準從大到小排序。
\(2\):以該字節爲基準從小到大排序,且該字節的最高位是有符號整形的符號位。
\(3\):以該字節爲基準從大到小排序,且該字節的最高位是有符號整形的符號位。優化
例如,對int
從小到大排序,則應將\(\{0,0,0,2\}\)傳入\(op\)。ui
對結構體unsigned int,int
之前一個爲關鍵字從大到小排序,則代碼大體寫成spa
Radixsort(a,a+n,buf,new int[8]{1,1,1,1,-1,-1,-1,-1});
對長度爲\(n\)的int
數組排序效率對好比下:(STL不吸氧是真的布星)
\[\begin{matrix} 方式&n=10^6,不開\text{O2}&n=5*10^6,不開\text{O2}&n=5*10^6,開\text{O2}&n=10^7,開\text{O2}\\ \text{Radixsort}&\text{20ms}&\text{120ms}&\text{60ms}&\text{120ms}\\ \text{std::sort}&\text{200+ms}&\text{1100+ms}&\text{320+ms}&\text{680+ms}\\ \text{std::stable_sort}&\text{210+ms}&\text{1200+ms}&\text{410+ms}&\text{860+ms} \end{matrix}\]
然而,Radixsort
的運行時間與待排序類型的關鍵字位長總和成正比(upd:蒟蒻目測和總位長也有關,猜想是由於訪問步長增長致使緩存刷新次數增長。例如,對long long
排序大約是對int
排序的三倍時間)。
而std::sort
受此的影響小多了。當總位長在\(10\)位以上時,開O2之後二者的差距很小了。因此綜合實現難度方面,int
多關鍵字和long long
等用開O2的std::sort
就夠了。
至於實數類型,Radixsort
不能直接資磁。double
是\(8\)位的用std::sort
就行了。至於若是是在想從小到大排float
的話,必須膜改一下數組,將全部的負實數強行除了符號位都按位取反之後,傳入\(\{0,0,0,2\}\),最後還要還原回來,實在是太麻煩了。
#include<bits/stdc++.h> #define UC unsigned char using namespace std; template<typename T> void Radixsort(T*fst,T*lst,T*buf,int*op){ static int b[0x100]; int Len=lst-fst,Sz=sizeof(T),at=0,i,j; UC*bgn,*end,tmp; for(i=0;i<Sz;++i){ if(op[i]==-1)continue; bgn=(UC*)fst+i;end=(UC*)lst+i; tmp=((op[i]&1)?0xff:0)^((op[i]&2)?0x80:0); memset(b,0,sizeof(b)); for(UC*it=bgn;it!=end;it+=Sz)++b[tmp^*it]; for(j=1;j<0x100;++j)b[j]+=b[j-1]; for(UC*it=end;it!=bgn;buf[--b[tmp^*(it-=Sz)]]=*--lst); lst=buf+Len;swap(fst,buf);at^=1; } if(at)memcpy(buf,fst,Sz*Len); }
有沒有以爲很好實現呢?比什麼後綴排序不知道好寫到哪裏去了
這樣實現很簡短,但常數沒有卡到極限,b桶數組的初始化部分能夠強行展開出來並行計算。