Algorithm 比BMH(Boyer&"x2013;Moore&"x2013;Horspool)搜索更快的算法

Algorithm 比BMH(Boyer&"x2013;Moore&"x2013;Horspool)搜索更快的算法,algorithm,search,string,full-text-search,Algorithm,Search,String,Full Text Search,您将使用哪种算法在短文本中搜索短子字符串?简而言之,我的意思是5-10个字符代表子字符串,255个字符代表字符串。我正在考虑根据输入数据长度选择算法。对于较长的输入,哪种算法更好?试试。但是,对于这样短的字符串,通常的线性扫描就足够了。您可以尝试或。两者都取决于模式的长度。如果你正在寻找一种比Boyer Moore更好的算法,那么你要求的是混合答案 据我所知,在文本搜索中,只有后缀树优于Boyer-Moore。但是,它使用更多的时间来创建索引,并使用更多的磁盘空间 其他信息: 在速度方面,后缀树

您将使用哪种算法在短文本中搜索短子字符串?简而言之,我的意思是5-10个字符代表子字符串,255个字符代表字符串。我正在考虑根据输入数据长度选择算法。对于较长的输入,哪种算法更好?

试试。但是,对于这样短的字符串,通常的线性扫描就足够了。

您可以尝试或。两者都取决于模式的长度。

如果你正在寻找一种比Boyer Moore更好的算法,那么你要求的是混合答案

据我所知,在文本搜索中,只有后缀树优于Boyer-Moore。但是,它使用更多的时间来创建索引,并使用更多的磁盘空间

其他信息: 在速度方面,后缀树或后缀数组胜过任何版本的Boyer-Moore,因为后缀树基本上实现了树状数据结构中所有可能的搜索

但是,后缀树具有较高的ram内存成本,并且索引文本(创建树数据结构)的速度较慢

Boyer Moore与后缀树的速度差异: Boyer Moore在搜索文本上是线性的。 后缀树在搜索模式上是线性的

如果在200个字符的文本中搜索5个字母单词,boyer moore将执行200次操作,后缀树将执行5次操作

无论它的速度有多快,都很难实现。就数据结构的难度而言,它可能是最难的。一旦建成,它可以大大优化空间和速度

这就是说,在未来几年中寻找后缀树。 通常,后缀树用于DNA索引和web搜索引擎优化

Boyer Moore被广泛应用于各个领域,例如会议程序(文本搜索功能)和网络搜索引擎。

@anon@Anton Gogolev
用一个词回答你的问题: 四联轨道炮

这个C函数在短的2,3,4模式和160个字符的字符串上进行了大量测试,您可以在这个表中自行决定

还有一篇文章:

我认为Boyer-Moore Horspool可以通过这种变化更快(我不知道它的名字,也许我的名字:-))。BMH算法没有利用匹配字符和非匹配字符信息。它仅使用当前图案位置中的最后一个文本字符。例如:

Pattern:  ABCABC
          012345
在BMH中,下一个位置是(C与下一个C对齐):

如果我们使用匹配的字符,下一个位置是(BC与下一个BC对齐):

如果我们使用匹配字符和不匹配字符,下一个位置是(BC与下一个BC对齐,但由于不匹配的模式字符A与下一个BC的上一个字符相同,因此也将不匹配。由于没有其他BC,跳过的是模式长度):

这是Java实现(仍然可以改进),使用风险自负,因为我还没有彻底测试它。在我的性能测试中,Boyer Moore Horspool在所有方面仍然优于此实现。但正如预期的那样,如果模式被重用(两者都没有模式预处理),那么这个实现将获胜

public static int[] processPattern1(char[] pattern) {
    int[] skip = new int[256];

    for (int i = 0; i < skip.length; ++i) {
        skip[i] = pattern.length;
    }

    for (int i = 0; i < pattern.length - 1; ++i) {
        skip[pattern[i]] = pattern.length - i - 1;
    }

    return skip;
}

