Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
String 使用长公共前缀进行更快的字符串排序?_String_Algorithm_Sorting_Data Structures - Fatal编程技术网

String 使用长公共前缀进行更快的字符串排序?

String 使用长公共前缀进行更快的字符串排序?,string,algorithm,sorting,data-structures,String,Algorithm,Sorting,Data Structures,我有一套弦。其中90%是以开头的URL。“http://www.“。我想按字母顺序把它们分类 目前我使用C++ STD::SoTo()。但是std::sort是基于比较的快速排序的一种变体,比较两个具有长公共前缀的字符串并不有效。但是(我认为)基数排序也不起作用,因为大多数字符串都放在同一个桶中,因为公共前缀很长 对于这个问题,有比普通的快速排序/基数排序更好的算法吗?常见前缀似乎自然地暗示trie数据结构可能有用。因此,我们的想法是构建一个包含所有单词的trie,然后对每个节点进行排序。排序应

我有一套弦。其中90%是以
开头的URL。“http://www.“
。我想按字母顺序把它们分类

目前我使用C++ STD::SoTo()。但是std::sort是基于比较的快速排序的一种变体,比较两个具有长公共前缀的字符串并不有效。但是(我认为)基数排序也不起作用,因为大多数字符串都放在同一个桶中,因为公共前缀很长


对于这个问题,有比普通的快速排序/基数排序更好的算法吗?

常见前缀似乎自然地暗示trie数据结构可能有用。因此,我们的想法是构建一个包含所有单词的trie,然后对每个节点进行排序。排序应该是特定节点的子节点驻留在列表中并进行排序。这很容易做到,因为在一个特定的节点上,我们只需要对子节点进行排序,所以递归解决方案自然会显现出来。更多灵感请参见此:

创建两个组:带前缀的组和不带前缀的组。对于第一组,请删除前缀,然后对前缀进行排序并重新添加。对于第二组,只需排序。之后,将第二个集合划分为before前缀和After前缀。现在连接三个列表(前列表2、后列表1、后列表2)

您可以编写自己的自定义代码,在前缀之后开始比较,而不是删除和添加第一个列表的前缀(即,在比较时忽略前缀部分)


附录:如果你有多个常用前缀,你可以进一步使用它们来加快速度。最好用一个非常常见的前缀创建一个浅树并加入它们。

< P>我猜想,当你考虑URL的平均长度时,花费在每个URL的10个字符的顺序上尝试使用共同前缀的处理时间甚至不为自己支付。
试试完全标准的那种。如果这还不够快,可以考虑并行化或分发一个完全标准的排序。这是一种简单可行的方法。

如果在开始快速排序之前计算出向量中的最小值和最大值,那么您总是知道每次调用partition()的值的范围,因为分区值是最小值或最大值(或至少接近最小值/最大值)每个子范围的最小值和最大值以及包含分区的最小值和最大值是每个子范围的另一端

如果子范围的最小值和最大值共享公共前缀,则可以从公共前缀后面的字符位置开始执行所有分区比较。随着快速排序的进行,范围越来越小,因此它们的公共前缀应该越来越长,忽略它们进行比较将节省越来越多的时间。多少,我不知道;您必须对此进行基准测试,看看它是否真的有帮助

无论如何,额外的开销是相当小的;一次遍历向量以查找最小和最大字符串,每个字符串(*)花费1.5次比较,然后对每个分区进行一次检查以查找分区的最大共享前缀;该检查相当于一个比较,它可以从包含前缀的最大共享前缀开始,因此它甚至不是一个完整的字符串比较


  • 最小/最大算法:一次扫描矢量两个元素。对于每一对,首先将它们相互比较,然后将较小的一对与运行最小值进行比较,将较大的一对与运行最大值进行比较。结果:两个元素进行三次比较,或每个元素进行1.5次比较

最后,我发现三元快速排序效果很好。我发现算法在

