الگوریتم بایتپ الگوریتم بایتپ، الگوریتمی تقریبی برای تشخیص تطابق دو رشته است. الگوریتم پیش رو، مشخص میکند که در متن ورودی، زیر رشتهای وجود دارد که "تقریباً" با الگوی مورد نظر داده شده، برابر باشد. در این تعریف، با مفهوم فاصله ی لونشتین (levenshtein)—در صورتی که زیررشته و الگوی مد نظر، فاصله از یکدیگر داشته باشند، الگوریتم آنها را برابر در نظر میگیرد—برابری تقریبی تعریف میشود. الگوریتم بایتپ، با پیش پردازش تعدادی ماسک بیتی، که هر کدام دارای یک بیت به ازای هر عضو الگو است، شروع می گردد. پس از آن الگوریتم اکثر عملیات خود را با عملگرهای دودویی انجام میدهد، که بسیار سریع میباشند.
با توجه به ساختمان داده ی مورد نیاز الگوریتم، این الگوریتم زمانی که طول الگوی ما، از عدد ثابتی کمتر باشد،(معمولاً زمانی که کوچکتر از واحد کلمهٔ کامپیوتر مورد استفاده باشد) بهترین عملکرد خود را دارد، علاوه بر آن، زمانی که تعداد حروف به کار رفته، کم باشند نیز عملکرد الگوریتم مناسب است. پیچیدگی محاسباتی الگوریتم برای الفبای با تعداد حروف ثابت و کلمه با طول و متنی با طول ، مستقل از ساختار متن و الگو، از میباشد.
بالینت دملکی (Bálint Dömölki)، الگوریتم بایتپ در حالت جستجوی دقیق را، در سال ۱۹۶۴ اختراع نمود و شیامسوندر (R. K. Shyamasundar) آن را در سال ۱۹۷۷ تعمیم داد.
الگوریتم بایتپ، برای جستجوی دقیق الگو در متن، در حالت کلی، در زیر با زبان C پیادهسازی شدهاست.
#include <stdlib.h>
#include <string.h>
typedef char BIT; /* needs only to hold the values 0 and 1 */
const char *bitap_search(const char *text, const char *pattern)
{
const char *result = NULL;
int m = strlen(pattern);
BIT *R;
int i, k;
if (pattern[0] == '\0') return text;
/* Initialize the bit array R */
R = malloc((m+1) * sizeof *R);
R[0] = 1;
for (k=1; k <= m; ++k)
R[k] = 0;
for (i=0; text[i] != '\0'; ++i) {
/* Update the bit array. */
for (k=m; k>= 1; --k)
R[k] = R[k-1] && (text[i] == pattern[k-1]);
if (R[m]) {
result = (text+i - m) + 1;
break;
}
}
free(R);
return result;
}
الگوریتم بایتپ، همان طور که در برنامهٔ بالا می بینید، به خاطر تطابق طبیعی خود با عملیات دودویی، از دیگر الگوریتمهای معروف جستجوی رشته، متمایز میباشد. توجه کنید که در مورد پیادهسازی بالا، بر خلاف تصور، هر بیت با مقدار ۰ نشان دهندهٔ یک تطابق، و هر بیت با مقدار ۱ نشان دهندهٔ یک عدم تطابق میباشد. میتوان الگوریتم مشابهی با تصور شهودی از ۰ و ۱ نوشت، اما در این حالت ما باید دستور R |= ۱
را به حلقهٔ داخلی اضافه کنیم. در این پیاده سازی، ما از این واقعیت که شیفت به چپ یک عدد، در سمت راست آن عدد، صفر اضافه می نماید به صورت بهینه استفاده کرده ایم.
توجه نمایید در پیادهسازی کلی برای تبدیل شرط (text[i] == pattern[k-۱])
به یک عملگر دودویی نیاز به یک ماسک دودویی CHAR_MAX
داریم.
#include <string.h>
#include <limits.h>
const char *bitap_bitwise_search(const char *text, const char *pattern)
{
int m = strlen(pattern);
unsigned long R;
unsigned long pattern_mask[CHAR_MAX+1];
int i;
if (pattern[0] == '\0') return text;
if (m> 31) return "The pattern is too long!";
/* Initialize the bit array R */
R = ~1;
/* Initialize the pattern bitmasks */
for (i=0; i <= CHAR_MAX; ++i)
pattern_mask[i] = ~0;
for (i=0; i <m; ++i)
pattern_mask[pattern[i]] &= ~(1UL <<i);
for (i=0; text[i] != '\0'; ++i) {
/* Update the bit array */
R |= pattern_mask[text[i]];
R <<= 1;
if (0 == (R & (1UL <<m)))
return (text + i - m) + 1;
}
return NULL;
}
برای تعمیم الگوریتم بایتپ، به جستجوگری فازی در متن، آرایهٔ بیتی R باید به یک آرایهٔ دوبعدی تبدیل شود. در این صورت، به جای آرایهٔ تک بعدی R که متناسب با طول متن متغیر بود، k آرایهٔ متفاوت با نامهای R۱..k در نظر گرفته شود. آرایهٔ Ri نمایشی از پیشوندهای الگوی مدنظر که به یک پسوند دلخواه متن موجود با حداکثر i خطا را، در خود نگاه می دارد. در این کد، یک خطا میتواند یک درج، یک پاک کردن یا یک جایگزین کردن کاراکتری دلخواه باشد. برای اطلاعات بیشتر به فاصله ی لونشتین (levenshtein) مراجعه نمایید.
پیادهسازی زیر با استفاده از الگوریتم بایتپ، با توجه به تطابق فازی، اولین زیر رشتهای که حداکثر k خطا را دربردارد، بر خواهد گرداند. هر چند در کد، تنها به جایگزینی توجه شدهاست و حذف و درج در نظر گرفته نشدهاست.(در واقع فاصله ی همینگ در نظر گرفته شدهاست)
#include <stdlib.h>
#include <string.h>
#include <limits.h>
const char *bitap_fuzzy_bitwise_search(const char *text, const char *pattern, int k)
{
const char *result = NULL;
int m = strlen(pattern);
unsigned long *R;
unsigned long pattern_mask[CHAR_MAX+1];
int i, d;
if (pattern[0] == '\0') return text;
if (m> 31) return "The pattern is too long!";
/* Initialize the bit array R */
R = malloc((k+1) * sizeof *R);
for (i=0; i <= k; ++i)
R[i] = ~1;
/* Initialize the pattern bitmasks */
for (i=0; i <= CHAR_MAX; ++i)
pattern_mask[i] = ~0;
for (i=0; i <m; ++i)
pattern_mask[pattern[i]] &= ~(1UL <<i);
for (i=0; text[i] != '\0'; ++i) {
/* Update the bit arrays */
unsigned long old_Rd1 = R[0];
R[0] |= pattern_mask[text[i]];
R[0] <<= 1;
for (d=1; d <= k; ++d) {
unsigned long tmp = R[d];
/* Substitution is all we care about */
R[d] = (old_Rd1 & (R[d] | pattern_mask[text[i]])) <<1;
old_Rd1 = tmp;
}
if (0 == (R[k] & (1UL <<m))) {
result = (text+i - m) + 1;
break;
}
}
free(R);
return result;
}
برخی دیگر از الگوریتمهایی که برای جستجوی یک الگو در متن استفاده میشوند عبارتند از KMP، RKS، BMS.