public static int[] processPattern2(char[] pattern) {
    int[] skip = new int[pattern.length];
    int i, j, k, x, y;
    int lpos = pattern.length - 1;
    int l2pos = pattern.length - 2;

    OUTER:
    for (k = l2pos; k > -1; k--) { // k points to unmatched pattern character
        j = k + 1;
        for (i = k; i > 0; i--) {
            if (pattern[i] == pattern[j] && pattern[i-1] != pattern[k]) {
                for (x = i + 1, y = j + 1; y < pattern.length && pattern[x] == pattern[y]; x++, y++) {
                }
                if (y == pattern.length) {
                    skip[k] = pattern.length - x;
                    continue OUTER;
                }
            }
        }
        for (x = lpos - j; x > -1; x--) {
            if (pattern[x] == pattern[lpos]) {
                for (i = x - 1, y = l2pos; i > -1 && pattern[i] == pattern[y]; i--, y--) {
                }
                if (i == -1) {
                    skip[k] = lpos - x;
                    continue OUTER;
                }
            }
        }
        skip[k] = pattern.length;
    }

    return skip;
}

public static int search(char[] text, char[] pattern, int[] skip1, int[] skip2) {
    int k = pattern.length - 1;
    int i, j;
    int lpos = k;
    int l2pos = pattern.length - 2;

    while (k < text.length) {
        if (text[k] == pattern[lpos]) {
            for (j = l2pos, i = k - 1; j > -1 && text[i] == pattern[j]; j--, i--) {
            }
            if (j == -1) {
                return i + 1;
            }
            k += skip2[j];
        } else {
            k += skip1[text[k]];
        }
    }

    return -1;
}

public static void main(String[] args) {
    String origText = "TTTTTTTTTTTTTTTZBCRABCCABCTTTTTTTTTTTTT";
    char[] pattern = "ZBCRABCCABC".toCharArray();
    char[] text = origText.toCharArray();
    int[] skip1 = processPattern1(pattern);
    int[] skip2 = processPattern2(pattern);
    System.out.println(search(text, pattern, skip1, skip2) == origText.indexOf(pattern));
}
publicstaticint[]processPattern1(char[]pattern){
int[]跳过=新int[256];
对于(int i=0;i-1;k--){//k指向不匹配的模式字符
j=k+1;
对于(i=k;i>0;i--){
if(模式[i]==模式[j]&模式[i-1]!=模式[k]){
对于(x=i+1,y=j+1;y-1;x--){
if(模式[x]==模式[lpos]){
对于(i=x-1,y=l2pos;i>-1&&pattern[i]==pattern[y];i--,y--){
}
如果(i==-1){
skip[k]=lpos-x;
继续对外开放;
}
}
}
跳过[k]=模式长度;
}
回程箕斗;
}
公共静态int搜索(char[]文本,char[]模式,int[]skip1,int[]skip2){
int k=模式长度-1;
int i,j;
int-lpos=k;
int l2pos=pattern.length-2;
while(k-1&&text[i]==pattern[j];j--,i--){
}
如果(j==-1){
返回i+1;
}
k+=skip2[j];
}否则{
k+=skip1[文本[k]];
}
}
返回-1;
}
公共静态void main(字符串[]args){
字符串origText=“ttttttttt zbcracabctttttttttttttt”;
char[]pattern=“zbcrabc.toCharArray();
char[]text=origText.toCharArray();
int[]skip1=processPattern1(模式);
int[]skip2=processPattern2(模式);
System.out.println(搜索(文本、模式、skip1、skip2)=origText.indexOf(模式));
}

以下是我对上述代码的改进。在我的测试中,它与BMH并驾齐驱,但在某些情况下会取得相当大的成功(每次运行是对39650个字符的英文文档的随机位置进行1000000次搜索)

