intTypePromotion=1
zunia.vn Tuyển sinh 2024 dành cho Gen-Z zunia.vn zunia.vn
ADSENSE

CHUỖI VÀ CÁC BÀI TOÁN TRÊN CHUỖI

Chia sẻ: 123968574 123968574 | Ngày: | Loại File: PDF | Số trang:44

207
lượt xem
48
download
 
  Download Vui lòng tải xuống để xem tài liệu đầy đủ

Tham khảo tài liệu 'chuỗi và các bài toán trên chuỗi', công nghệ thông tin, hệ điều hành phục vụ nhu cầu học tập, nghiên cứu và làm việc hiệu quả

Chủ đề:
Lưu

Nội dung Text: CHUỖI VÀ CÁC BÀI TOÁN TRÊN CHUỖI

  1. CHUỖI VÀ CÁC BÀI TOÁN TRÊN CHUỖI Chuỗi (string) là một loại dữ liệu cơ bản thường được sử dụng trong rất nhiều các hệ thống và là thành phần cơ bản trong các hệ thống xử lý văn bản (word - processing-system), các hệ thống này cung cấp cho ta rất nhiều khả năng đ ể xử lý văn bản. Ngoài ra một 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 chuỗi 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 chuỗi khác. - Phép chen chuỗi 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ác phép toán nêu trên thì phép tìm kiếm trên chuỗi là phép toán quan trọng và 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 đó là : 1. G iải thuật Brute-Force. 2. G iải thuật Knuth-Morris-Pratt. 3. G iải thuật Boyer-Moore. $1. Các khái niện cơ bản về chuỗi 1.1. Chuỗi và phân chia chuỗi a. Đ ịnh nghĩa chuỗi Chuỗi là một dãy các ký tự được chứa trong một vùng liên tục của bộ nhớ. Các ký tự này có thể là ký tự chữ, ký tự số hoặc ký tự đặc biệt. Chuỗi ký tự (text string) có thể được xem như là dãy các chữ, các số và các ký tự đặc biệt. Một loại chuỗi khác là chuỗi nhị phân (binary string), đó là một dãy các kí tự 0 và 1. 1 Vâ Minh Phæ – Bæ m«n Khoa häc m¸y tÝnh
  2. b. Đ ộ dài chuỗi. Số ký tự của chuỗi được gọi là chiều dài của chuỗi. Mỗi ký tự chiếm 1 byte. Một chuỗi có thể có chiều dài bằng 0 gọi là chuỗi rỗng(null string ), ký hiệu là “ Một chuỗi có thể đ ược chia làm nhiều phần, mỗi phần là một chuỗi con (sub string ). Các chuỗi con có thể có chiều dài bằng nhau hoặc khác nhau. 1.2. Cách phân chia chuỗi a. Dùng ký tự đặc biệt. Dùng ký tự trống ( blank) để phân chia chuỗi con. Khi đó các chuỗi con có thể khác nhau. Để truy xuất một chuỗi con trong chuỗi thì ta phải tìm kiếm từ đầu chuỗi. Do đó tốc độ truy xuất của phương pháp này chậm. b. Dùng chiều dài cố định. Ta chia các chuỗi con thành các phần bằng nhau. Để truy xuất một chuỗi con trong một chuỗi thì ta dùng cô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 ký tự đầu tiên của chuỗi con. Ta sử dụng biến Last để cho biết địa chỉ của ký tự cuối cùng của chuỗi. Gọi: n- số chuỗi con ai-địa chỉ của ký tự đầ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
  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 chuỗi a có chiều dài n. Có hai trường hợp xảy ra sau khi tìm kiếm đó là: - Nếu không tìm thấy chuỗi p trong chuỗi 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 ký 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. Nội dung của giải thuật - Đ ối với vị trí kí tự thứ i của chuỗi a (i=1,2,…,n-m+1) ta so sánh các ký 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 chuỗi 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 chỉ về vị trí ký tự kế tiếp khi bắt đầu tìm kiếm lần cuối cùng (i = i-j+2). Giải thuật kết thúc khi j>m hoặc i>n. - Ta khai báo : Type St =string[255]; 3 Vâ Minh Phæ – Bæ m«n Khoa häc m¸y tÝnh
  4. Index = 1..255; c. Giải thuật: Chương trình thực hiện giải 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 là độ dài chuỗi p} procedure init; var i,j:integer; begin writeln('Nhập chuỗi a:'); readln(a); writeln('Nhập chuỗi p:'); readln(p); end; procedure Result; begin writeln('Chuỗi 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; 4 Vâ Minh Phæ – Bæ m«n Khoa 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 c lrscr; 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 So sánh 2 giá trị Chí số mới của i và j stt 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 - Tăng i và j lên 1 6 a[3]=p[1] i=4;j=2 7 a[4]=p[2] i=5;j=3 - 8 a[5]p[3] i=4;j=1 i=i-j+2 5 Vâ Minh Phæ – Bæ m«n Khoa häc m¸y tÝnh
  6. 9 a[4]p[1] i=5;j=1 - 10 a[5]p[1] i=6;j=1 - tăng i và j lên 1 11 a[6]=p[1] i=7;j=2 12 a[7]=p[2] i=8;j=3 - 13 a[8]=p[3] i=9;j=4 - 14 a[9]=p[4] i=10;j=5 - 15 a[10]=p[5] i=11;j=6 - giải thuật kết thúc do 16 a[11]=p[6] i=12;j=7 j>m Đến đây giải thuật kết thúc giá trị trả về ở đây là 6 của lần tìm thấy đầu tiên a=’ 0101101001110011101011100’ p=’ 010011’ d. Phân tích giải thuật Trường hợp xấu nhất của giải thuật này là trường hợp cả hai chuỗi p và a đ ều gồm các số 0 và kết thúc là số 1. Khi đó với n-m +1 lần tìm kiếm ta phải so sánh m ký tự của chuỗi p với các ký tự tương ứng của chuỗi a. Số lần so sánh : Cmax=m*(n-m+1) Ta có thể cải tiến giải thuật này bằng giải thuật Knuth- Morris-Pratt. 2.2. Giải thuật Knuth- Morris- Pratt. a. Nội dung của giải thuật - Trong giải thuật Brute-Force ta nhận thấy khi so sánh đến ký tự p[j]a[i] thì ta đ ã có j -1 kí tự đầu tiên của chuỗi p bằng với các j-1 ký tự cuối cùng trước a[i] của chuỗi a. V í dụ : 6 Vâ Minh Phæ – Bæ m«n Khoa häc m¸y tÝnh
  7. chuỗi a là :’1010100111’ chuỗi p là :’10100111‘ - Ta nhận thấy a[5] và p[5] khác nhau. Khi đó ta không cần cho j=1 nữa mà cho j về 3 để so sánh vì ta nhận thấy 3 ký tự đầu tiên của chuỗi p bằng với 3 ký tự đang xét cuối cùng của của chuỗi a. Do đó ta không cần cho i quay về vị trí trước nữa mà vẫn tiếp tục cho i tăng. Ta sử dụng mảng next[1…m] để để ghi nhận giá trị j quay về . Phần tử next[j] sẽ cho giá trị mới của j khi phát hiện hai ký tự khác nhau. Mảng next[1…m] được xác định như sau : - Sử dụng chuỗi p1 ho àn toàn giống p. Cho chuỗi p1 di chuyển từ trái qua phải đồng thời so sánh với chuỗi p và dừng lại khi các kí tự đầu tiên của chuỗi p1 trùng với các kí tự của chuỗi p. Các kí tự trùng này sẽ xác định giá trị của next. - Nếu sự khác nhau này được phát hiện ở p[j] thì next[j] :=1+số ký tự trùng nhau +.với j=1 next[j]=0 +.với j>1 next[j] := lµ sè lín nhÊt k
  8. procedure init; var i,j:integer; begin writeln('Nhập chuỗi a:'); readln(a); writeln('Nhập chuỗi p:'); readln(p); end ; procedure Result; begin writeln('Chuỗi cần tìm là:',p); end ; Function Kmsearch(p,a:st):integer; var i,j,m,n:integer; next:array[index]of integer; procedure Initnext; begin i:=1; j:=0; next[1]:=0; repeat if(j=0)or(p[i]=p[j])then b egin i:=i+1; j:=j+1; next[i]:=j; end; else j:=next[j]; 8 Vâ Minh Phæ – Bæ m«n Khoa häc m¸y tÝnh
  9. until i=m; end; begin m:=length(p); n:=length(a); {Tạo mảng next} Initnext; i:=1; j:=1; repeat if (j=0) or (a[i]=p[j]) then begin i:=i+1; j:=j+1; end; else begin j:=next[j]; end; until(j>m)or (i>n); if j>m then Kmsearch:=i-m else Kmsearch:=0; end; begin clrscr; Init; Kmsearch(a,p); write('V ị trí của ký tự đầu của chuỗi p trong a là:',Kmsearch(p,a):2); writeln; 9 Vâ Minh Phæ – Bæ m«n Khoa häc m¸y tÝnh
  10. Result; readln; end . c. Ví dụ cụ thể Cho chuỗi a : 101'01.0'011'1 i =10 p : 101'00.1'11 j =8 Các bước sẽ được thể hiện trong bảng sau : chuỗi j next[j] 2 1 101’001’11 (p) 101’001’11 (p1) 3 1 101’001’11 101’001’11 4 2 101’001’11 101’001’11 5 3 101’001’11 1 01’001’11 6 1 101’001’11 1 01’001’11 7 2 101’001’11 1 01’001’11 8 101’001’11 101’001’11 10 Vâ Minh Phæ – Bæ m«n Khoa häc m¸y tÝnh
  11. Số lần so sánh Cmax=n+m. Ta thấy số lần so sánh đ ã giảm đi nhiều lần. 2.3. Giải thuật Boyer –Moore a. Nội dung giải thuật: - G iải thuật Boyer-Moore tương tự với giải thuật Knuth-Morris-Pratt. Đối với giải thuật Boyer, ta xét chuỗi p1 từ phải qua trái trong khi ta so sánh chuỗi p với chuỗi a. Cách xây dựng mảng next của giải thuật Boyer-Moore là phần tử next[j] là số vị trí kí tự m à chuỗi p sẽ di chuyển qua phải đối với chuỗi p1 để có được vị trí khác nhau ở kí tự thứ j kể từ phải qua trái của chuỗi p. b. Giải thuật: Để xác định vị trí mới của j khi có sự so sánh trùng nhau ta dùng mảng skip. Hàm Function Ord(c:char):integer trả về số thứ tự của ký tự c trong bộ ký tự (đánh số từ 1). Khi đó skip[c]=m nếu c không phải là một ký tự của chuỗi p skip[c]=m-j nếu c là kí tự thứ j của chuỗi p. Ta có giải thuật : Program Boyer-Moore; Use crt; Type St=string[50]; Const Charno=255; procedure init; begin writeln(‘ hay nhap chuoi a:’); readln(a); writeln(‘nhap chuoi p:’); readln(p); end; procedure result; 11 Vâ Minh Phæ – Bæ m«n Khoa häc m¸y tÝnh
  12. begin writeln(‘chuoi can tim la:’,p); end; Function Bmsearch (p,a:st):integer; Var i,j,m,n:integer; skip :array[1..charno]of interger; procedure Initskip; var i:1..charno; j:integer; begin for i:=1 to charno do skip[i]=m; for j:=1 to m do if skip[ord(p[j])]=m then skip[ord(p[j])]=m-j; end; begin m:=length(p); n:=length(a); i nitskip; i :=m; j :=m; repeat if a[i]=p[j] then begin i:=i-1; j:=j-1; end; begin if m-j+1>skip[ord(a[i])] then i :=i+m-j+1 else i:=i+skip[ord(a[i])]; j:=m; end; until (jn); if j
  13. begin clrscr; init; bmsearch(a,p); write(‘vi tri cua ky tu dau cua chuoi p trong a la :’,bmsearch(p,a):2) ; writeln ; result ; readln ; end. c. Phân tích giải thuật Số lần so sánh : Cmax=m+n Số bước thực hiện trong trường hợp bộ ký tự không nhỏ và chuỗi p không lớn là: S=n/m {$M $4000,0,0} Program Bai_tap_tren_xau; uses crt; type m= array [1..9] of string; const menu:m=(' 1. Dao nguoc xau ',' 2. Tinh chieu dai cua xau',' 3. Chi so cua xau',' 4. Lay xau ky tu con', ' 5. In xau khong de quy',' 6. In xau de quy',' 7. Bai 5.2',' 8. Bai 5.5',' 9. Thoat'); type infor=char; ref=^elemen; elemen=record info:infor; link:ref; 13 Vâ Minh Phæ – Bæ m«n Khoa häc m¸y tÝnh
  14. end; var first:ref; const max=1000; type stacks=record index:integer; data:array[1..max] of integer; End; stackc=record index:integer; data:array[1..max] of char; end; stackR=record index:integer; data:array[1..max] of real; End; var step:integer; d,g:ref; ch1,h,c1:char; i1,n,f,e,b1,b2:integer; i:integer; s:string; stack:stackc; kt:boolean; t:real; nu,r: integer; stack1:stacks; {---------------------------------------------------------} 14 Vâ Minh Phæ – Bæ m«n Khoa häc m¸y tÝnh
  15. function themdau(var first:ref;NewInfo:Infor):ref; var p:ref; begin new(p); p^.info:=NewInfo; p^.link:=first; first:=p; themdau:=p; end; {--------------------------------------------------------} function themcuoi(var q:ref;NewInfo:Infor):ref; var p,scan:ref; begin New(p); p^.Info:=NewInfo; p^.link:=nil; if q = nil then q :=p else Begin scan:=q; while scan^.linknil do scan:=scan^.link; scan^.link:=p; End; themcuoi:=p; end; 15 Vâ Minh Phæ – Bæ m«n Khoa häc m¸y tÝnh
  16. {--------------------------------------------------------} procedure xoadau(var first:ref); var p:ref; begin if firstnil then b egin p:=first; first:=p^.link; dispose(p); end; end; {-----------------------------------------------------} procedure xoacuoi(var first:ref); var p,q:ref; begin q :=first; p :=q^.link; if(first=nil)then exit; if(p=nil)then b egin dispose(q); first:=nil; end else b egin while(p^.linknil) do 16 Vâ Minh Phæ – Bæ m«n Khoa häc m¸y tÝnh
  17. begin p:=p^.link; q:=q^.link; end; d ispose(p); q ^.link:=nil; end; end; {----------------------------------------------------------} procedure inra(first:ref); var p:ref; begin p:=first; while(pnil) do begin write(p^.info); p:=p^.link; end; end; {---------------------------------------------------------} procedure dao(var first:ref); var a,b,c:ref; begin if(first=nil) then exit else if (first^.link=nil) then 17 Vâ Minh Phæ – Bæ m«n Khoa häc m¸y tÝnh
  18. exit else a:=nil; b:=first; c:=first^.link; while(cnil) do begin b^.link:=a; a:=b; b:=c; c:=c^.link; end; b ^.link:=a; first:=b; end; {-----------------------------------------------------------} function chieudai(first:ref):integer; var d em:integer; p :ref; begin p:=first; dem:=0; while(pnil) do begin p:=p^.link; dem:=dem+1; end; 18 Vâ Minh Phæ – Bæ m«n Khoa häc m¸y tÝnh
  19. chieudai:=dem; end; {-----------------------------------------------------------} function chiso(first:ref;d:integer):infor; var p:ref; dem:integer; begin p:=first; dem:=1; while(dem
  20. begin q:=q^.link; inc(dem); end; if(q=nil) then begin xaukitucon:=nil; exit; end; n ew(daumoi); daumoi^.info:=q^.info; duoimoi:=daumoi; for i:=2 to n do begin q:=q^.link; if(qnil) then begin new(temp); temp^.info:=q^.info; duoimoi^.link:=temp; duoimoi:=temp; end else break; end; duoimoi^.link:=nil; xaukitucon:=daumoi; end; {------------------------------------------------------------} 20 Vâ Minh Phæ – Bæ m«n Khoa häc m¸y tÝnh
ADSENSE

CÓ THỂ BẠN MUỐN DOWNLOAD

 

Đồng bộ tài khoản
2=>2