a.Modelul matematic:secventa finita de caractere.
b.Notatii: s,sub,u - siruri
c - valoare de tip caracter
b - valoare booleana
poz,lung - intregi pozitivi
c.Operatori:
CreazaSirVid(s) - procedura ce creaza sirul vid s;
SirVid(s)-->b - functie ce returneaza true daca sirul e vid;
Sircomplet(s) - functie booleana ce returneaza valoarea true daca
sirul este complet;
LungSir(s)-->lung - functie ce returneaza numarul de caractere
ale lui s;
Pozitie(sub,s)-->poz - functie care returneaza pozitia la care
subsirul sub apare prima data in s; daca sub nu e gasit in s, se
returneaza val 0; pozitiile caracterelor sint numerotate de la
stinga la dreapta incepind cu 1;
Concat(u,s) - procedura care concateneaza la sfirsitul lui u
atitea caractere din s, pina cind SirComplet(u) devine true;
CopiazaSubsir(u,s,poz,lung) - procedura care-l face pe u copia
subsirului din s incepind cu pozitia poz, pe lungime lung sau
pina la sfirsitul lui s; daca poz < 1 sau poz > LungSir(s), u
devine sirul vid;
StergeSir(s,poz,lung) - procedura care sterge din s,incepind cu
pozitia poz, subsirul de lung caractere; pentru poz invalid, s
ramine nemodificat;
InsereazaSir(sub,s,poz) - procedura care insereaza in s, de la
pozitia poz, sirul sub;
FurnizeazaCar(s,poz)-->c - functie care returneaza caracterul de
la pozitia poz din s; pentru poz invalid, se returneaza Chr(0);
AdaugaCaracter(s,c) - procedura ce adauga caracterul c la
sfirsitul sirului s;
StergeSubsir(sub,s,poz) - procedura ce sterge prima aparitie a
subsirului sub in sirul s si returneaza pozitia poz de stergere;
daca sub nu e gasit, poz revine pe 0, iar s nemodificat;
StergeToateSubsir(s,sub) - sterge toate aparitiile lui sub in s.
const LungimeMax=...;
type TipLungime=0..LungimeMax;
TipIndice=1..LungimeMax;
TipSir=record lungime:TipLungime;
sir:array[TipIndice] of char
end;
var s:TipSir;
Spre exemplu, in acest context, operatorii CreazaSirVid si
FurnizeazaCar se pot implementadupa cum urmeaza:
procedure CreazaSirVid(var s:TipSir);
begin
s.lungime:=0
end;
function FurnizeazaCar(s:TipSir,poz:TipIndice):char;
begin
if (poz<1) or (poz>s.lungime) then
begin
writeln('pozitie incorecta');
FurnizeazaCar:=chr(0)
end
else
FurnizeazaCar:=s.sir[poz]
end;
Tipul standard String=String[255] ( sau String[lung_sir],
unde 1<=lung_sir<=255) din Turbo PASCAL implementeaza fiecare sir printr-un
tablou de caractere (array [0..lung_sir] of char), elementul 0 al tabloului
precizind lungimea sirului (deci pentru un sir s:string, functia length
returneaza ord(s[0])).
In C, implementarea sirurilor se face tot prin tablouri de caractere, marcarea sfirsitului unui sir fiind facuta prin caracterul cu ordinalul 0 ('\0') care urmeaza caracterelor sirului.
Un exemplu de implementare in Pascal este:
const LungimeHeap={numar foarte mare};
LungimeTabela={numar maxim de siruri};
type ElementTabela=record
lungime,
indicator:1..LungimeHeap
end;
TipSir=1..LungimeTabela;
{un sir e un indicator in tabela de siruri}
var TabelaDeSiruri:array [1..LungimeTabela] of ElementTabela;
Heap:array [1..LungimeHeap] of char;
Disponibil:0..LungimeHeap; {primul caracter liber din heap}
NumarDeSiruri:0..LungimeTabela;
In aceasta implementare, pentru o utilizare rationala, maxima a heap-ului,
orice stergere a unui sir, ar trebui sa fie urmata de o compactare a sirurilor
ramase in heap, sau de o adaugare a spatiului disponibilizat intr-o tabela
a spatiilor disponibile, asemanatoare cu cea de siruri (in aceasta ultima
varianta, la o insertie, trebuie ocupat spatiul disponibil cu lungimea cea mai
apropiata (mai mare) celei a sirului )
type PointerCelula=^Celula;
Celula=record
ch:char;
urm:PointerCelula
end;
TipSir=record
Lungime:integer;
Cap,Coada:PointerCelula
end;
In acest context, unii din operatorii specifici pot fi
implementati astfel:
procedure CreazaSirVid(var s:TipSir);
begin
s.Lungime:=0;
s.Cap:=nil;
s:coada:=nil
end;
function FurnizeazaCar(s:TipSir;poz:integer):char;
var contor:integer;
p:PointerCelula;
begin
if (poz<1) and (poz>s.Lungime) then
begin
writeln('index eronat');
FurnizeazaCar:=chr(0)
end
else
begin
p:=s.cap;
for contor:=1 to poz-1 do p:=p^.urm;
FurnizeazaCar:=p.ch
end
end;
const n={numarul de siruri din tabela de siruri};
l={numarul maxim de caractere dintr-un sir, sfirsitul unui
sir se marcheaza cu chr(0)}
type Sir=array [0..l-1] of char;
Tabela=array [0..n-1] of sir;
var T:tabela;
X:Sir;
Se cere sa se verifice apartenenta sirului X la tabela T.
Presupunind ca n este suficient de mare si ca tabela este
ordonata alfabetic, se poate utiliza cautarea binara performanta.
function CautareTabelara(var T:tabela;var X:Sir;var poz:integer):boolean;
{ primii doi parametrii formali (de lungime mare), se declara cu var,
pentru a li se transmite (prin stiva) doar adresa }
var i,s,d,m:integer;
begin
s:=0;d:=n;
while s < d do
begin
m:=(s+d) div 2;i:=0;
while (T[m,i]=X[i]) and (X[i]<>chr(0)) do
i:=i+1;
if T[m,i] < X[i] then s:=m+1
else d:=m
end;
if d < n then
begin
i:=0;
while (T[d,i]=X[i]) and (X[i]<>chr(0)) do
i:=i+1
end;
poz:=d;
CautareTabelara:=(d < n) and (T[d,i]=X[i])
end;
Parametrul poz returneaza indicele primului sir mai mare sau egal
decit cel cautat sau prima intrare de dupa cele ocupate (daca toate sirurile
sint mai mici decit cel cautat), deci functia poate fi utilizata si la crearea
(ordonata) a tabelei de siruri.
var s:array [0..n-1] of char;
p:array [0..m-1] of char; {0 < m <=n}
Se cere sa se determine pozitia primei aparitii in sirul s a
sirului ( modelului ) p.
In cautarea directa, modelul e "deplasat paralel" cu sirul, cu cite o pozitie, pina la gasirea lui sau pina cind numarul pozitiilor netestate din sir e mai mic decit lungimea modelului.
O posibilitate de implementare a cautarii directe este urmatoarea:
function CautareDirecta(var poz:integer):boolean;
var i,j:integer; {i parcurge caracterele din sir, j pe cele din model}
begin
i:=-1;
repeat
i:=i+1; j:=0;
while (j < m) and (s[i+j]=p[j]) do j:=j+1
until (j=m) or (i=n-m);
poz:=i;
CautareDirecta:=j=m
end;
Compilarea construieste un tablou d de deplasari, continind cite o intrare pentru fiecare caracter din model; valoarea din intrare e indicele de la care continua comparatia intre caracterele din model si cele din sir dupa o nepotrivire anterioara, realizindu-se deplasarea modelului pe mai mult de o pozitie. Calculul elementului i al tabloului d ia in considerare lungimea maxima a subsirului care incepe cu primul caracter al modelului si e egal cu subsirul care precede caracterul de pe pozitia i a modelului.
O varianta de implementare este urmatoarea:
const mmax={lungime maxima model};
nmax={lungime maxima sir sursa};
var m{lungime model},n{lungime sir}:integer;
p:array [0..mmax-1] of char;{model}
s:array [0..nmax-1] of char;{sir}
d:array [0..mmax-1] of integer:{tabela de deplasari}
function CautareKMP(var poz:integer):boolean;
var i,j,k:integer;
begin
{citire sir}
{citire model}
j:=0;k:=-1;d[0]:=-1; {compilare model}
while j < m-1 do
begin
while (k>=0) and (p[j]<>p[k]) do k:=d[k];
j:=j+1;k:=k+1;
if p[j]=p[k] then d[j]:=d[k]
else d[j]:=k
end;
i:=0;j:=0; {cautare model}
while (j < m) and (i < n) do
begin
while (j>=0) and (s[i]<>p[j]) do j:=d[j];
j:=j+1;i:=i+1;
end;
poz:=i-m;
CautareKMP:=j=m
end;
Cautarea se face comparind perechi de caractere din sir si model, pornind de la ultimul caracter din model. In cazul aparitiei unei inegalitati, modelul va fi "deplasat" astfel incit in dreptul caracterului din sir unde a aparut nepotrivirea, sa se afle un caracter identic din model, cel mai apropiat spre stinga, daca un astfel de caracter exista; altfel, numarul de pozitii cu care se face "deplasarea" modelului, este egal cu lungimea lui. Marimea deplasarii pentru fiecare caracter posibil (din sir, unde apare nepotrivirea), se calculeaza in tabloul d, la precompilarea modelului.
O varianta de implementare este urmatoarea:
const mmax={lungime maxima model};
nmax={lungime maxima sir sursa};
var m{lungime model},n{lungime sir}:integer;
p:array [0..mmax-1] of char;{model}
s:array [0..nmax-1] of char;{sir}
d:array [char] of integer:{tabela de deplasari}
function CautareBM(var poz:integer):boolean;
var i,j,k:integer;
begin
{citire sir}{citire model}
for i:=0 to 255 do d[chr(i)]:=m;{compilare model}
for j:=0 to m-2 do d[p[j]]:=m-j-1;
i:=m;j:=m;{cautare model}
while (j>0) and (i<=n) do
begin
j:=m;k:=i;
while (j>0) and (s[k-1]=p[j-1]) do
begin
k:=k-1;j:=j-1
end;
if j>0 then
i:=k+d[s[k-1]]
end;
poz:=i-m;
CautareBM:=j=0
end;