AlgoVerse

الگوریتم KMP (کنوت–موریس–پرات)

تطبیق رشته در O(n + m): هیچ نویسه‌ای از متن دوباره خوانده نمی‌شود؛ بعد از ناهمخوانی، تابع پیشوند می‌گوید الگو چقدر جلو برود.

روش ساده بعد از ناهمخوانی الگو را فقط یک خانه جلو می‌برد و دوباره از اول مقایسه می‌کند. ولی ما از قبل می‌دانیم q نویسه‌ی آخر متن با P[0..q−1] برابر بوده‌اند. پس:

ادامه‌ی توضیح ↓
ورودی:
T="bacbabababab…" · P="ababa"خروجی PDF

الگوی ababa در bacbababababa سه بار پیدا می‌شود، در جابه‌جایی‌های ۴، ۶ و ۸؛ بعد از رخداد اول، KMP هم‌پوشانی را نگه می‌دارد و از اول شروع نمی‌کند.

  1. def kmp_match(T, P):
  2. n, m = len(T), len(P)
  3. pi = prefix_function(P)
  4. matches = []
  5. q = 0 # how many characters of P match the text ending here
  6. shift = 0 # where P sits under T, for the picture
  7. for i in range(n):
  8. while q > 0 and P[q] != T[i]:
  9. q = pi[q - 1]
  10. if P[q] == T[i]:
  11. q = q + 1
  12. if q == m:
  13. matches.append(i - m + 1)
  14. q = pi[q - 1]
  15. shift = i - q + 1
  16. return matches
  17. def prefix_function(P):
  18. pi = [0] * len(P)
  19. k = 0
  20. for q in range(1, len(P)):
  21. while k > 0 and P[k] != P[q]:
  22. k = pi[k - 1]
  23. if P[k] == P[q]:
  24. k = k + 1
  25. pi[q] = k
  26. return pi

ناوردا: بعد از هر گام، P[0..q−1] بلندترین پیشوندی از P است که با انتهای T[0..i] برابر است.

شروع اجرا

0123456789101112
bacbababababa
ababa
pi—
matches—

متغیرهای محلی

T'bacbababababa'
P'ababa'

نارنجی = در همین گام عوض شد

Call stack

  1. kmp_match()خط 1
گام ۱ از ۱۱۵
خط سیاه = match_char, fall_back · خط نارنجی = گام کلیدیmatch_char: 0/10 · fall_back: 0/1 · found: 0/3
    توضیح

    ایده

    روش ساده بعد از ناهمخوانی الگو را فقط یک خانه جلو می‌برد و دوباره از اول مقایسه می‌کند. ولی ما از قبل می‌دانیم q نویسه‌ی آخر متن با P[0..q−1] برابر بوده‌اند. پس:

    • اگر T[i] با P[q] بخواند، q یکی زیاد می‌شود.
    • اگر نخواند، q را به π[q − 1] (بلندترین مرزِ قسمت جورشده) برمی‌گردانیم و دوباره امتحان می‌کنیم؛ متن دوباره خوانده نمی‌شود.
    • اگر q = m شد، الگو پیدا شده؛ با q = π[m − 1] ادامه می‌دهیم تا رخدادهای هم‌پوشان هم پیدا شوند.

    هزینه

    i فقط جلو می‌رود و هر برگشت q را کم می‌کند؛ پس کل کار O(n) به‌اضافه‌ی O(m) برای ساختن π.

    در trace به چه چیزی نگاه کنی

    • اشاره‌گر i روی متن فقط جلو می‌رود؛ الگو زیر متن با جابه‌جایی فعلی کشیده شده و خانه‌های پررنگش جور شده‌اند.