这是我修改过的实现,具有类似于std::sort的接口。它比我的机器和数据集上的std::sort快大约40%

#include <iterator>

template<class RandIt> static inline void multiway_qsort(RandIt beg, RandIt end, size_t depth = 0, size_t step_len = 6) {
    if(beg + 1 >= end) {
        return;
    }

    struct { /* implement bounded comparing */
        inline int operator() (
                const typename std::iterator_traits<RandIt>::value_type& a,
                const typename std::iterator_traits<RandIt>::value_type& b, size_t depth, size_t step_len) {

            for(size_t i = 0; i < step_len; i++) {
                if(a[depth + i] == b[depth + i] && a[depth + i] == 0) return 0;
                if(a[depth + i] <  b[depth + i]) return +1;
                if(a[depth + i] >  b[depth + i]) return -1;
            }
            return 0;
        }
    } bounded_cmp;

    RandIt i = beg;
    RandIt j = beg + std::distance(beg, end) / 2;
    RandIt k = end - 1;

    typename std::iterator_traits<RandIt>::value_type key = ( /* median of l,m,r */
            bounded_cmp(*i, *j, depth, step_len) > 0 ?
            (bounded_cmp(*i, *k, depth, step_len) > 0 ? (bounded_cmp(*j, *k, depth, step_len) > 0 ? *j : *k) : *i) :
            (bounded_cmp(*i, *k, depth, step_len) < 0 ? (bounded_cmp(*j, *k, depth, step_len) < 0 ? *j : *k) : *i));

    /* 3-way partition */
    for(j = i; j <= k; ++j) {
        switch(bounded_cmp(*j, key, depth, step_len)) {
            case +1: std::iter_swap(i, j); ++i;      break;
            case -1: std::iter_swap(k, j); --k; --j; break;
        }
    }
    ++k;

    if(beg + 1 < i) multiway_qsort(beg, i, depth, step_len); /* recursively sort [x > pivot] subset */
    if(end + 1 > k) multiway_qsort(k, end, depth, step_len); /* recursively sort [x < pivot] subset */

    /* recursively sort [x == pivot] subset with higher depth */
    if(i < k && (*i)[depth] != 0) {
        multiway_qsort(i, k, depth + step_len, step_len);
    }
    return;
}
#包括
模板静态内嵌空心多路排序(RandIt beg,RandIt end,尺寸深度=0,尺寸步长=6){
如果(beg+1>=结束){
返回;
}
结构{/*实现有界比较*/
内联int运算符()(
常量typename std::迭代器特征::值类型&a,
常量typename std::迭代器特征::值(类型和b、大小(深度)、大小(步长){
对于(大小i=0;ib[depth+i])返回-1;
}
返回0;
}
}有界_-cmp;
RandIt i=乞讨;
RandIt j=beg+std::距离(beg,end)/2;
RandIt k=end-1;
类型名称std::迭代器特征::值类型键=(/*l、m、r的中值)*/
有界cmp(*i,*j,深度,步长)>0?
(有界cmp(*i,*k,深度,步长)>0?(有界cmp(*j,*k,深度,步长)>0?*j:*k:*i):
(有界cmp(*i,*k,深度,步长)小于0?(有界cmp(*j,*k,深度,步长)<0?*j:*k:*i));
/*三向分割*/
对于(j=i;j轴)子集*/
if(end+1>k)多路排序(k,end,depth,step_len);/*递归排序[x
令人惊讶的是,这篇论文在URL数据集上提供了大量单线程算法的基准测试(见第29页)。Rantala的多键快速排序与缓存的变体提前问世;您可以在中测试多键缓存8

我在那篇论文中测试了数据集,如果有任何迹象表明你在前十个字符中只看到了一点熵,并且在100个字符范围内区分了前缀。进行100次基数排序将对缓存产生影响,但没有什么好处,例如,对一百万个URL排序意味着你在ea中寻找约20个区分位c键