Documente Academic
Documente Profesional
Documente Cultură
Curs
Curs
ALGORITMI
MODUL 1
CURS 3
3. TEHNICI DE CĂUTARE SI SORTARE
3.1. METODE DE CĂUTARE
Obiectiv: Căutarea unor obiecte pe
baza valorii unui câmp (cheie) asociat
fiecărui obiect
- dacă obiectele nu sunt ordonate - căutare directă
- dacă obiectele sunt ordonate găsirea unui obiect se
poate face mai rapid
2
Căutarea binară
int CautareBinara(int *p, int n, int val) //iterativ
{
int inc, sfr, mij;
inc = 0;
sfr = n-1;
mij = (inc + sfr)/2;
while((inc <= sfr) && (val != p[mij]))
{
if(val < p[mij]) sfr = mij - 1;
else inc = mij + 1;
mij = (inc + sfr) / 2;
}
if(p[mij] == val)
return mij;
else
3
return -1;
}
int CautareBinara(int *p, int inc, int sfr, int val) //recursiv – divide et
// impera
{
int mij;
mij = (inc + sfr)/2;
if(p[mij] == val)
return mij;
9
// utilizarea functiei de biblioteca bsearch()
#include <stdlib.h>
#include <stdio.h>
#include <conio.h>
int main(void){
int int_values[] = {1, 2 , 3, 4, 5};
float float_values[] = {1.1, 2.2, 3.3, 4.4, 5.5};
if (int_ptr)
printf("Valoarea %d a fost gasita!\n", int_value);
else
printf("Valoarea %d nu a fost gasita!\n", int_value);
num = sizeof(float_values)/sizeof(float);
11
//apel la functia de bibioteca bsearch() pentru sirul de numere reale
float_ptr = (float *)bsearch(&float_value, float_values, num,
sizeof(float),(int (*) (const void *, const void *)) compare_float);
if (float_ptr)
printf("Valoarea %3.1f a fost gasita!\n", float_value);
else
printf("Valoarea %3.1f nu a fost gasita!\n", float_value);
_getch();
}//end main()
12
int compare_int(int *a, int *b)
{
return(*a - *b);
} //end compare_int()
13
Metode de sortare- Generalități
Sortarea constă în rearanjarea obiectelor într-o ordine
specifică, prin permutarea acestora
Pentru un set de obiecte S={a1, a2, ..., an}, prin sortare
rezultă setul S1={ak1, ak2, ..., akn}, astfel că, dându-se o
funcţie de ordonare f, este îndeplinită relaţia de ordine :
f(ak1) < f(ak2) <...< f(akn)
Sortarea se face în raport cu o cheie asociată obiectelor
Eficienţa unei metode de sortare se evaluează prin:
numărul de comparaţii ale cheii
numărul de permutări ale unui obiect
16
Sortarea prin interschimbare (bubble sort)
17
EXEMPLU BUBBLE-SORT
Exemplu : 9 7 5 6 2
7 9 5 6 2 -> 7 5 9 6 2 -> 7 5 6 9 2 -> 7 5 6 2 9
5 7 6 2 9 -> 5 6 7 2 9 -> 5 6 2 7 9
5 6 2 7 9 -> 5 2 6 7 9
5 2 6 7 9 -> 2 5 6 7 9
Exemplu : 9 2 5 6 7:
9 2 5 6 7 -> 2 9 5 6 7 -> 2 5 9 6 7 -> 2 5 6 9 7 -> 2 5 6 7 9
25679
20
void SortBubble(int *p, int n)
{
int i, j, temp, flag;
for(i=0; i<n; i++) {
flag = 0;
for(j=1; j<n-i; j++) {
if(p[j-1] > p[j]) {
// interschimbare
temp = p[j];
p[j] = p[j-1];
p[j-1] = temp;
flag = 1;
}
}
// daca nu s-a facut nici o interschimbare
if(flag == 0) break;
} 21
}
//bubble sort (varianta do-while)
void SortBubbleD(int *p, int n)
{
int j, temp, flag;
do{
flag = 0;
for(j=0; j<n-1; j++) {
if(p[j] > p[j+1]) {
temp = p[j];
p[j] = p[j+1];
p[j+1] = temp;
flag = 1;
}
}//for
}while(flag != 0);
}
22
Sortarea prin selecţie simplă
se caută cel mai mic element şi se aduce pe prima
poziţie din şir prin interschimbare
apoi se consideră tabloul format din elementele
2,3,...,N şi se caută cel mai mic element care se
aduce pe prima poziţie din şirul curent, ...
Exemplu : 9 7 5 6 2
9 7 5 6 2 -> 2 7 5 6 9 -> 2 5 7 6 9 -> 2 5 6 7 9
23
void SortSel(int *p, int n){
int i, j, pozmin, temp;
for(i=0; i<n; i++) // parcurgeri
{
// cautare pozitie cel mai mic element din sirul curent
pozmin = i;
for(j=i+1; j<n; j++) {
if(p[pozmin] > p[j])
pozmin = j;
}
// interschimbare cu elementul de pe prima pozitie
temp = p[pozmin];
p[pozmin] = p[i];
p[i] = temp;
} 24
}
Sortarea prin inserţie simplă
se consideră pe rând tablourile formate din primele
2,3,...,N elemente din vector
se asigură că aceste tablouri sunt ordonate prin
aducerea noului element (2,3,...) pe poziţia
corespunzătoare valorii sale
acest lucru implică deplasarea spre dreapta, cu o
poziţie, a elementelor cu chei mai mari decât cea a
noului element, astfel ca acesta să ajungă înaintea
acelor elemente, dar după elementele cu chei mai mici
25
EXEMPLU INSERȚIE SIMPLĂ
Exemplu : 9 7 5 6 2
97 -> 79
7 9 5 -> 579
5 7 9 6 -> 5679
5 6 7 9 2 -> 25679
26
void SortIns(int *p, int n){
int i, j, temp;
for(i=1; i<n; i++) {
temp = p[i];
for(j=i-1; j>=0; j--) // tabloul curent
{
if(p[j] > temp)
p[j+1] = p[j]; // deplasare dreapta
else
break;
}
p[j+1] = temp;
} 27
}
Observaţie:
poziţia pe care trebuie adus noul element este
căutată secvenţial (pe un subşir deja ordonat),
astfel că algoritmul se poate îmbunătăţi
(elementele analizate fiind deja sortate), folosind
căutarea binară
28
void SortIns(int *p, int n){
int i, j, temp, inc, mij, sfr;
for(i=1; i<n; i++) {
temp = p[i];
// cautarea binara
inc = 0;
sfr = i-1;
mij = (inc + sfr)/2;
while(inc <= sfr) {
if(p[mij] > temp)
sfr = mij-1;
else
inc = mij+1;
mij = (inc + sfr)/2;
}
for(j=i-1; j>=inc; j--)
p[j+1] = p[j]; // deplasare dreapta
p[inc] = temp; 29
}
}
ALGORITMUL SHELL SORT
ShellSort este un algoritm de sortare performant, bazat
pe sortarea prin inserție (InsertSort)
30
ALGORITMUL SHELL SORT
Algoritmul ShellSort realizează deplasări pe distanţe
mari, sortând elementele aflate la distanţe mari prin
metoda inserţiei.
h=4
7 10 1 9 2 5 8 6 4 3
* *
2 10 1 9 7 5 8 6 4 3
* *
2 5 1 9 7 10 8 6 4 3
* *
2 5 1 6 7 10 8 9 4 3
* * *
2 5 1 6 4 10 8 9 7 3
* * *
2 3 1 6 4 5 8 9 7 10
32
h=1
2 3 1 6 4 5 8 9 7 10
*
1 2 3 6 4 5 8 9 7 10
*
1 2 3 4 6 5 8 9 7 10
*
1 2 3 4 5 6 8 9 7 10
*
1 2 3 4 5 6 7 8 9 10
33
void ShellSort(int *p, int max){
int stop=0,temp=0,h=0, i, j , k;
while( h<= max/3)
h = 3*h + 1; // se porneste de la un h>max/3
while(h>0) {
for(int i=h; i<max; i++) { // se ia fiecare element de la pozitia h
// pana la sfarsit
temp=p[i];
j=i;
while((j>=h)&&(p[j-h]>temp)) {
p[j]=p[j-h]; // deplasare dreapta
j=j-h;
}
p[j]=temp;
} //for
h = (h-1)/3; // modificarea distantei de comparare
}// while 34
}
Observaţii:
toate exemplele anterioare realizează sortarea prin
ordonarea crescătoare a unor numere întregi
Temă:
modificaţi aceste funcţii de sortare pentru a realiza
sortări prin ordonare descrescătoare pentru toate
tipurile aritmetice
35
Exemplul 1: utilizarea unei funcţii de sortare:
#include <iostream>
using namespace std;
int main( ){
int i, n, *tab;
cout <<"Cate numere: ";
cin >> n;
39
Exemplul 3
#include <iostream>
using namespace std;
int fcmp(char *s1, char *s2);
void BubbleSort (char **names, const int size);
int main(void) {
int dimc = 6;
const char *tabc[] = {"abc", "xyz", "acd", "axyz", "bc", "eltcti"};
BubbleSort(tabc, dimc); //sortare crescatoare dupa dimensiune
cout << "\nSirurile sortate: ";
for(int i=0;i<dimc; i++)
cout << tabc[i] << ", ";
cout << endl;
}
40
void BubbleSort (char **names, const int size) {
int swapped;
do {
swapped = 0;
for (int i = 0; i < size-1; ++i) {
if (fcmp(names[i], names[i+1]) > 0 ) {
char *temp = names[i];
names[i] = names[i+1];
names[i+1] = temp;
swapped = 1;
}
}
} while (swapped);
}
42
43
3.2.2. Metode avansate de sortare
44
SORTAREA PRIN INTERCLASARE (MERGE SORT)
Principiul metodei: se bazează pe obținerea din 2 vectori
ordonati a unui vector ordonat ce conține elementele
celor 2 vectori.
Sortarea prin interclasare utilizează metoda Divide et
Impera
Se împarte vectorul inițial nesortat în secvențe din ce în
ce mai mici, astfel încât fiecare secvență să fie ordonată
la un moment dat și apoi interclasată cu o altă secvență
din vector.
Practic interclasarea va începe când se ajunge la o
secvență formată din două elemente. Aceasta odată
ordonată se va interclasa cu o alta corespunzătoare, iar
apoi procesul va continua la următorul nivel ce implică
perechi de câte 4 elemente, etc.
45
46
#include<iostream>
using namespace std;
void interclas(int *a,int i,int m,int j);
// i- pozitia de inceput a primului subsir, m- pozitia de sfarsit a primului
subsir,
// j- pozitia de sfarsit al celui de-al doilea subsir
void divimp(int *a,int i,int j);
// i- indicele primului element din vector,
// j - indicele ultimului element din vector
#define DIM 1000
void main(){
int a[DIM],n;
cout<<"n="; cin>>n;
for(int i=0;i<n;i++){
cout<<"a["<<i<<"]=";
cin>>a[i];
} 47
divimp(a,0,n-1);
for(int i=0;i<n;i++)
cout<<a[i]<<' ';
} //main
50
Algoritmul QuickSort
Se bazează pe noţiunea de partiţie
Prin partiţionarea datelor se înţelege împărţirea
acestora în două grupuri, astfel încât toate elementele
cu chei mai mari decât o valoare dată se află într-un
grup, iar cele cu valori mai mici se află în celălalt grup
Etapele partiţionării :
se consideră un element x al tabloului numit şi element
pivot
se parcurge tabloul de la stânga până ce se găseşte un
element ai mai mare ca x
se parcurge tabloul de la dreapta până ce se găseşte un
element aj mai mic ca x
51
se interschimbă ai cu aj
se actualizează i şi j prin incrementare, respectiv
decrementare
se repetă paşii anteriori până când cele două scanări se
întâlnesc
în acest moment tabloul este partiţionat, adică :
în stânga lui x se găsesc numai elemente mai mici ca x
în dreapta lui x se găsesc numai elemente mai mari ca x
a[k] <= x, k = 0,...,i-1
a[k] >= x, k = j+1,...,n
a[k] = x, k = j+1,...,i-1
52
După prima partiţionare, şirul nu este încă ordonat
De aceea se continuă, la stânga şi la dreapta pivotului,
în acelaşi mod.
- algoritmul QuickSort are o natură recursivă
QuickSort is
{
If (right-left) == 0 then
Return
Else
pivot = Tablou[right]; // sau Tablou[middle]
partition = Partitionare(left, right, pivot)
QuickSort(left, partition-1);
QuickSort(partition+1, right);
EndIf 53
}
Pivotul este elementul din mijlocul sirului
88 6 57 71 60 42 83 73 48 65
48 6 57 71 60 42 83 73 88 65
48 6 57 42 60 71 83 73 88 65
6 48 57 42 60 71 65 73 88 83
6 48 42 57 60 65 71 73 83 88
6 42 48 57 60 65 71 73 83 88
Pivotul este ultimul element din șir
88 6 57 71 60 42 83 73 48 65
inc sfr
65 6 57 71 60 42 83 73 48 88
inc
65 6 57 48 60 42 83 73 71 88
inc sfr
42 6 57 48 60 65 83 73 71 88
sfr inc inc
42 6 57 48 60 65 71 73 83 88
sfr inc
6 42 57 48 60 65 71 73 83 88
6 42 57 48 60 65 71 73 83 88
6 42 48 57 60 65 71 73 83 88
void QuickSort(int *p, int prim, int ultim)
{
int inc, sfr, pivot, temp, mij;
inc = prim;
sfr = ultim;
mij=(prim+ultim)/2;
pivot = p[mij];
// partitionare
do {
while(p[inc] < pivot)
inc++;
while(p[sfr] > pivot)
sfr--;
56
if(inc < sfr) {
temp = p[inc];
p[inc] = p[sfr];
p[sfr] = temp;
}
if(inc <= sfr) {
sfr--;
inc++;
}
}while(inc <= sfr);
// apel recursiv
if(prim < sfr)
QuickSort(p, prim, sfr);
if(inc < ultim)
QuickSort(p, inc, ultim);
57
}
Alegerea valorii pivot :
pivotul trebuie să reprezinte valoarea cheii unui element
din tablou
se poate alege la întâmplare, dar trebuie evitate
valoarea minimă, respectiv maximă
Valori uzuale :
elementul din mijlocul tabloului
ultimul element din tabloul partiţionat
valoarea mediană între primul, ultimul şi elementul din
mijlocul tabloului
58
Biblioteca standard (stdlib.h) pune la dispoziţie funcţia:
void qsort(void *base, size_t nelem, size_t width,
int(*fcmp)(const void *, const void *));
void main(void){
int i,n,tab[DIM];
printf("Introdu dimensiune tablou: ");
scanf("%d",&n);
printf("Introdu elemente tablou:\n");
for(i=0;i<n;i++){
printf("tab[%d] = ",i);
scanf("%d",&tab[i]);
}
fcmp=compara; //fcmp va avea adresa functiei de comparare 60
qsort(tab,n,sizeof(i),fcmp);
puts("Tabloul ordonat este");
for(i=0;i<n;i++)
printf("%d ",tab[i]);
_getch();
}//main
int compara(const void * val1, const void* val2)
{
//return((*(int*)val1) - (*(int*)val2)); //ordonare crescatoare
return((*(int*)val2) - (*(int*)val1)); //ordonare descrescatoare
} //compara
61
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>
struct datac {
int an;
int luna;
int zi;
};
struct pers {
char numep[12];
struct datac datan;
};
62
int cmp( const struct pers *a, const struct pers *b);
void main(void){
struct pers angaj[ ] = {
{"x1", {1980, 6,6}},
{"x2", {1960, 5, 5}},
{"x3", {1960, 1,5}},
{"x4", {1961, 12, 32}},
{"x5", {1980, 2, 29}}
};
int i;
int nang = sizeof(angaj)/sizeof(struct pers);
// apel functie de sortare
qsort((void *)angaj, nang, sizeof(angaj[0]), (int (*)(const void*, const
void*))cmp);
printf("Datele sortate :\n");
for (i = 0; i < nang; i++) {
printf("\t%s, %d, %d, %d\n", angaj[i].numep, angaj[i].datan.an,
angaj[i].datan.luna, angaj[i].datan.zi);
}
_getch(); 63
}
int cmp(const struct pers *a, const struct pers *b){
if((a->datan).an > (b->datan).an) return 1;
else
if((a->datan).an < (b->datan.an)) return -1;
else {
if((a->datan).luna > (b->datan).luna) return 1;
else if((a->datan).luna < (b->datan).luna) return -1;
else {
if((a->datan).zi > (b->datan).zi)
return 1;
else if((a->datan).zi < (b->datan).zi)
return -1;
else
if((strcmp(a->numep, b->numep)>0)) return 1;
else if((strcmp(a->numep, b->numep)<0))
return -1;
return 0;
} //else 64
}// else
}
65