kmp 알고리즘에서 preprocessing(전처리) 과정에 관한 질문입니다.

canuyes의 이미지

안녕하세요?
현재 kmp알고리즘을 공부중에 있는 학생입니다.
kmp알고리즘을 공부중 전처리과정(preprocessing)의 구현에 관한 어려움믈 겪고 있어 질문남깁니다.

제가 공부중인 서적과 다수의 웹자료에 전처리과정은 아래와 같이 구현되어있습니다.

void preprocess(char* pattern,int* table){
     int len=strlen(pattern);
     int i=0,j=-1;
     table[0]=-1;
     while(i<len){
                  while(j>-1&&pattern[i]!=pattern[j]){
                                                      j=table[j];
                  }
                  i++;j++;
                  table[i]=j;
     }
     return;
}

3시간 가량 생각해보고 고민해보았는데 코드가 이해가 되질않네요..
자괴감만 커져 갑니다...ㅠㅠ
strcmp등을 이용하여 직접 접두부를 찾는 방법도 생각해보았지만
그런 방법을 선택시에 위의 코드보다 복잡도가 크게 증가한다고 하네요...

구글링중 다음 링크하단에서 꽤나 충실한 설명을 보았지만
http://211.228.163.31/30stair/KMP_DOC1/KMP_DOC1.php?pname=KMP_DOC1
부족한 능력 탓인지 이해가 잘 되지 않네요...

혹시 kmp 알고리즘의 전처리과정의 알고리즘에 대해 알려주실수 있으신가요?ㅜㅜ

이제 곧 점심시간이라 점심전에 올려봅니다 ㅠㅠ

익명 사용자의 이미지

제가 이해한걸 쓴 글입니다.
http://dol9.tistory.com/122

전처리 과정이라는게,
어느 위치에서 틀렸을때 어디로 이동할거냐를 정하는 건데,
뭉탱뭉탱 움직이기위해 prefix, suffix를 사용한다고 생각했습니다.

도움이 됐으면 좋겠네요

canuyes의 이미지

답변 감사드립니다.

그런데 전 kmp의 진행과정보다는 kmp의 preprocessing의 작동원리가 궁금합니다. ㅜㅜ
링크에는 preprocessing 자체에 초점이 맞추어져 있지는 않는것 같네요...
계속 구글링 하던중
http://www.iti.fh-flensburg.de/lang/algorithmen/pattern/kmpen.htm
에서 나름 만족할만한 설명을 찾았습니다.
하지만 아직 구현된 코드가 맞는 건 알겠으나, 머리속에서 정리되서 스스로 작성할 수 있을 정도로 이해한것은 아닌것같습니다.
추후에 혹시 preprocessing 함수에 대해 더 설명해주 실 수 있으시다면 설명해주세요..
답변 정말 감사드립니다. ㅠㅠ

ant35rookie의 이미지

안녕하세요,
1년 전 글이지만 답글을 달아봅니다

fail table의 아이디어는
"pattern vs source text"를 비교함으로써 알게 되는 것을 "source text"가 없는 상황에서도
"pattern vs pattern"을 통해 미리 예측하는 것으로 생각하고 있습니다

소스에서 보면 아무래도 j = table[j] 부분이 제일 난해한 것 같은데요
예제 없이 이해하기가 쉽지 않은 것 같습니다

1. 먼저 아래와 같은 패턴을 선정하고 미리 fail table을 계산한 결과입니다
① 패턴 BABBACAA
② fail table
0 1 2 3 4 5 6 7 8 : Array index
B A B B A C A A : Pattern
-1 0 0 1 1 2 ? : border

########################################################################################
border == 경계 란?
해당 문자 바로 전까지의 pattern 에서 prefix & postfix가 최대로 겹치는 넓이로써
pattern이 dismatch 되었을 때, 새로 정해지는 pattern의 index 입니다
비교대상 text의 index가 1씩 증가함에 있어서 border가 클 수록 pattern의 시작 index가 커지며
이로 인해 다음 비교 시, 0~index-1 까지를 skip 하게 됩니다
########################################################################################

2. "A"에 대한 경계값 구하기를 예로 든다면, 아래와 같은 상황일 것입니다
(1) matching fail 발생
B A B B A C | A
B A B B A C | X

(2) A에서 매칭 되지 않았다면 BABBAC 까지는 매칭 되었음을 뜻하며 이는 소스에서 A의 경계값을 구하는 동안에 i==5인 이유가 됩니다
A의 경계값으로 BABBAC의 접두사 및 접미사의 일치부분만 찾으면 됩니다
이 때, 이미 구해진 C의 경계값을 이용하는데 경계값은 순차적으로 계산되기 때문에 C의 경계값도 이미 정해진 상태이며 "2"입니다
C의 경계값을 이용하는 이유는 경계값을 최대의 길이로 선정해야 하기 때문입니다
즉, A의 경계값으로 C의 경계값에 1을 더한 길이 3인 값을 찾는 것인데 그 이유는 맨 아래에 예로 들었습니다

(3) 그런데 길이가 3인 경계값을 구하다보면 BAB vs BAC 가 다름을 확인하게 됩니다
아래의 소스가 그 역할을 수행하며 이는 곧 A의 경계값의 크기가 3이 될 수 없음을 의미합니다

while ( j > -1 && pattern[i] != pattern[j] )
j = table[j]

(4) 소스코드를 보면 일치한다고 생각했던 BA"B" vs BA"C" 마저 틀려버렸고 이는 A의 경계값의 크기가 3이 될 수 없음을 뜻합니다
즉, BA"B"가 dismatch 되었을 때를 가정하고 다시 경계값을 계산해야 합니다
j = table[j] 코드를 통해 j는 2가 되고 3번째 "B"의 경계값을 이용합니다
(사실, 경계값이란 main함수에서 pattern의 index를 reset하는 역할이기 때문에
A가 dismatch일 때, BAB"B"의 4번째 문자에서 패턴매칭을 다시 시작하지 못함을 의미합니다 )

#step 1 : A에서 dismatch 발생 (i == 5, j == 2)
B A B B A C | A
B A B B A C | X

#step 2 : pattern[5] != pattern[2] --> j = table[2] (==0)
........ B A | B
B A B B A | C

#step 3 : pattern[5] != pattern[0] --> j = table[0] (==-1)
.............. | B
B A B B A | C

#step 4 : j++, i++

#step 5 : j=-1 , table[6] = -1

(6) 미리 구해진 fail table에 의해서 j=0 이 되고 while문을 통해 pattern[5] != pattern[0] 가 성립합니다
이제 j=-1 이 되며 j++를 통해 table[i]= 0 이 저장되게 됩니다
이로써 A의 경계값은 0이 되며 이는 A에서 disamtch 되었을 때, 패턴의 처음부터 다시 검사해야 함을 뜻합니다

###########################################
경계값이 최대여야 하는 이유

A B A B A B C B : pattern
A B A B A B A B C B : text

# 경계값이 최대일 경우
..... A B A B A B C B : pattern
A B A B A B A B C B : text

# 경계값의 최대가 아닐 경우, text의 두 번째 A부터 시작하는 pattern을 놓치게 됨
........... A B A B A B C B : pattern
A B A B A B A B C B : text
###########################################

오늘도 조금 더 배우는 하루

익명 사용자의 이미지

asd

익명 사용자의 이미지

KMP 전처리 작업이 pattern mismatch 시 인덱스를 얼마만큼 조정할 것인가 라는 것만 이해하면
나머지는 스스로 생각해 보셔도 똑같은 알고리즘 나올 듯해요.
알고리즘은 스스로 생각해 보는 게 실력 향상법임.

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.