基于字典树实现的O(n)排序

我们用字典树,从高位到低位进行排序,使用中有类似于基排的思路。

残留问题在于,空间方面,需要我们使用vector或类似的动态扩充的来做。不过,不想去想了,先给个代码:

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+1,M=256,mod=255;
struct node{
    int a[M],tot;
}t[N<<2];
int cnt,sav[5];
inline void insert(int x){
    int now=0;
    for(int i=1;i<=4;++i){
        sav[i]=(x&mod),x>>=8;
    }
    int res=0;
    for(int i=4;i;--i){
        int v=sav[i];
        res=(res<<8)+v;
        if(!t[now].a[v]){
            t[now].a[v]=++cnt;
        }
        now=t[now].a[v];
    }
    ++t[now].tot;
}
inline void print(int now,int sum){
    while(t[now].tot){
        --t[now].tot;
        printf("%d ",sum);
    }
    for(int i=0;i<M;++i){
        if(t[now].a[i]){
            print(t[now].a[i],(sum<<8)+i);
        }
    }
}
int main(){
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;++i){
        int x;
        scanf("%d",&x);
        insert(x);
    }
    print(0,0);
    return 0;
}

Update:一个粗糙的想法:我们用vector储存,最终输出排序的时候,每次对每个节点的最多256个子节点排序即可,直接输出排序后的序列的复杂度最多\(O(4(树高)*8(排序)*n)\),使用基排会更低(将基数设为4,会有最低复杂度\(O(4(树高)*4(排序)*n)\))

此算法的优势:总复杂度在\(O(n)\)水平,且支持常数级别的增加/删除操作,也可以用来查询kth,前驱,后继,(使用二分的话,每次复杂度最多即为就是\(O(4(树高)*8(二分次数)=32)\),kth维护和,前驱后继分别维护最小值和最大值,然后,前驱后继因为可以直接索引,所以可以不用二分做到\(O(4)\)

Update2:发现,上面的方法其实并不优秀,因为如果我们增加树高的话,会使得总负责度更低,比如我们令基数为16,树高变高了,但是空间却可以开下了,就可以避免排序的复杂度了,所以,我们可以根据题目,动态的变化基数大小。
(当然,从总分析来看,基数为8是最优的)

如何做有负数的情况?类似二进制位,我们加一层“符号位”,0为负,1为正即可

原文链接: https://www.cnblogs.com/ThinkofBlank/p/12928148.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍;

也有高质量的技术群,里面有嵌入式、搜广推等BAT大佬

    基于字典树实现的O(n)排序

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/350018

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年3月2日 上午6:03
下一篇 2023年3月2日 上午6:03

相关推荐