小さなノートの文字列マッチングアルゴリズム

ブルートフォースアルゴリズム

また、単純なパターンマッチングアルゴリズムとして知られているBFアルゴリズムは、基本的な考え方は単純な問題の粗比較であるアルゴリズムにブルース・フォースによって提案されました。Cコードのアルゴリズムの実装は簡単ですが、詳細な操作でいくつかの問題が発生しました。
コードの問題

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#define LEN 100

int B_FIndex(char S[],char T[])
{
    int i = 0,j = 0;
    int Len_S = strlen(S); // 使用strlen函数获取字符串长度
    int Len_T = strlen(T);

    if(S == NULL || T == NULL || Len_S < Len_T)     // Error Input
        return -1;

    while(i < Len_S && j < Len_T)
    {
        if(S[i] == T[j])
        {
            i++;
            j++;
        }// end if
        else
        {
            i = i - j +1;
            j = 0;
        }// end else
    }//end while

    if(j >=Len_T)
    {
        printf("Success patterened at %d",i-j);	// 匹配成功位置信息提示
        return 0;
    }
    else
    {
        printf("Fail patterened");
        return -1;
    }
}//end BF

int main(int argc,char * argv[])
{
    char S[LEN+1],T[LEN+1];

    fgets(S,sizeof(S),stdin);	// 采用推荐的安全函数fgets
    fgets(T,sizeof(T),stdin);

    B_FIndex(S,T);
}

このコードは一見問題はない、と他のブログのコードでは違いはありませんが、コンパイラは渡すことができますが、それは100%正しいと一致することはできません、なぜあなたは言うのですか?
ケース1:=マスターシリアルストリング

hello world
hello world
Success patterened at 0
Process returned 0 (0x0)   execution time : 16.536 s
Press any key to continue.

あなたは、出力の期待を修正することができます。
ケース2:サブ<主な文字列

hello world
hello
Fail patterened
Process returned 0 (0x0)   execution time : 9.249 s
Press any key to continue.

