This is an old revision of the document!


Laboratorul 6: Algoritmi de sortare 2

1. Obiectivele laboratorului

  • Înțelegerea structurii și proprietăților unui heap
  • Implementarea algoritmilor de sortare heap și radix sort (cu măsurarea timpului de execuție)

2. Introducere

2.1 Heap

Există mai mutle tipuri de heap, dar ne vom referi numai la binary heap pentru implementarea algoritmului Heap sort.

Un heap binar este un arbore binar cu următoarele proprietăţi:

  • este „complet“ (toate nivelele sunt pline, cu posibila excepţie a ultimului nivel), adică de înălţime minimă
  • există aceeaşi relaţie de ordine între orice nod şi părintele acestuia (excepţie - nodul rădăcină).

Dacă nodurile conţin numere întregi după care stabilim relaţia de ordine, heap-ul poate fi de două feluri:

  • max-heap (rădăcina are cel mai mare număr, de la orice copil la părinte avem relaţia mai mic sau egal)
  • min-heap (rădăcina are cel mai mic număr, de la orice copil la părinte avem relaţia mai mare sau egal)

2.2 Bucket-uri

Un pas din algoritmul Radix sort foloseşte o funcţie de indexare. Aceasta prelucrează cheia fiecărui element pentru a decide câte elemente să pună în fiecare sector (bucket).

  • Sectoarele pot exista ca vectori independenţi sau ca un singur vector în care marcăm poziţia la care începe fiecare sector.
  • Este recomandat ca funcţia de indexare să existe explicit (să fie definită ca subprogram) atunci când are o formă complicată. Dacă are o formă simplă (cum ar fi o singură operaţie), această parte poate fi omisă.

2.3 Operații pe biți

Menţionăm următoarele operaţii pe biţi ce se pot folosi în C/C++ :

Operaţii logice

  • & şi pe biţi (bitwise AND)
  • | sau pe biţi (bitwise OR)
  • ^ sau exclusiv pe biţi (bitwise XOR)
  • ~ complement pe biţi (bitwise NOT)

Deplasări

  • » la dreapta (right shift)
  • « la stânga (left shift)

Descriem numai operaţiile pe care le vom folosi în cadrul exemplului de mai jos: » şi &.

  • Operaţia n » k are ca rezultat valoarea obţinută prin mutarea la dreapta a tuturor biţilor lui n (pe primii k biţi se obţine 0, iar ultimii k biţi din n sunt ignoraţi).
  • Operaţia n & k are ca rezultat valoarea obţinută prin păstrarea biţilor nenuli din n pentru poziţiile pe care şi k are biţi nenuli (0 în rest)

Dacă n este număr natural şi k = 2p, atunci:

  • n » p == n / k
  • n & (k - 1) == n % k

Apar diferenţe în cazul numerelor negative.

3. Algoritmii de sortare

3.1 Heap Sort
  • Timp mediu: O(N log N)
  • Timp la limită: O(N log N)
  • Memorie: O(1)
  • Stabil: NU

Descriere :

  • Metoda de sortare prin selecţie directă se bazează pe selecţia repetată a ultimei chei dintre n elemente, apoi dintre n-1 elemente rămase, etc.
  • Pentru a găsi cea mai mică cheie dintre n elemente sunt necesare n-1 comparaţii, apoi găsirea următoarei dintre n-1 elemente are nevoie de n-2 comparaţii, etc. ⇒ n(n-1)/2 comparaţii.
  • Această sortare se poate îmbunătăţi prin reţinerea, de la fiecare scanare, de mai multă informaţie decât identificarea unui singur element, cel mai mic.
  • De exemplu, cu n/2 comparaţii se poate determina cheia mai mică pentru fiecare pereche de elemente dintre cele n elemente, apoi cu alte n/4 comparaţii se poate determina cheia cea mai mică pentru fiecare pereche ale cheilor determinate anterior, şi aşa mai departe. Astfel, cu n-1 comparaţii se poate construi arborele de selecţie.