公共类BoyerMoore{
int[]tab1=新int[256];
int[]tab2=新int[1000][1001];
int[]tab3=新int[1000];
公共场所{
for(int i=0;iText   : TTTTZBCTTTTTTTTTTTTT
Pattern: ABCCABC
Text   : TTTTZBCTTTTTTTTTTTTT
Pattern:        ABCCABC
public static int[] processPattern1(char[] pattern) {
    int[] skip = new int[256];

    for (int i = 0; i < skip.length; ++i) {
        skip[i] = pattern.length;
    }

    for (int i = 0; i < pattern.length - 1; ++i) {
        skip[pattern[i]] = pattern.length - i - 1;
    }

    return skip;
}

public static int[] processPattern2(char[] pattern) {
    int[] skip = new int[pattern.length];
    int i, j, k, x, y;
    int lpos = pattern.length - 1;
    int l2pos = pattern.length - 2;

    OUTER:
    for (k = l2pos; k > -1; k--) { // k points to unmatched pattern character
        j = k + 1;
        for (i = k; i > 0; i--) {
            if (pattern[i] == pattern[j] && pattern[i-1] != pattern[k]) {
                for (x = i + 1, y = j + 1; y < pattern.length && pattern[x] == pattern[y]; x++, y++) {
                }
                if (y == pattern.length) {
                    skip[k] = pattern.length - x;
                    continue OUTER;
                }
            }
        }
        for (x = lpos - j; x > -1; x--) {
            if (pattern[x] == pattern[lpos]) {
                for (i = x - 1, y = l2pos; i > -1 && pattern[i] == pattern[y]; i--, y--) {
                }
                if (i == -1) {
                    skip[k] = lpos - x;
                    continue OUTER;
                }
            }
        }
        skip[k] = pattern.length;
    }

    return skip;
}

public static int search(char[] text, char[] pattern, int[] skip1, int[] skip2) {
    int k = pattern.length - 1;
    int i, j;
    int lpos = k;
    int l2pos = pattern.length - 2;

    while (k < text.length) {
        if (text[k] == pattern[lpos]) {
            for (j = l2pos, i = k - 1; j > -1 && text[i] == pattern[j]; j--, i--) {
            }
            if (j == -1) {
                return i + 1;
            }
            k += skip2[j];
        } else {
            k += skip1[text[k]];
        }
    }

    return -1;
}

public static void main(String[] args) {
    String origText = "TTTTTTTTTTTTTTTZBCRABCCABCTTTTTTTTTTTTT";
    char[] pattern = "ZBCRABCCABC".toCharArray();
    char[] text = origText.toCharArray();
    int[] skip1 = processPattern1(pattern);
    int[] skip2 = processPattern2(pattern);
    System.out.println(search(text, pattern, skip1, skip2) == origText.indexOf(pattern));
}
public class BoyerMoore {

    int[] tab1 = new int[256];
    int[][] tab2 = new int[1000][1001];
    int[] tab3 = new int[1000];

    public BoyerMoore8() {
        for (int i = 0; i < tab1.length; i++) {
            tab1[i] = -1;
        }
    }

    public void processPattern(char[] pattern) {
        // tab1 structure,
        // 0 => tab2 index
        // tab2 structure,
        // 0 - pattern length - 2 => skip values
        // pattern length - 1 => default skip value
        // pattern length => pattern position where to start comparing
        int i, p;
        int lp = pattern.length - 1;

        for (i = 0; i < pattern.length; ++i) {
            tab3[i] = tab1[pattern[i]];
            tab1[pattern[i]] = i;
        }

        for (i = pattern.length - 2; i > -1; i--) {
            if (i < tab1[pattern[i]]) {
                continue;
            }

            p = tab1[pattern[i]];
            tab2[p][lp] = lp - i;
            tab2[p][pattern.length] = i - 1;

            computeJump(pattern, p, i + 1, tab2[p][lp]);
        }
        computeJump(pattern, tab1[pattern[lp]], pattern.length, 0);
    }

    public void computeJump(char[] pattern, int index, int len, int defJump) {
        int i, k, x, y;
        int lpos = len - 1;
        int l2pos = len - 2;
        int p = tab3[lpos];

        OUTER1:
        for (k = 0; k < lpos; k++) { // k points to unmatched pattern character
            i = tab3[k + 1];
            OUTER2:
            while (i > 0) {
                if (pattern[i - 1] != pattern[k]) {
                    x = k + 2;
                    y = i + 1;
                    while (x < len) {
                        if (pattern[y++] != pattern[x++]) {
                            i = tab3[i];
                            continue OUTER2;
                        }
                    }
                    tab2[index][k] = (len - y) + defJump;
                    continue OUTER1;
                } else {
                    i = tab3[i];
                }
            }
            x = l2pos - k;
            while (p > x) {
                p = tab3[p];
            }
            i = p;
            OUTER3:
            while (i > -1) {
                x = l2pos;
                y = i - 1;
                while (y > -1) {
                    if (pattern[y--] != pattern[x--]) {
                        i = tab3[i];
                        continue OUTER3;
                    }
                }
                tab2[index][k] = (lpos - i) + defJump;
                continue OUTER1;
            }
            tab2[index][k] = len + defJump;
        }
    }

    public int search(char[] text, char[] pattern) {
        int k = pattern.length - 1;
        int i, j, p;
        int lpos = k;
        int l2pos = k - 1;

        OUTER:
        while (k < text.length) {
            p = tab1[text[k]];
            if (p == -1) {
                k += pattern.length;
                continue OUTER;
            } else {
                if (text[k] == pattern[lpos]) {
                    for (j = l2pos, i = k - 1; j > -1; j--, i--) {
                        if (text[i] != pattern[j]) {
                            k += tab2[p][j];
                            continue OUTER;
                        }
                    }
                    return i + 1;
                } else {
                    for (j = tab2[p][pattern.length], i = k - 1; j > -1; j--, i--) {
                        if (text[i] != pattern[j]) {
                            k += tab2[p][j];
                            continue OUTER;
                        }
                    }
                    k += tab2[p][lpos];
                    continue OUTER;
                }
            }
        }

        return -1;
    }

    public int search(String origText, String origPattern) {
        char[] text = origText.toCharArray();
        char[] pattern = origPattern.toCharArray();

        processPattern(pattern);
        int res = search(text, pattern);

        for (int i = 0; i < pattern.length; i++) {
            tab1[pattern[i]] = -1;
        }

        return res;
    }
}
Pattern:  ABCABC
          012345
public class BoyerMooreHorspool {

    int[] tab1 = new int[256];
    int[][] tab2 = new int[1000][1000];
    int[] tab3 = new int[1000];

    public BoyerMooreHorspool() {
        for (int i = 0; i < tab1.length; i++) {
            tab1[i] = 999;
        }
        for (int i = 0; i < 1000; i++) {
            tab2[999][i] = -1;
        }
    }

    public void processPattern(char[] pattern) {
        int i, j, p;

        for (i = 0; i < pattern.length; ++i) {
            tab1[pattern[i]] = -1;
        }

        for (i = 0; i < pattern.length; ++i) {
            tab3[i] = tab1[pattern[i]];
            tab1[pattern[i]] = i;
        }

        for (i = 0; i < pattern.length; i++) {
            p = tab1[pattern[i]];

            for (j = tab3[i] + 1; j < i; j++) {
                tab2[p][j] = tab3[i];
            }
            if (i == p) {
                for (j = i; j < pattern.length; j++) {
                    tab2[p][j] = i;
                }
            } else {
                tab2[p][i] = i;
            }
        }
    }

    public int search(char[] text, char[] pattern) {
        int k = pattern.length - 1;
        int i, j, oi, ok;
        int lpos = k;

        while (k < text.length) {
            j = k;
            ok = k;
            i = tab2[tab1[text[j]]][lpos];
            k += lpos - i;
            j--;
            i--;
            while (i > -1) {
                oi = i;
                i = tab2[tab1[text[j]]][i];
                k += oi - i;
                j--;
                i--;
            }
            if (ok == k) {
                return j + 1;
            }
        }

        return -1;
    }

    public int search(String origText, String origPattern) {
        char[] text = origText.toCharArray();
        char[] pattern = origPattern.toCharArray();

        processPattern(pattern);
        int res = search(text, pattern);

        for (int i = 0; i < pattern.length; i++) {
            tab1[pattern[i]] = 999;
        }

        return res;
    }
}