これは何が原因ですか?
ためのscanf()関数のみ連続したストリング、遭遇スペースのその後端部を受け入れることができ、私が選んだように、マッチング機能に影響を与える関数fgets()は関数(比()を取得関数は、汎用、より安全です)。
私たちが直接に切り替えるとなります(一般的なアプリケーションで機能が問題ありません)、上記のコードは正常に動作します。しかし、取得する()関数最大の問題は、入力が原因配列の長さは超えているかどうか、それはチェックしないということであるメモリ・オーバーフローのセキュリティ問題を。
)((fgetsを持つ別の差に問題を引き起こす)となる本当の理由は以下のとおりです。

  • ()取得を停止することですガイド改行を読んで、文字を一つずつ読み込む(廃棄改行)
  • 関数fgets()は、それが最初の改行に遭遇するまで、文字にクロックされるかはsizeof(文字列)に読み込まれて-1文字を操作の最後に。改行が読み込まれている場合、それはなります改行、および他の文字とセーブ

だから、重要な問題は、改行文字です。
CASE1の場合には、メインの文字列

時間 E リットル リットル インクルード ワット インクルード R リットル D '\ n' は '\ 0'

また、文字列のための

時間 E リットル リットル インクルード ワット インクルード R リットル D '\ n' は '\ 0'

マッチが成功しているので、問題はありません。
しかし、ケース2で、文字列として

時間 E リットル リットル インクルード '\ n' は '\ 0'

したがって、サブストリングマッチングの原因は、改行を一致させるために行く時間を取ることです。

上記の分析は問題である場合、溶液は、失われた右ラインフィード関数BF内の文字列の長さを計算することで次のように、キーコードが変更され

    int Len_S = strlen(S) - 1; // 使用strlen函数获取字符串长度,不包含结束符,
    int Len_T = strlen(T) - 1; // 减1就去掉了换行符。

もちろん、単にこの問題を楽しみに特定の修正を置くために他の方法は、あります。

KMPアルゴリズム

このアルゴリズムは、ここに記載されていないについては、C ++のコードが直接与えられた
次の関数の
方法は、ここで次の関数の2種類を提供し、缶の仕事

/* 求模式全的netx[]函数
   next[]下标从0开始,初始值定位-1
   S:cdbcbabcdbcdbcacabc
   T:bcdbcdbca
*/

#include <iostream>
#include <string>

using namespace std;

int get_next1(string T,int next[])
{
    next[0] = -1;
    int k = -1;

    for (int i = 1; i < T.size(); i++)
    {
        while (k > -1 && T[k + 1] != T[i])///如果匹配到某一个不相等的时候,开始回溯
        {
            k = next[k];///回到next数组中记录的位置重新匹配
        }
        if (T[k + 1] == T[i] || k == -1)///如果字符一样,继续向前匹配
        {
            k++;
        }
        next[i] = k;///将最大匹配的值赋给next数组
    }
}

int get_next2(string T,int next[])
{// 求next函数的值,
    int i = 0;
    signed int j = -1;
    next[0] = -1;       // initialization
    while(i < T.size())     // 与T[0]字符的ASCII值比较,显然始终成立
    {
        if(j == -1 || T[i] == T[j])
        {
            ++i;
            ++j;
            next[i] = j;
        }
        else
            j = next[j];
    }
}

int main(int argc,char* argv[])
{

    string T;

    cout << "Please input Substring: ";
    cin >> T;
    int next[T.size()] = {0};
    get_next1(T,next);
    cout << "The next[] of substring T:";
    for(int i =0; i <T.size(); i++)
        cout << next[i] << " ";

    cout << endl;

    get_next2(T,next);
    cout << "The next[] of substring T:";
    for(int i =0; i <T.size(); i++)
        cout << next[i] << " ";

    cout << endl;
}

輸出

Please input Substring: bcdbcdbca
The get_next1 of substring T:-1 0 0 0 1 2 3 4 0
The get_next2 of substring T:-1 0 0 0 1 2 3 4 5

Process returned 0 (0x0)   execution time : 4.611 s
Press any key to continue.

KMP達成

#include <iostream>
#include <cstring>
using namespace std;


/*
    得到next数组
*/
void get_next(string T, int *next)
{
    int j, k;
    j = 0;
    k = -1;
    next[0] = -1;
    while(j <T.size())
    {
        if(k == -1 || T[j] == T[k])
        {
            j++;
            k++;
            next[j] = k;
        }
        else
        {
            k = next[k];
        }
    }
}

/*
    KMP算法
*/
int KMP(string S, string T, int *next)
{
    int i = 0, j = 0;
    get_next(T, next);
    int Len_S = S.size();
    int Len_T = T.size();

    while (i < Len_S && j < Len_T)
    {
        if (j == -1 || S[i] == T[j])
        {
            i++;
            j++;
        }
        else
        {
            j = next[j];
        }
    }
    if (j == Len_T)
    {
        cout << "Success patterned with shift " << i-j <<endl;
        return i - j;
    }
    else
    {
        cout << "Fail patterned" << endl;
        return -1;
    }
}

int main()
{
    string S,T;
    cin >> S ;
    cin >> T;
    int next[T.size()];
    int i;

    Get_Next(T, next);
    cout << "模式串的next的值为:";
    for (i = 0; i < T.size(); i++)
        cout << next[i] << " ";
    cout << endl;
    KMP(S, T, next);
}

輸出

cdbcbabcdbcdbcacabc
bcdbcdbca
模式串的next的值为:-1 0 0 0 1 2 3 4 5
Success patterned with shift 6

Process returned 0 (0x0)   execution time : 19.706 s
Press any key to continue.
公開された25元の記事 ウォン称賛23 ビュー10000 +

おすすめ

転載: blog.csdn.net/Secur17y/article/details/100585369