Documente Academic
Documente Profesional
Documente Cultură
Efectuat de studentul
grupei IA21: Ghiderman Ion
Verificat de: Bitcovschi L.
Chiinu, 2015
Sarcina
S se creieze un fiier textual care conine cel puin 50 de nregistrri i cel puin 5 cmpuri.
Unul din cmp este cheia care este unic pentru fiecare nregistrare i este neordonat.
S se implementeze citeva metode de cutare i pentru fiecare metod s se analizeze lungimea
medie teoretic de cutare i lungimea practic de cutare.De descris algoritmul metodei pe pai:
1. Metoda secvenial n tabele neordonate;
2. Metoda de cutare n tabele neordonate structur arborescent;
3. Metoda binara n tabele ordonate;
4. Metoda Hash (de dispersare);
5. Metoda Fibonacci.
Cutarea
Problema cea mai frecvent ntlnit n practic este, probabil, cea a regsirii rapide a unor
informaii. De exemplu, cutarea unui cuvnt n dicionar sau a unui numr n cartea de telefon. De
obicei, informaiile sunt reprezentate sub forma unor nregistrri, fiecare nregistrare coninnd un
cmp numit cheie, ce permite identificarea nregistrrii (de exemplu, ntr-un dicionar nregistrrile sunt
formate dintr-un cuvnt ce reprezint cmpul cheie, din pronunia i definiia corespunztoare
cuvntului respectiv).
O problem de cutare const n identificarea unei nregistrri cu cheia specificat, n scopul
prelucrrii informaiilor corespunztoare. Presupunem c nregistrrile au chei distincte; cazul
nregistrrilor avnd chei identice poate fi tratat n diverse moduri, n funcie de aplicaie (de exemplu,
fiecare nregistrare poate conine o list simplu nlnuit format din nregistrri avnd aceeai cheie
comun).
Cutarea secvential
S presupunem c nregistrrile sunt memorate ntr-un vector global R de dimensiune n. Pentru
a identifica nregistrarea cu cheia specificat x, o prim soluie ar fi de a compara secvenial cheia x cu
cheile nregistrrilor din R:
search (int c) { int position=-1,a,j;
for(int i=0;(position==-1)&&(i<n);i++)
{ a=t[i].getCod();
if(c==a )
{ position=i; t[i].show(); } }
if(position==-1 ) cout<<"\n Inexistent";
}
}
n cazul n care cheia nu se gsete n vector se fac exact n comparaii. n cazul n care cheia se
gsete n vector, n ipoteza c nregistrrile sunt cutate cu aceeai probabilitate (1/n), se fac n medie
2
1
n 1
(1 2... n)
comparaii.
n
2
Deci algoritmul de cutare secvenial este de O(n).
Cutarea secvenial poate fi adaptat n mod natural pentru cazul n care nregistrrile sunt
reinute ntr-o list simplu nlnuit, complexitatea algoritmului rmnnd neschimbat.
Cutarea binar
Dac numrul de nregistrri este mare, putem diminua timpul de cutare presupunnd c
nregistrrile sunt n ordinea cresctoare a cheilor i aplicnd o strategie de tip "divide et impera ".
Comparm cheia cutat x cu cheia nregistrrii din mijloc. n caz de egalitate, cutarea se
ncheie cu succes, altfel njumtim spaiul de cutare, determinnd jumtatea n care exist anse s
se gseasc cheia x i relund procedeul pentru aceast jumtate.
while((c!=t[m].getCod())&&(s<=f))
{ count++; delay(100);
if(t[m].getCod()>c)
{ f=m-1; }
else
{ s=m+1;}
m=(s+f)/2; }
if(s<=f)
{ t[m].show();
} else
{
cout<<"Not found!"; }
Observaii
1. Algoritmul poate fi descris foarte elegant recursiv.
2. Strategiei de cutare binar i se poate asocia un arbore binar astfel :
- rdcina arborelui este indicele elementului din mijloc, (n+1) div 2;
- subarborele stng este format din arborele binar corespunztor cutrii n irul elementelor cu indici
mai mici dect rdcina;
- subarborele drept este format din arborele binar corespunztor cutrii n irul elementelor cu indici
mai mari dect rdcina.
Fig. 1.
3
De exemplu, pentru n=15 arborele binar asociat algoritmului de cutare binar este
Fig. 2.
pe fiecare nivel i0,1,2,3 fiind situate 2 vrfuri.
Pentru n = 10 arborele este :
i
Fig. 3.
primele 3 niveluri fiind complete, al patrulea coninnd 3 vrfuri.
Observaii
1. Parcurgnd n inordine arborele, obinem irul indicilor ordonat cresctor.
2. Pe fiecare nivel i n arbore exist 2 i vrfuri, cu excepia ultimului nivel care este incomplet n cazul
n care n nu este de forma 2k-1.
Folosind aceste observaii, putem calcula nlimea arborelui asociat algoritmului de cutare
binar n funcie de n, dimensiunea spaiului de cutare. Dac notm cu h nlimea arborelui, atunci :
1+2+...+2h-1 < n 1+2+...+2h
2h n < 2h+1
Problema enunat presupune c mulimea de valori n care se face cutarea este static (deci nu
suport inserri sau tergeri de elemente) i deci arborele binar asociat rmne total echilibrat, cu
nlimea h = [log2n]. De asemeni, n analiza complexitii am presupus c orice valoare este cutat cu
aceeai probabilitate.
Cutarea Fibonacci
Algoritm: Sirul numerelor Fibonacci se defineste recursiv astfel: F0=0, F1=1, Fk+2=Fk+1+Fk, k>=0.
Lungimea tabelului este egala cu ultimul numar Fibonacci si este N=Fm. Daca lungimea tabelului nu
este un numar Fibonacci se ia in calitate de Fm cel mai mic numar din F, imediat mai mare decat n.
Pas1 (Initializare):
i=Fk, p=Fk-1, q=Fk-2, unde p si q sunt doua numere Fibonacci consecutive.
Pas2 (Comparare): Daca K<Ki, atunci mergi la pasul 3; daca K>Ki atunci mergi la pasul 4; si daca
K=Ki algoritmul se finiseaza cu succes.
Pas3 (Descrestere i): Daca q=0, atunci avem insucces. In caz contrar se fac urmatoarele atribuiri: i=i-q
si p=q; q=p-q; apoi ne intoarcem la pasul 2.
Pas4 (Incrementare i): Daca p=1, atunci avem insucces. In caz contrar se fac urmatoarele atribuiri
i=i+q p=p-q si apoi q=q-p (p se ia acel obtinut acum); apoi ne intoarcem la pasul 2.
Programul
#include
#include
#include
#include
#include
#include
#include
<conio.h>
<stdio.h>
<iostream.h>
<string.h>
<math.h>
<stdlib.h>
<dos.h>
class elem {
public:
protected :
int get_st()
{
return st;
}
int set_dr(int new_dr)
{
dr=new_dr;
return dr;
}
int get_dr()
{
return dr;
}
char* getnume() {
return nume; }
char* getprenume() { return prenume;}
int getan(){ return an; }
char* getobiect() { return obiect; }
int fscanf_el (FILE * f)
{return fscanf(f,"%i %s %s %s
%i",&cod,nume,prenume,obiect,&an);}
void virtual show( ) {
cout<<cod<<" "<<nume<<" "<<prenume<<"
"<<an<<endl; }
virtual int free() { return cod==0; }
int operator >(STUDENT &e2) {
return (this->cod>e2.cod);}
int operator < (STUDENT &e2) {
return (this->cod<e2.cod); }
int operator <= (STUDENT &e2) {
return (this->cod<=e2.cod); }
int operator >= (STUDENT &e2){
return (this->cod>=e2.cod); }
int operator == (STUDENT &e2) {
return (this->cod==e2.cod); }
int operator != (STUDENT &e2) {
return (this->cod!=e2.cod); }
};
"<<obiect<<"
};
getch(); exit(1); }
template
<class el>
tabel<el>::tabel (char * file) {
FILE *pf;
pf=fopen(file,"rt");
n=0;
while(!feof(pf))
if (t[n].fscanf_el(pf)>0)
n++;
fclose(pf);
}
template
<class el>
void tabel<el>::search (int c) { int position=-1,a,j;
for(int i=0;(position==-1)&&(i<n);i++)
{ a=t[i].getcod();
if(c==a )
{ position=i; t[i].show(); } }
if(position==-1 ) cout<<"\nNu exista";
else{
cout<<"\nLungimea practica de cautare este:"<<position;
cout<<"\nLungimea teoretica de cautare este:"<<n/2; }
}
template
<class el>
int tabel<el>::fib_search(el initial)
{
int position=-1, contor=0, i=0, q=0, p=0;
double durata;
int
fib[]={0,1,1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,1597,2584,4181,6765};
for(int j=0;;j++)
{
if(i>n)
{
i=fib[j-2];
p=fib[j-3];
q=fib[j-4];
break;
}
else i=fib[j];
}
while(2<3)
{
contor++;
if(initial==t[i]) {position=i; break;}
if(initial<t[i])
{
if(q==0) break;
else {int v=p;i=i-q;p=q;q=v-q;}
}
if(initial>t[i])
{
if(p==1) break;
else{ i=i+q; p=p-q; q=q-p;}
}
}
template
<class el>
}
if(position==-1){cout<<endl<<cout<<"Error!Error!"<<endl;}
else
{
cout<<endl;
t[position].show();
cout<<endl<<"Lungimea practica de cautare este:"<<" "<<contor<<endl;
float caut;
caut=log(n)/log(2);
cout<<"Lungimea teoretica de cautare este:"<<" "<<caut<<endl;
}
return position;
template
<class el>
void tabel<el>::sort()
{
int j,count=0;
el aux;
for(int i=0;i<n-1;i++)
for(j=i;j<n;j++)
{
if(t[i].getcod()>t[j].getcod())
{
aux=t[i];
t[i]=t[j];
t[j]=aux;
count++;
}
}
cout<<"Sortarea s-a terminat!"<<endl;
getch();
}
template
<class el>
void tabel<el>::searchbin(int c)
{
if(!n)
{
cout<<"ERROR! Introduceti datele";
getch();
return; }
int s=0,f=n-1,count=1,j;
int m=(s+f)/2;
while((c!=t[m].getcod())&&(s<=f))
{ count++;
if(t[m].getcod()>c)
{
f=m-1;
}
else
{
s=m+1;}
m=(s+f)/2; }
if(s<=f)
{
t[m].show();
cout<<"\nLungimea practica de cautare este:"<<" "<<count;
cout<<"\nLungimea teoretica de cautare este:"<<" "<<log(n)/log(2);
}
else
{
cout<<"\n Nu exista asa date!";
}
template
<class el>
void tabel<el>::createtree()
{
for(int i=1;i<n;i++)
{
int forw=1,j=0;
while(forw)
{
if(t[i]<t[j])
{
if(t[j].get_st()==-1)
{
t[j].set_st(i);
forw=0;
}
else
j=t[j].get_st();
}
else
if(t[i]>t[j])
{
if(t[j].get_dr()==-1)
{
t[j].set_dr(i);
forw=0;
}
j=t[j].get_dr();
}
}
}
}
template
<class el>
void tabel<el>::killtree()
{
for(int i=0;i<n;i++)
{
t[i].set_st(-1);
10
t[i].set_dr(-1);
}
template
<class el>
int tabel<el>::searchtree(STUDENT tmp)
{
int i=0,count=0,forw=1;
while(forw)
{
if(tmp==t[i])
{
t[i].show();
cout<<t[i].st<<" "<<t[i].dr<<endl;
cout<<"Lungimea practica de cautare este:"<<count<<endl;
cout<<"Lungimea teoretica maxima de cautare este:"<<n/2<<endl;
cout<<"Lungimea teoretica minima de cautare
este:"<<log(n)/log(2.0)*2.0;
forw=0;
}
else
{
if(tmp<t[i])
i=t[i].get_st();
else
i=t[i].get_dr();
if(i==-1)
{
forw=0;
cout<<"Elementul nu este gasit"<<endl;
}
}
count++;
}
return 0;
}
void main()
{
clrscr();
STUDENT pl,tmp;
tabel <STUDENT> gr("student.txt");
char ch, c;
int coden;
do{
clrscr();
cout<<"Menu:"<<endl;
cout<<"*****************************************"<<endl;
cout<<"0)Afisare tabel"<<endl;
cout<<"1)Metoda secventila"<<endl;
cout<<"2)Metoda arborescenta"<<endl;
cout<<"3)Sortarea"<<endl;
cout<<"4)Metoda binara"<<endl;
cout<<"5)Metoda Fibonacci"<<endl;
11
cout<<"6)Exit"<<endl;
c=getch();
switch(c)
{
case '0':
ch='n';
while(ch!='y')
{
clrscr();
gr.show("Continutul fisierului:\n"," ");
cout<<endl<<"Iesiti?(Y/N)";
ch=getch();
}
break;
case '1':
ch='n';
while(ch!='y')
{
clrscr();
cout<<"Introduceti codul pentru cautare"<<endl;
cin>>coden;
gr.search(coden);
cout<<endl;
cout<<endl<<"Iesiti?(Y/N)";
ch=getch();
}
break;
case '2':
ch='n';
while(ch!='y')
{
clrscr();
cout<<"Introduceti codul pentru cautare"<<endl;
cin>>coden; cout<<endl;
tmp.setcod(coden);
gr.createtree();
cout<<endl;
gr.searchtree(tmp); cout<<endl;
cout<<endl<<"Iesiti?(Y/N)";
gr.killtree();
ch=getch();
}
break;
case '3':
clrscr();
gr.sort();
getch();
break;
case '4':
ch='n';
while(ch!='y')
{
clrscr();
cout<<"Introduceti codul pentru cautare"<<endl;
cin>>coden;
cout<<endl;
gr.searchbin(coden); cout<<endl;
cout<<endl<<"Iesiti?(Y/N)";
ch=getch();
12
}
break;
case '5':
ch='n';
while(ch!='y')
{
clrscr();
cout<<"Introduceti codul pentru cautare"<<endl;
cin>>pl.cod;
cout<<endl;
if(gr.fib_search(pl)==-1) cout<<endl<<"Eroare!
Sortati!"<<endl;
cin.ignore();
cout<<endl;
cout<<endl<<"Iesiti?(Y/N)";
ch=getch();
}
break;
} }
while(c!='6');
}
13
14
Rezultatul
Afiare tabel:
Metoda secvenial
15
Metoda arborescent
Metoda binar
Metoda Fibonacci
16
Concluzii
La execuia programului s-a afiat tabloul cu nregistrrile ncarcate din fiier apoi la
introducerea unui identificator pentru o inregistrare pe care o vom cauta n tabloul de elemente s-a
afisat nregistrarea, lungimea teoretica de cautare, lungimea practica de cautare, iar daca nu se gaseste
ni se afieaza nregistrare inexistent.
Pentru a vedea mai bine care metod este mai eficient pentru cutarea n tabele am cautat una
i aceiai nregistrare folosind toate metodele descrise n program.
n final am observat c cea mai bun metod pentru cutare este:
1. Metoda Fibonacci
2. Metoda binar
3. Metoda arborescent
4. Metoda secvential
Nu este mare diferen dintre metoda Fibonacci i cea binar, dar totui este la lungimea
teoretic cu citeva miimi.
17