V â Minh P hæ Bæ m«n K hoa häc m¸ y tÝnh
1
CHUI VÀ CÁC BÀI TOÁN TRÊN CHUỖI
Chui (string) là mt loi dữ liệu cơ bản tờng được sử dụng trong rất nhiều
các hthống và thành phần bản trong các hthống xử văn bản (word-
processing-system), c hthống này cung cấp cho ta rất nhiều khả năng đxử
văn bản. Ngoài ra mt vài các h thống đồ hoạ trên máy tính (computer
graphics system) biểu diễn các hình ảnh như là các chuỗi nhị phân.
Các thao tác trên chuỗi chúng ta thường gặp một số các phép toán cơ bản như:
- Phép tìm kiếm một chui con trong một chuỗi.
- Phép thay thế một chuỗi con của một chuỗi bởi một chui khác.
- Phép chen chui con vào một chuỗi.
- Phép loại bỏ một chuỗi con của một chuỗi.
Trong c phép toán nêu trên thì phép tìm kiếm trên chui là phép toán quan
trọng thường gặp , vì vậy ta chỉ tìm hiểu các giải thuật liên quan đến phép
toán này đó :
1. Giải thuật Brute-Force.
2. Giải thuật Knuth-Morris-Pratt.
3. Giải thuật Boyer-Moore.
$1. Các khái nin cơ bản về chui
1.1. Chui và phân chia chui
a. Định nghĩa chuỗi
Chui là một dãy các ký tđược chứa trong một vùng liên tục của bnhớ. Các
ký t này có thể là ký tự chữ, ký tự số hoặc ký tự đặc biệt.
Chui tự (text string) thể được xem như dãy các chữ, c số và c
tự đặc biệt.
Một loại chuỗi khác là chui nhị phân (binary string), đó một dãy các t 0
1.
V â Minh P hæ Bæ m«n K hoa häc m¸ y tÝnh
2
b. Đdài chui. Stự của chuỗi được gọi là chiều dài của chuỗi. Mỗi tự
chiếm 1 byte.
Một chui có thể có chiều dài bng 0 gọi là chuỗi rỗng(null string ), ký hiệu là “
Một chui có thể được chia làm nhiều phần, mỗi phần là mt chuỗi con (sub
string ). Các chui con có thể có chiều dài bằng nhau hoặc khác nhau.
1.2. Cách phân chia chui
a. Dùng ký tự đặc biệt. Dùng ký tự trống ( blank) để phân chia chuỗi con. Khi đó
các chui con thể khác nhau. Đtruy xuất một chui con trong chuỗi thì ta
phi tìm kiếm t đầu chuỗi. Do đó tốc độ truy xuất của phương pp này chậm.
b.ng chiều dài c đnh. Ta chia các chuỗi con thành các phn bằng nhau. Đ
truy xuất một chuỗi con trong một chuỗi thì ta dùng ng thức tính địa chỉ. Do
đó tốc độ truy xuất của phương pháp này rất nhanh.
c. Dùng chỉ điểm (pointer).
- Dùng chđiểm đầu: Chđiểm đầu chỉ vào tđầu tiên của chuỗi con.
Ta sdụng biến Last để cho biết địa chỉ của ký tự cuối cùng của chuỗi.
Gọi:
n- schuỗi con
ai-địa chỉ củatự đầu tiên của chuỗi con thứ i
bi- địa chỉ của ký tự cuối cùng của chuỗi con thứ i
Ta có :
ai = pointer[i]
bi = pointer[i+1]-1 , nếu i<n
= last , nếu i=n
- Dùng chđiểm cuối : Chđiểm cuối chỉ vào t cuối cùng của chuỗi
con. Ta s dụng biến First để cho biết địa ch của ký tự đầu tiên của
chui.
Ta có :
ai = First , nếu i=1
V â Minh P hæ Bæ m«n K hoa häc m¸ y tÝnh
3
= pointer[i-1] ,nếu i>1
bi = pointer[i]
$2.Các giải thuật tìm kiếm trên chuỗi
Bài toán: Tìm kiếm chuỗi p có chiều dài là m trong chui a có chiều dài n.
hai trường hợp xảy ra sau khi tìm kiếm đó là:
- Nếu không tìm thy chuỗi p trong chui a thì kết quả là 0.
- Nếu tìm thấy chuỗi p trong chuỗi a thì kết quả là vị trí của tự đầu tiên
của lần tìm thấy đầu tiên.
Sau đây chúng ta lần lượt đi vào phân tích từng giải thuật cụ thể :
2.1. Giải thuật Brute- Force.
a. Ni dung của giải thuật
- Đi với vị trí tự thi của chuỗi a (i=1,2,…,n-m+1) ta so sánh các t
tương ứng từ trái qua phải:
p[1] với a[i]
p[2] với a[i+1]
………….
p[m] với a[i+m+1]
- Gọi:
i - chỉ số của chui a.
j - chỉ s của chuỗi p.
Nếu a[i] = p[j] thì ta tăng chỉ số i và j lên 1(xét đến ký tự tiếp theo)
Nếu a[i]<>p[j] thì ta cho j ch về đầu chuỗi p (j=1) và i chvề vị trí tự
kế tiếp khi bắt đầu tìm kiếm lần cuối cùng (i = i-j+2).
Gii thuật kết thúc khi j>m hoặc i>n.
- Ta khai báo :
Type
St =string[255];
V â Minh P hæ Bæ m«n K hoa häc m¸ y tÝnh
4
Index = 1..255;
c. Giải thuật:
Chương trình thực hiện gii thuật này như sau:
program Brute_Force;
uses crt;
type
st=string[50];
var a,p:st; {a chứa chuỗi nguồn , p là chuỗi đích, n độ dài chuỗi a ,m độ dài chuỗi
p}
procedure init;
var i,j:integer;
begin
writeln('Nhp chuỗi a:');
readln(a);
writeln('Nhp chuỗi p:');
readln(p);
end;
procedure Result;
begin
writeln('Chui cần tìm là:',p)
end;
Function Brutesearch(p,a:st):integer;
var i,j,m,n:integer;
begin
m:=length(p);
n:=length(a);
i:=1;
j:=1;
repeat
if a[i]=p[j] then
begin
i:=i+1;
j:=j+1;
V â Minh P hæ Bæ m«n K hoa häc m¸ y tÝnh
5
end
else
begin
i:=i-j+2;
j:=1;
end;
until(j>m)or (i>n);
if j>m then Brutesearch:=i-m;
else Brutesearch:=0;
end;
begin
clrscr;
Init;
Brutesearch(a,p);
write('Vị trí của ký tự đầu của chuỗi p trong a là:',Brutesearch(p,a):2);
writeln;
Result;
readln;
end.
Ví d: Ta xét một ví dụ cụ thể sau:
Cho chuỗi a=’ 0101101001110011101011100’ n=27, chuỗi p=’ 010011’ m=6
stt So sánh 2 giá tr Chí smới của i và j Chú thích
1 a[1]=p[1] i=2;j=2
2 a[2]=p[2] i=3;j=3
3 a[3]=p[3] i=4;j=4
4 a[4]<>p[4] i=2,j=1 i=i-j+2
5 a[2]<>p[1] i=3;j=1 -
6 a[3]=p[1] i=4;j=2 Tăng i và j lên 1
7 a[4]=p[2] i=5;j=3 -
8 a[5]<>p[3] i=4;j=1 i=i-j+2