Kmp

จาก Theory Wiki
ไปยังการนำทาง ไปยังการค้นหา

หน้านี้สำหรับอธิบายการทำงานของอัลกอริทึม Knuth–Morris–Pratt string matching

อัลกอริทึมรับ string P (pattern) และสตริง S จากนั้นหา P ใน S

อัลกอริทึมจะทยอย match P ใน S ไปเรื่อย ๆ เช่นถ้าเราต้องการหา ABABACA ใน ABABABACA อัลกอริทึมจะเริ่ม match ตั้งแต่ตำแหน่งแรก ดังด้านล่าง

S:ABABABACA
P:A
S:ABABABACA
P:AB
S:ABABABACA
P:ABA
S:ABABABACA
P:ABAB
S:ABABABACA
P:ABABA

จนกระทั่ง match ไม่ได้

S:ABABA*B*ACA
P:ABABA*C*

สิ่งที่อัลกอริทึมทราบคือ ณ ตำแหน่งปัจจุบัน match มาได้ถึง ABABA แล้ว คำถามคือจะเอาข้อมูลนี้ไปใช้อย่างไรได้บ้าง?

สังเกตว่าถ้าเอา P มาเทียบกับตัวเอง โดยพิจารณาเฉพาะ prefix ABABA ที่ถูก match ไปแล้ว เราจะพบว่า:

P:ABABA|
  ..ABA|
  ....A|

ดังนั้นการที่จะขยับจุดเริ่มต้นของจุดที่จะตรวจสอบ pattern P ใน S ให้น้อยที่สุด คือ ขยับไปสองตำแหน่ง นั่งคือ ดูจากความยาวของ ABABA ลบด้วยความยาวของ ABA แล้วสองสตริงนี้คืออะไร?

สังเกตว่า ถ้าเรา match มาได้ถึง ABABA แล้ว เราจะกระโดดไปน้อยสุด เราต้องหา suffix ที่ยาวที่สุดของ ABABA ที่เป็น prefix ของ ABAB ด้วยนั่งเอง ซึ่งในกรณีนี้คือ ABA ค่าของความยาวนี้จะเรียกว่า prefix function ถ้าเรามีค่านี้แล้วการจะ implement algorithm KMP ก็จะสามารถเขียนได้โดยง่าย

prefix function

ส่วนที่ยุ่งยากที่สุดคือการคำนวน prefix function (, เพื่อความง่ายต่อไปจะเรียกว่า T), ซึ่งมีนิยามดังนี้

  • T(j) เป็นความยาวของ prefix ของ P[1...(j-1)] ที่เป็น suffix ของ P[1...j] ฟังก์ชันนี้จะใช้ในการกระโดดเมื่อเกิดการจับคู่ไม่ได้

ด้านล่างแสดงตัวอย่างของค่า T(j) ต่าง ๆ ของสตริง ABABACA

  P : ABABACA
T(2): AB
      --         T(2) = 0

T(3): ABA
      --A        T(3) = 1

T(4): ABAB 
      --AB       T(4) = 2

T(5): ABABA 
      --ABA      T(5) = 3

T(6): ABABAC
      ------     T(6) = 0

ในการคำนวณนั้นเราจะเก็บไล่พิจารณา prefix ต่าง ๆ ของ P ไปตามลำดับ ตอนที่พิจารณา P[1..j] เราจะคำนวณ T[j] ไปด้วย โดยเรา assume ว่าเราคำนวณ T[2], T[3], ..., T[j-1] มาแล้ว

ดึงข้อมูลจาก "http://158.108.32.49/wiki/index.php?title=Kmp&oldid=43735"