Descriem următorii paşi pentru o variantă de implementare a algoritmului Heap sort (ordonare crescătoare):

  • presupunem că vectorul formează un arbore binar, fiecare poziţie din vector reprezentând un nod, cu rădăcina pe poziţia 0 (zero) şi cu fiecare nod k având copiii 2k+1 şi 2k+2 (dacă nu există poziţia din vector cu indicele respectiv, atunci nu există nod copil ⇒ NULL)
  • formăm un max-heap cu aceeaşi reprezentare (pe vector, fără a construi altă structură pentru noduri)
  • extragem maximul din rădăcina heap-ului (poziţia 0 din vector) şi facem o intersschimbare între poziţia maximului şi ultima poziţie din vector. Acum maximul se află pe poziţia dorită şi putem să-l excludem din heap.
  • repetăm paşii (refacem forma de heap, extragem noul maxim, reducem cu 1 numărul de elemente nesortate), cât timp mai sunt elemente în heap.

Definim următoarele două funcţii pentru a prezenta mai usor algoritmul Heap sort:

  • funcţia „cerne“ (asigură „cernerea“/„scurgerea“/„căderea“ nodului k până poziţia necesară pentru heap) - dacă nodul k nu are valoarea mai mare decât a copiilor lui (nu se păstrează relaţia de ordine a heap-ului), atunci nodul k va fi „cernut“ până va fi respectată relaţia.
  • funcţia „makeHeap“ (formează max heap-ul) - funcţia cerne toate nodurile pentru a obţine un heap

Implementare:

void schimba(int a[],int i,int j) //functie auxiliara
{
    int aux;
    aux = a[i];
    a[i] = a[j];
    a[j] = aux;
}
void cerne(int a[],int n,int k)
{
    int fiuStanga = 2 * k + 1, //pozitia primului copil
        fiuDreapta = 2 * k + 2,
        pozMax = fiuStanga; //pozitia copilului mai mare
    if(fiuStanga >= n)
        return; //"nodul" k este frunza
    if(fiuDreapta < n) {
        if(a[fiuDreapta] > a[fiuStanga] ) {
            pozMax = fiuDreapta;
        }
    }//am ales copilul mai mare
    if(a[k] < a[pozMax]) {
        schimba(a,k,pozMax); //nodul k este "cernut" - coboara
        cerne(a,n,pozMax); //cernem la noua lui pozitie
    }
}
void makeHeap(int a[],int n) //functia mai e numita "heapify"
{
    //pentru i > n / 2, i este cu siguranta nod frunza
    for(int i = n / 2;i >= 0;i--) { //ne asiguram ca exista ordine
        cerne(a,n,i); // pentru orice nod de la i la n-1
    }
}
void heapSort(int a[],int n)
{
    makeHeap(a,n); //construim un heap
    while(n > 1) {
        schimba(a,0,n-1); //mutam maximul pe ultima pozitie
        n--; //am asezat un element pe pozitia finala
        cerne(a,n,0); //elementul pus in locul maximului trebuie "cernut"
        //obtinem din nou forma de heap
    }
 
}

4. Exerciții

  1. Se dă un vector cu n întregi (citit din fișierul input.txt, câte un număr pe fiecare linie). Scrieţi o funcţie care să creeze un arbore binar de căutare cu valorile din vector. Scrieţi o funcţie care verifică dacă arborele este binar de căutare. Scrieţi o funcţie care verifică dacă o valoare (generată aleator) dată se află în arbore (căutare). Acelaşi arbore – inserare (şi să rămână arbore de căutare). Acelaşi arbore – ştergere (şi să rămână arbore de căutare). [80% nota]
  2. Același enunț ca ex. 1 dar acum păstrați arborele echilibrat (AVL). [20% nota]

5. Probleme opționale, de interviu

  1. Se dă V (un vector de n întregi) şi P (un vector de taţi de lungime n). Verificaţi dacă se poate construi un arbore binar de căutare cu valorile din V şi legăturile copil-părinte din P.
  2. Propuneți soluții eficiente pentru a programa un program de tip “auto-complete” pentru o listă de cuvinte (în timp ce tastați se afișează cele mai probabile 3 cuvinte la care vă referiți). Hint: verificați/căutați trie sau arbori de prefixe.
sda-aa/laboratoare/07.1618198936.txt.gz · Last modified: 2021/04/12 06:42 by cristian.rusu
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0