zoukankan      html  css  js  c++  java
  • Trie树遍历的加速

    Trie树用来给字符串排序的时候有一个好处:边读边排序,但是读完之后要输出的时候麻烦来了。经过测试,用26W个word建立的Trie中,空白位是使用位的20倍左右,那么在Trie比较大的时候当然也就比较慢了。这篇文章讨论的优化主要是去避免访问这些空白位,实现方式无关(数组或指针?)。

      首先想到的一个方法是:在insert的时候顺便标记这个节点有哪些子节点。因为总共只有26种可能性,那么自然也就想到了用一个int作为flag,如果0位置1则表示有‘a’这个子节点。

      第一步(记录)完成了,下面我们来看如何来使用该记录?熟悉位移的同学可能已经想到:可以使用x&-x来计算出最低位为1的数。但是遗憾的是这个并不是我们想要的结果,因为得到的是2^N,我们想要的是这个N。好的,最笨的一种方法出来了:

      int t[] = new int[1<<26];

      t[1<<0] = 0.....

    非常遗憾的是我们申请不了这么大的空间。那么,问题就是将一些离散的数通过数组建立映射关系,很自然地就会联想到Hash。怎么使用Hash呢?我尝试了一下,从2^0到2^26对29取余数为:

      1.2.4.8.16.3.6.12.24.19.9.18.7.14.28.27.25.21.13.26.23.17.5.10.20.11

    没有看错,没有一个是相同的!这样的话就可以仅仅使用一个大小不到30的数组就可以搞定。同样遗憾的时候,这里用到了取余数的操作,要知道这个还算比较大的,可能一不小心就把我们辛辛苦苦省下来的时间又葬送掉了。那么有没有其他的方法呢?还是回到最笨的方法的思路上:

      如果我们申请不了int[1<<26],那申请int[1<<13]总是可以的吧?

    为什么这么做呢?因为申请不了这么大的空间!这时候就把这个问题换成两半了,比如在节点I出的标志位flag:

      int lowHalf = flag&((1<<14)-1);

      int highHalf = (flag>>13)&((1<<14)-1);

      while(lowHalf > 0){

        int i = lowHalf&-lowHalf;

        int j = t[i];

        // do someting

      }

      while(highHalf > 0){

        int i = highHalf&-highHalf;

        int j = t[i]+13;

        // do someting

      }

    和最笨的那种方法相比,只是多了一次操作而已。

      好了现在来看最后一种方法,就不多写了:

      switch(flag&-flag){

      case 1<<0:

      case 1<<1:

      case 1<<2:

      .....

      }

  • 相关阅读:
    Unity The Method Signature Matching Rule
    Unity The Property Matching Rule
    Unity The Type Matching Rule
    Unity The Custom Attribute Matching Rule
    Unity The Member Name Matching Rule
    Unity No Policies
    Unity The Return Type Matching Rule
    Unity The Parameter Type Matching Rule
    Unity The Namespace Matching Rule
    关于TSQL递归查询的(转)
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/2701042.html
Copyright © 2011-2022 走看看