الگوریتم رابین کارپ (Rabin-Karp Algorithm) — به زبان ساده
در این مطلب، «الگوریتم رابین کارپ» (Rabin-Karp Algorithm) که برای جستجوی رشته و الگو استفاده میشود، مورد بررسی قرار گرفته و پیادهسازی آن در زبانهای برنامهنویسی گوناگون شامل ++C، «سی» (C)، «جاوا» (Java)، «پایتون» (Python)، «سی شارپ» (#C) و «پیاچپی» (PHP) انجام شده است.
الگوریتم رابین کارپ
فرض میشود که متن [text txt[0..n-1 و الگوی [pat[0..m-1 داده شده است. هدف نوشتن تابع جستجویی (char pat[], char txt[]) است که همه وقوعهای []pat در []txt را چاپ کند.
همچنین، فرض میشود که n > m است. مثال زیر در این راستا قابل توجه است.
Input: txt[] = "THIS IS A TEST TEXT" pat[] = "TEST" Output: Pattern found at index 10 Input: txt[] = "AABAACAADAABAABA" pat[] = "AABA" Output: Pattern found at index 0 Pattern found at index 9 Pattern found at index 12
الگوریتم تطبیق الگوی ساده، الگو را به صورت اسلایدی (کشویی) در متن جستجو میکند. پس از هر اسلاید، کاراکترها یکی یکی در قسمت کنونی بررسی میشوند و اگر مطابق با الگو بودند، پرینت میشوند. همچون الگوریتم جستجوی رشته ساده، الگوریتم رابین کارپ نیز الگو را یکی یکی اسلاید میکند. اما بر خلاف الگوریتم ساده، به جای خود الگو و خود متن، الگوریتم رابین کارپ مقدار هش الگو را با مقدار هش زیر رشته کنونی از متن مطابقت میدهد و اگر مقادیر هش با یکدیگر تطبیق داشته باشند، تطبیق کاراکتر به کاراکتر انجام میشود. بنابراین، الگوریتم رابین کارپ نیاز به محاسبه مقادیر هش برای رشتههای زیر دارد.
- خود الگو
- همه زیر رشتههای موجود در متن به طول m
از آنجا که نیاز به محاسبه موثر مقادیر هش برای همه زیررشتهها با اندازه m از متن است، باید یک تابع هش داشت که دارای مشخصاتی باشد که در ادامه بیان شده است. هش در هر جا به جایی (شیفت)، باید به طور موثری بر اساس مقادیر هش کنونی و کاراکتر بعدی در متن قابل محاسبه باشد. در واقع میتوان گفت ([hash(txt[s+1 .. s+m باید به طور کارایی از ([hash(txt[s .. s+m-1 و [txt[s+m قابل محاسبه باشد؛ یعنی [(hash(txt[s+1 .. s+m])= rehash(txt[s+m], hash(txt[s .. s+m-1 و rehash باید عملیات از درجه (O(1 باشد.
تابع هش توصیه شده توسط رابین و کارپ، یک مقدار صحیح را محاسبه میکند. مقدار صحیح برای یک رشته، یک مقدار عددی از رشته است. برای مثال، اگر همه کاراکترهای ممکن از ۱ تا ۱۰ هستند، مقدار عددی "122" برابر با ۱۲۲ خواهد بود. تعداد کاراکترهای ممکن بالاتر از ۱۰ است (عموما ۲۵۶) و طول الگو میتواند بزرگ باشد. بنابراین، مقادیر عددی را نمیتوان به صورت کاربردی به عنوان عدد صحیح ذخیره کرد. بنابراین، مقدار عددی با استفاده از «حساب ماژولار» (Modular Arithmetic) محاسبه میشود تا اطمینان حاصل شود که مقادیر هش را میتوان در یک متغیر صحیح ذخیره کرد (میتواند در کلمات حافظه جا شود). برای هش کردن دوباره (بازهش)، نیاز به خارج کردن قابل توجهترین رقم و افزودن کم اهمیتترین رقم جدید در مقدار هش است. بازهش کردن با استفاده از فرمول زیر انجام میشود.
hash( txt[s+1 .. s+m] ) = ( d ( hash( txt[s .. s+m-1]) – txt[s]*h ) + txt[s + m] ) mod q
hash( txt[s .. s+m-1] ): s مقدار هش در شیفت
hash( txt[s+1 .. s+m] ): (s+1 مقدار هش در شیفت بعدی (یا شیفت
d: تعداد کاراکترها در الفبا
q: یک عدد اول
h: d^(m-1)
عبارت بالا چگونه کار میکند؟
این یک راهکار ریاضیاتی ساده است که در آن، مقدار اعشاری پنجره کنونی بر اساس پنجره پیشین محاسبه میشود. برای مثال، طول الگو ۳ و رشته «۲۳۴۵۶» است. مقدار اولین پنجره (که ۲۳۴ است) برابر با «۲۳۴» محاسبه شده است. برای محاسبه پنجره بعدی یعنی «۳۴۵»، محاسبه ۵+۱۰*(۱۰۰*۲– ۲۳۴) انجام و نتیجه ۳۴۵ حاصل میشود.
الگوریتم رابین کارپ در ++C
1/* Following program is a C++ implementation of Rabin Karp
2Algorithm given in the CLRS book */
3#include <bits/stdc++.h>
4using namespace std;
5
6// d is the number of characters in the input alphabet
7#define d 256
8
9/* pat -> pattern
10 txt -> text
11 q -> A prime number
12*/
13void search(char pat[], char txt[], int q)
14{
15 int M = strlen(pat);
16 int N = strlen(txt);
17 int i, j;
18 int p = 0; // hash value for pattern
19 int t = 0; // hash value for txt
20 int h = 1;
21
22 // The value of h would be "pow(d, M-1)%q"
23 for (i = 0; i < M - 1; i++)
24 h = (h * d) % q;
25
26 // Calculate the hash value of pattern and first
27 // window of text
28 for (i = 0; i < M; i++)
29 {
30 p = (d * p + pat[i]) % q;
31 t = (d * t + txt[i]) % q;
32 }
33
34 // Slide the pattern over text one by one
35 for (i = 0; i <= N - M; i++)
36 {
37
38 // Check the hash values of current window of text
39 // and pattern. If the hash values match then only
40 // check for characters on by one
41 if ( p == t )
42 {
43 /* Check for characters one by one */
44 for (j = 0; j < M; j++)
45 {
46 if (txt[i+j] != pat[j])
47 break;
48 }
49
50 // if p == t and pat[0...M-1] = txt[i, i+1, ...i+M-1]
51 if (j == M)
52 cout<<"Pattern found at index "<< i<<endl;
53 }
54
55 // Calculate hash value for next window of text: Remove
56 // leading digit, add trailing digit
57 if ( i < N-M )
58 {
59 t = (d*(t - txt[i]*h) + txt[i+M])%q;
60
61 // We might get negative value of t, converting it
62 // to positive
63 if (t < 0)
64 t = (t + q);
65 }
66 }
67}
68
69/* Driver code */
70int main()
71{
72 char txt[] = "GEEKS FOR GEEKS";
73 char pat[] = "GEEK";
74 int q = 101; // A prime number
75 search(pat, txt, q);
76 return 0;
77}
78
79// This is code is contributed by rathbhupendra
الگوریتم رابین کارپ در C
1/* Following program is a C implementation of Rabin Karp
2Algorithm given in the CLRS book */
3#include<stdio.h>
4#include<string.h>
5
6// d is the number of characters in the input alphabet
7#define d 256
8
9/* pat -> pattern
10 txt -> text
11 q -> A prime number
12*/
13void search(char pat[], char txt[], int q)
14{
15 int M = strlen(pat);
16 int N = strlen(txt);
17 int i, j;
18 int p = 0; // hash value for pattern
19 int t = 0; // hash value for txt
20 int h = 1;
21
22 // The value of h would be "pow(d, M-1)%q"
23 for (i = 0; i < M-1; i++)
24 h = (h*d)%q;
25
26 // Calculate the hash value of pattern and first
27 // window of text
28 for (i = 0; i < M; i++)
29 {
30 p = (d*p + pat[i])%q;
31 t = (d*t + txt[i])%q;
32 }
33
34 // Slide the pattern over text one by one
35 for (i = 0; i <= N - M; i++)
36 {
37
38 // Check the hash values of current window of text
39 // and pattern. If the hash values match then only
40 // check for characters on by one
41 if ( p == t )
42 {
43 /* Check for characters one by one */
44 for (j = 0; j < M; j++)
45 {
46 if (txt[i+j] != pat[j])
47 break;
48 }
49
50 // if p == t and pat[0...M-1] = txt[i, i+1, ...i+M-1]
51 if (j == M)
52 printf("Pattern found at index %d \n", i);
53 }
54
55 // Calculate hash value for next window of text: Remove
56 // leading digit, add trailing digit
57 if ( i < N-M )
58 {
59 t = (d*(t - txt[i]*h) + txt[i+M])%q;
60
61 // We might get negative value of t, converting it
62 // to positive
63 if (t < 0)
64 t = (t + q);
65 }
66 }
67}
68
69/* Driver program to test above function */
70int main()
71{
72 char txt[] = "GEEKS FOR GEEKS";
73 char pat[] = "GEEK";
74 int q = 101; // A prime number
75 search(pat, txt, q);
76 return 0;
77}
الگوریتم رابین کارپ در جاوا
1// Following program is a Java implementation
2// of Rabin Karp Algorithm given in the CLRS book
3
4public class Main
5{
6 // d is the number of characters in the input alphabet
7 public final static int d = 256;
8
9 /* pat -> pattern
10 txt -> text
11 q -> A prime number
12 */
13 static void search(String pat, String txt, int q)
14 {
15 int M = pat.length();
16 int N = txt.length();
17 int i, j;
18 int p = 0; // hash value for pattern
19 int t = 0; // hash value for txt
20 int h = 1;
21
22 // The value of h would be "pow(d, M-1)%q"
23 for (i = 0; i < M-1; i++)
24 h = (h*d)%q;
25
26 // Calculate the hash value of pattern and first
27 // window of text
28 for (i = 0; i < M; i++)
29 {
30 p = (d*p + pat.charAt(i))%q;
31 t = (d*t + txt.charAt(i))%q;
32 }
33
34 // Slide the pattern over text one by one
35 for (i = 0; i <= N - M; i++)
36 {
37
38 // Check the hash values of current window of text
39 // and pattern. If the hash values match then only
40 // check for characters on by one
41 if ( p == t )
42 {
43 /* Check for characters one by one */
44 for (j = 0; j < M; j++)
45 {
46 if (txt.charAt(i+j) != pat.charAt(j))
47 break;
48 }
49
50 // if p == t and pat[0...M-1] = txt[i, i+1, ...i+M-1]
51 if (j == M)
52 System.out.println("Pattern found at index " + i);
53 }
54
55 // Calculate hash value for next window of text: Remove
56 // leading digit, add trailing digit
57 if ( i < N-M )
58 {
59 t = (d*(t - txt.charAt(i)*h) + txt.charAt(i+M))%q;
60
61 // We might get negative value of t, converting it
62 // to positive
63 if (t < 0)
64 t = (t + q);
65 }
66 }
67 }
68
69 /* Driver program to test above function */
70 public static void main(String[] args)
71 {
72 String txt = "GEEKS FOR GEEKS";
73 String pat = "GEEK";
74 int q = 101; // A prime number
75 search(pat, txt, q);
76 }
77}
78
79// This code is contributed by nuclode
الگوریتم رابین کارپ در پایتون
1# Following program is the python implementation of
2# Rabin Karp Algorithm given in CLRS book
3
4# d is the number of characters in the input alphabet
5d = 256
6
7# pat -> pattern
8# txt -> text
9# q -> A prime number
10
11def search(pat, txt, q):
12 M = len(pat)
13 N = len(txt)
14 i = 0
15 j = 0
16 p = 0 # hash value for pattern
17 t = 0 # hash value for txt
18 h = 1
19
20 # The value of h would be "pow(d, M-1)%q"
21 for i in xrange(M-1):
22 h = (h*d)%q
23
24 # Calculate the hash value of pattern and first window
25 # of text
26 for i in xrange(M):
27 p = (d*p + ord(pat[i]))%q
28 t = (d*t + ord(txt[i]))%q
29
30 # Slide the pattern over text one by one
31 for i in xrange(N-M+1):
32 # Check the hash values of current window of text and
33 # pattern if the hash values match then only check
34 # for characters on by one
35 if p==t:
36 # Check for characters one by one
37 for j in xrange(M):
38 if txt[i+j] != pat[j]:
39 break
40
41 j+=1
42 # if p == t and pat[0...M-1] = txt[i, i+1, ...i+M-1]
43 if j==M:
44 print "Pattern found at index " + str(i)
45
46 # Calculate hash value for next window of text: Remove
47 # leading digit, add trailing digit
48 if i < N-M:
49 t = (d*(t-ord(txt[i])*h) + ord(txt[i+M]))%q
50
51 # We might get negative values of t, converting it to
52 # positive
53 if t < 0:
54 t = t+q
55
56# Driver program to test the above function
57txt = "GEEKS FOR GEEKS"
58pat = "GEEK"
59q = 101 # A prime number
60search(pat,txt,q)
61
62# This code is contributed by Bhavya Jain
الگوریتم رابین کارپ در #C
1// Following program is a C# implementation
2// of Rabin Karp Algorithm given in the CLRS book
3using System;
4public class GFG
5{
6 // d is the number of characters in the input alphabet
7 public readonly static int d = 256;
8
9 /* pat -> pattern
10 txt -> text
11 q -> A prime number
12 */
13 static void search(String pat, String txt, int q)
14 {
15 int M = pat.Length;
16 int N = txt.Length;
17 int i, j;
18 int p = 0; // hash value for pattern
19 int t = 0; // hash value for txt
20 int h = 1;
21
22 // The value of h would be "pow(d, M-1)%q"
23 for (i = 0; i < M-1; i++)
24 h = (h*d)%q;
25
26 // Calculate the hash value of pattern and first
27 // window of text
28 for (i = 0; i < M; i++)
29 {
30 p = (d*p + pat[i])%q;
31 t = (d*t + txt[i])%q;
32 }
33
34 // Slide the pattern over text one by one
35 for (i = 0; i <= N - M; i++)
36 {
37
38 // Check the hash values of current window of text
39 // and pattern. If the hash values match then only
40 // check for characters on by one
41 if ( p == t )
42 {
43 /* Check for characters one by one */
44 for (j = 0; j < M; j++)
45 {
46 if (txt[i+j] != pat[j])
47 break;
48 }
49
50 // if p == t and pat[0...M-1] = txt[i, i+1, ...i+M-1]
51 if (j == M)
52 Console.WriteLine("Pattern found at index " + i);
53 }
54
55 // Calculate hash value for next window of text: Remove
56 // leading digit, add trailing digit
57 if ( i < N-M )
58 {
59 t = (d*(t - txt[i]*h) + txt[i+M])%q;
60
61 // We might get negative value of t, converting it
62 // to positive
63 if (t < 0)
64 t = (t + q);
65 }
66 }
67 }
68
69 /* Driver program to test above function */
70 public static void Main()
71 {
72 String txt = "GEEKS FOR GEEKS";
73 String pat = "GEEK";
74 int q = 101; // A prime number
75 search(pat, txt, q);
76 }
77}
78
79// This code is contributed by PrinciRaj19992
الگوریتم رابین کارپ در PHP
1<?php
2// Following program is a PHP
3// implementation of Rabin Karp
4// Algorithm given in the CLRS book
5
6// d is the number of characters
7// in the input alphabet
8$d = 256;
9
10/* pat -> pattern
11 txt -> text
12 q -> A prime number
13*/
14function search($pat, $txt, $q)
15{
16 $M = strlen($pat);
17 $N = strlen($txt);
18 $i; $j;
19 $p = 0; // hash value
20 // for pattern
21 $t = 0; // hash value
22 // for txt
23 $h = 1;
24 $d =1;
25
26 // The value of h would
27 // be "pow(d, M-1)%q"
28 for ($i = 0; $i < $M - 1; $i++)
29 $h = ($h * $d) % $q;
30
31 // Calculate the hash value
32 // of pattern and first
33 // window of text
34 for ($i = 0; $i < $M; $i++)
35 {
36 $p = ($d * $p + $pat[$i]) % $q;
37 $t = ($d * $t + $txt[$i]) % $q;
38 }
39
40 // Slide the pattern over
41 // text one by one
42 for ($i = 0; $i <= $N - $M; $i++)
43 {
44
45 // Check the hash values of
46 // current window of text
47 // and pattern. If the hash
48 // values match then only
49 // check for characters on
50 // by one
51 if ($p == $t)
52 {
53 // Check for characters
54 // one by one
55 for ($j = 0; $j < $M; $j++)
56 {
57 if ($txt[$i + $j] != $pat[$j])
58 break;
59 }
60
61 // if p == t and pat[0...M-1] =
62 // txt[i, i+1, ...i+M-1]
63 if ($j == $M)
64 echo "Pattern found at index ",
65 $i, "\n";
66 }
67
68 // Calculate hash value for
69 // next window of text:
70 // Remove leading digit,
71 // add trailing digit
72 if ($i < $N - $M)
73 {
74 $t = ($d * ($t - $txt[$i] *
75 $h) + $txt[$i +
76 $M]) % $q;
77
78 // We might get negative
79 // value of t, converting
80 // it to positive
81 if ($t < 0)
82 $t = ($t + $q);
83 }
84 }
85}
86
87// Driver Code
88$txt = "GEEKS FOR GEEKS";
89$pat = "GEEK";
90$q = 101; // A prime number
91search($pat, $txt, $q);
92
93// This code is contributed
94// by ajit
95?>
خروجی قطعه کدهای بالا به صورت زیر است.
Pattern found at index 0 Pattern found at index 10
زمان اجرای میانگین و بهترین حالت برای الگوریتم رابین کارپ از درجه (O(n+m و بدترین حالت از درجه (O(nm است. بدترین حالت از الگوریتم رابین کارپ هنگامی به وقوع میپیوندد که همه کاراکترهای الگو و متن مشابه باشند، به طوری که مقادیر هش همه زیر مجموعههای []txt با مقدار هش []pat تطبیق پیدا کنند. برای مثال، ”pat[] = “AAA و ”txt[] = “AAAAAAA.
اگر نوشته بالا برای شما مفید بوده است، آموزشهای زیر نیز به شما پیشنهاد میشوند:
- مجموعه آموزشهای برنامه نویسی
- آموزش ساختمان دادهها
- مجموعه آموزشهای ساختمان داده و طراحی الگوریتم
- جستجوی الگو (Pattern Searching) — به زبان ساده
- تطبیق رشته فازی در پایتون — راهنمای کاربردی
- کاربردهای هوش مصنوعی در بیوانفورماتیک — به زبان ساده
- متن کاوی (Text Mining) — به زبان ساده
^^