Computer >> Máy Tính >  >> Lập trình >> Lập trình

Thuật toán Aho-Corasick


Thuật toán này hữu ích để tìm tất cả các lần xuất hiện của tất cả các tập hợp từ khóa đã cho. Nó là một loại thuật toán đối sánh từ điển. Nó sử dụng cấu trúc cây bằng cách sử dụng tất cả các từ khóa. Sau khi tạo cây, nó sẽ cố gắng chuyển đổi cây như một động cơ tự động để thực hiện việc tìm kiếm trong thời gian tuyến tính. Có ba giai đoạn khác nhau của Thuật toán Aho-Corasick.

Đây là Đi tới, Không đạt, Đầu ra . Trong giai đoạn bắt đầu, nó làm cho cây bằng cách sử dụng tất cả các từ khóa. Trong giai đoạn tiếp theo hoặc trong Giai đoạn Thất bại, nó cố gắng tìm ra sự chuyển đổi ngược lại để có được một hậu tố thích hợp của một số từ khóa. Trong giai đoạn đầu ra, đối với mọi trạng thái ‘s’ của automaton, nó sẽ tìm thấy tất cả các từ kết thúc ở trạng thái ‘s’.

Độ phức tạp về thời gian của thuật toán này là:O (N + L + Z), trong đó N là độ dài của văn bản, L là độ dài của các từ khóa và Z là một số kết quả phù hợp.

Đầu vào và Đầu ra

Input:
A set of patterns: {their, there, answer, any, bye}
The main string: “isthereanyanswerokgoodbye”
Output:
Word there location: 2
Word any location: 7
Word answer location: 10
Word bye location: 22

Thuật toán

buildTree (patternList, size)

Đầu vào - Danh sách tất cả các mẫu và kích thước của danh sách

Đầu ra - Tạo bản đồ chuyển tiếp để tìm các mẫu

Begin
   set all elements of output array to 0
   set all elements of fail array to -1
   set all elements of goto matrix to -1
   state := 1       //at first there is only one state.

   for all patterns ‘i’ in the patternList, do
      word := patternList[i]
      present := 0
      for all character ‘ch’ of word, do
         if goto[present, ch] = -1 then
            goto[present, ch] := state
            state := state + 1
         present:= goto[present, ch]
      done
      output[present] := output[present] OR (shift left 1 for i times)
   done

   for all type of characters ch, do
      if goto[0, ch] ≠ 0 then
         fail[goto[0,ch]] := 0
         insert goto[0, ch] into a Queue q.
   done

   while q is not empty, do
      newState := first element of q
      delete from q.
      for all possible character ch, do
         if goto[newState, ch] ≠ -1 then
            failure := fail[newState]
            while goto[failure, ch] = -1, do
               failure := goto[failure, ch]
            done

            fail[goto[newState, ch]] = failure
            output[goto[newState, ch]] :=output[goto[newState,ch]] OR output[failure]
            insert goto[newState, ch] into q.
      done
   done
   return state
End

getNextState (presentState, nextChar)

Đầu vào - trạng thái hiện tại và ký tự tiếp theo để xác định trạng thái tiếp theo

Đầu ra : trạng thái tiếp theo

Begin
   answer := presentState
   ch := nextChar

   while goto[answer, ch] = -41, do
      answer := fail[answer]
   done
   return goto[answer, ch]
End

patternSearch (patternList, size, text)

Đầu vào - Danh sách các mẫu, kích thước của danh sách và văn bản chính

Đầu ra - Các chỉ mục của văn bản nơi tìm thấy các mẫu

Begin
   call buildTree(patternList, size)
   presentState := 0

   for all indexes of the text, do
      if output[presentState] = 0
         ignore next part and go for next iteration
      for all patterns in the patternList, do
         if the pattern found using output array, then
            print the location where pattern is present
      done
   done
End

Ví dụ

#include <iostream>
#include <queue>
#define MAXS 500    //sum of the length of all patterns
#define MAXC 26     //as 26 letters in alphabet
using namespace std;

int output[MAXS];
int fail[MAXS];
int gotoMat[MAXS][MAXC];

int buildTree(string array[], int size) {
   for(int i = 0; i<MAXS; i++)
      output[i] = 0;    //all element of output is 0

   for(int i = 0; i<MAXS; i++)
      fail[i] = -1;    //all element of failure array is -1

   for(int i = 0; i<MAXS; i++)
      for(int j = 0; j<MAXC; j++)
         gotoMat[i][j] = -1;    //all element of goto matrix is -1

   int state = 1;    //there is only one state

   for (int i = 0; i < size; i++) {    //make trie structure for all pattern in array
      //const string &word = array[i];
      string word = array[i];
      int presentState = 0;

      for (int j = 0; j < word.size(); ++j) {    //all pattern is added
         int ch = word[j] - 'a';
         if (gotoMat[presentState][ch] == -1)    //ic ch is not present make new node
            gotoMat[presentState][ch] = state++;    //increase state
            presentState = gotoMat[presentState][ch];
      }
      output[presentState] |= (1 << i); //current word added in the output
   }

   for (int ch = 0; ch < MAXC; ++ch)   //if ch is not directly connected to root
      if (gotoMat[0][ch] == -1)
         gotoMat[0][ch] = 0;

         queue<int> q;

   for (int ch = 0; ch < MAXC; ++ch) {    //node goes to previous state when fails
      if (gotoMat[0][ch] != 0) {
         fail[gotoMat[0][ch]] = 0;
         q.push(gotoMat[0][ch]);
      }
   }

   while (q.size()) {
      int state = q.front();    //remove front node
      q.pop();

      for (int ch = 0; ch <= MAXC; ++ch) {
         if (gotoMat[state][ch] != -1) {    //if goto state is present
            int failure = fail[state];
            while (gotoMat[failure][ch] == -1)    //find deepest node with proper suffix
               failure = fail[failure];
            failure = gotoMat[failure][ch];
            fail[gotoMat[state][ch]] = failure;
            output[gotoMat[state][ch]] |= output[failure];   // Merge output values
            q.push(gotoMat[state][ch]);    //add next level node to the queue
         }
      }
   }
   return state;
}

int getNextState(int presentState, char nextChar) {
   int answer = presentState;
   int ch = nextChar - 'a'; //subtract ascii of 'a'

   while (gotoMat[answer][ch] == -1) //if go to is not found, use fail function
      answer = fail[answer];
   return gotoMat[answer][ch];
}

void patternSearch(string arr[], int size, string text) {
   buildTree(arr, size);    //make the trie structure
   int presentState = 0;    //make current state as 0

   for (int i = 0; i < text.size(); i++) {    //find all occurances of pattern
      presentState = getNextState(presentState, text[i]);
      if (output[presentState] == 0)    //if no match continue;
      for (int j = 0; j < size; ++j) {   //matching found and print words
         if (output[presentState] & (1 << j)) {
            cout << "Word " << arr[j] << " location: " << i - arr[j].size() + 1 << endl;
         }
      }
   }
}

int main() {
   string arr[] = {"their", "there", "answer", "any", "bye"};
   string text = "isthereanyanswerokgoodbye";
   int k = sizeof(arr)/sizeof(arr[0]);
   patternSearch(arr, k, text);
   return 0;
}

Đầu ra

Word there location: 2
Word any location: 7
Word answer location: 10
Word bye location: 22