Sunteți pe pagina 1din 237

Universitatea Lucian Blaga din Sibiu,

Catedra de Calculatoare i Automatizri

Analiza i proiectarea
algoritmilor
Curs, anul II Calculatoare, Tehnologia informaiei,
Ingineria sistemelor multimedia
Puncte de credit: 5

Autor: Dr. rpd GELLRT


Web: http://webspace.ulbsibiu.ro/arpad.gellert
E-mail: arpad.gellert@ulbsibiu.ro

Cuprins (1)
Partea I Limbajul Java


Structura lexical i instruciuni

Variabile i constante

Tablouri i matrici

Tratarea excepiilor

Operaii I/O

Crearea claselor

Interfee grafice

Fire de execuie

Colecii
2

Cuprins (2)
Partea II Analiza algoritmilor








Complexitate, notaii asimptotice


Recurene
Algoritmi de cutare i sortare
Tabele de dispersie
Arbori binari
Heap-uri
Grafuri

Cuprins (3)
Partea III Proiectarea algoritmilor







Divide et impera
Greedy
Programare dinamic
Backtracking
Algoritmi genetici
Reele neuronale

Nota final
Nota laborator (NL) = 0,2*T1 + 0,2*T2 + 0,1*A + 0,5*C
Nota final = 0,5*NL + 0,5*E


T1 = Test gril susinut din noiunile predate n cadrul


capitolului Limbajul Java;

T2 = Test susinut la laborator din aplicaiile propuse la


laborator n cadrul capitolului Limbajul Java;

A = Activitatea la laborator (teme);

C = Colocviu de laborator din aplicaiile propuse la laborator n


cadrul capitolelor Analiza algoritmilor respectiv Proiectarea
algoritmilor;
E = Examen susinut din capitolele Analiza algoritmilor i
Proiectarea algoritmilor.
5

Bibliografie de baz
[Knu00] Knuth D., Arta programrii calculatoarelor, Teora, 2000.
[Cor00] Cormen T., Leiserson C., Rivest R., Introducere n algoritmi, Agora, 2000.
[Giu04] Giumale C., Introducere n analiza algoritmilor, Polirom, 2004.
[Wai01] Waite M., Lafore R., Structuri de date i algoritmi n Java, Teora, 2001.
[Log07] Logoftu D., Algoritmi fundamentali n Java, Polirom, 2007.
[Tan07] Tanas ., Andrei ., Olaru C., Java de la 0 la expert, Polirom, 2007.

Introducere (1)


Geneza cuvntului algoritm: provine din


latinizarea numelui savantului Al-Khwarizmi
(algoritmi) matematician, geograf,
astronom i astrolog persan (780-850),
considerat i printele algebrei moderne.

Algoritmul este o secven de operaii care transform


mulimea datelor de intrare n datele de ieire.

Proiectarea algoritmului const n dou etape:




Descrierea algoritmului printr-un pseudolimbaj (schem logic,


pseudocod);
Demonstrarea corectitudinii rezultatelor n raport cu datele de
intrare.

Analiza algoritmului se refer la evaluarea


performanelor acestuia (timp de execuie, spaiu de
memorie).

Introducere (2)


Imlementarea algoritmilor se va face n limbajul Java. Medii de


dezvoltare:


Java Development Kit (JDK) http://www.sun.com

Eclipse http://www.eclipse.org

Java Builder

NetBeans

Principalele caracteristici ale limbajului Java:




Simplitate elimin suprancrcarea operatorilor, motenirea multipl, etc.;

Complet orientat pe obiecte;

Portabilitate Java este un limbaj compilat i interpretat, fiind astfel


independent de platforma de lucru (Write Once, Run Enywhere);

Ofer posibilitatea, prin JNI (Java Native Interface), de a implementa aplicaii


mixte (ex. Java/C++), preul folosirii codului nativ fiind ns dependena de
platform [Gor98];
Permite programarea cu fire de execuie.
8

Introducere (3)
Cod surs

.java

Bytecode

Compilator
Java

.class

Java
Virtual
Machine

n urma compilrii codului surs, se obine codul de octei (bytecode)


care este apoi interpretat de maina virtual Java (JVM). Astfel,
aplicaia poate fi rulat pe orice platform care folosete mediul de
execuie Java.
Pe lng aplicaii obinuite, pot fi implementate aplicaii web (applet),
aplicaii server (servlet, JavaServer Pages, etc.), aplicaii n reea,
telefonie mobil (midlet), aplicaii distribuite RMI (Remote Method
Invocation), etc.
Compilarea programelor (javac.exe):

javac *.java


Rularea programelor (java.exe):

java *
9

Partea I
Limbajul Java

Limbajul Java
O aplicaie simpl:
class HelloWorld{
public static void main(String args[]){
System.out.println("Hello world");
}
}



Aplicaia HelloWorld afieaz la consol mesajul Hello world.


n orice aplicaie trebuie s existe o clas primar, care conine
metoda main de la care ncepe execuia n momentul rulrii.
Parametrul args al metodei main este un tablou de iruri de
caractere i reprezint argumentele din linie de comand.

Fiierul care conine clasa primar trebuie s aib numele clasei


(case sensitive!).

Java permite o singur clas public ntr-un fiier.

Compilarea programului: javac HelloWorld.java

Rularea programului: java HelloWorld

11

Limbajul Java convenii de scriere a codului [Web01]




Principalele segmentele ale codului Java apar n urmtoarea ordine:




Declaraia de pachet (package);

Directivele de import;

Declaraia de clas sau interfa;

Declaraiile variabilelor membru ale clasei (statice) sau ale instanei;

Constructori i metode;

Convenii de nume


Numele de clase, implicit de constructori, ncep cu majuscul (ex.:


NumeClasa);

Numele de metode ncep cu liter mic (ex.: numeMetoda);

Numele de variabile i obiecte ncep cu liter mic (ex.: numeObiect);

Numele constantelor se scriu cu majuscule, cuvintele fiind desprite


prin _ (ex.: NUME_CONSTANTA);

Numele trebuie s fie ct mai sugestive.

12

Limbajul Java Structura lexical


Structura lexical a limbajului Java este foarte asemntoare cu cea
a limbajului C++.


Comentariile se fac ca n C++.

Operatorii sunt n mare parte la fel ca n C++.

Instruciunile sunt i ele foarte asemntoare cu cele din C++. O


diferen important const n faptul c expresiile care apar n
instruciunile condiionale (if, for, while, do) sunt strict de tip
boolean, n timp ce n C++ pot fi de tip int.
Tipurile de date se clasific n dou categorii:


Tipuri de date primitive: byte (1 octet), short (2 octei), int (4 octei),


long (8 octei), char (2 octei unicode), float (4 octei), double (8
octei), boolean (1 bit);
Tipuri de date referin: clase, interfee, tablouri. Exist i variantele
referin ale tipurilor de date primitive: Byte, Short, Integer, Long,
Character, Float, Double, Boolean. Variantele referin ale tipurilor de
date primitive sunt necesare pentru c n Java nu exist operatorul &
pentru definiia unei referine. Pentru iruri de caractere, pe lng
char[], exist i tipul referin String.
13

Limbajul Java variabile




Variabilele primitive se pot crea prin declaraie. Exemple:





Variabilele referin se pot crea doar cu operatorul new (care returneaz


o referin), exceptnd variabilele de tip String care se pot crea i prin
declaraie. Exemple:




int i = 10;
float pi = 3.14f;

Integer integer = new Integer(10);


String strHello = new String(Hello);
String strWorld = world;

n Java nu este admis suprancrcarea operatorilor, excepie fiind doar


operatorul de adunare pentru clasa String, care permite concatenarea
irurilor. Exemplu:
String strHello = Hello;
String strWorld = world;
String strHelloWorld = strHello + + strWorld;

Concatenarea unui String cu o variabil primitiv determin conversia


implicit a acesteia n String. Exemplu:
String strTwo = Two;
int i = 2;
boolean b = true;
String str = strTwo + = + i + is + b;

//Rezultat: Two = 2 is true


14

Limbajul Java constante







Pentru crearea unei constante, declaraia de variabil


trebuie precedat de cuvntul cheie final.
Nu este permis modificarea valorii unei constante.
O clas declarat final nu poate fi derivat (v.
motenirea).
Exemple
public class Main {
public static void main(String[] args) {
final String APA = "Analiza si proiectarea algoritmilor";
final int TEN = 10;
TEN++;
//Eroare!
APA = "Analiza, proiectarea si implementarea algoritmilor"; //Eroare!
int eleven = TEN + 1;
}
}
15

Limbajul Java clasa String (1)


Principalele operaii:


substring cu parametrii index0 i indexf returneaza subirul care ncepe


la index0 i se termin la indexf-1, lungimea fiind indexf-index0. Exemplu:
String str = Hello world;
String substr = str.substring(0, 5);

charAt returneaz caracterul de pe o anumit poziie din ir. Exemplu:


String str = Hello world;
char c = str.charAt(6);

//Rezultat: w

length retuneaz lungimea irului n numr de caractere. Exemplu:


String str = Hello world;
int len = str.length();

//Rezultat: Hello

//Rezultat: 11

equals / equalsIgnoreCase permite comparaia unui ir cu alt ir.


Returneaz true dac cele dou iruri sunt egale, respectiv false dac ele
nu sunt egale. Exemplu:
String hello = Hello;
if(hello.equals(Hello))
System.out.println(equal);

//Rezultat: true
//Rezultat: equal

16

Limbajul Java clasa String (2)




compareTo / compareToIgnoreCase compar dou iruri.


Returneaz valoarea 0 dac cele dou iruri sunt lexicografic egale, o
valoare negativ dac parametrul este un ir lexicografic mai mare
dect irul curent i o valoare pozitiv dac parametrul este un ir
lexicografic mai mic dect irul curent. Exemplu:
String hello = Hello;
if(hello.compareTo(Hello) == 0)
System.out.println(equal);

trim elimin eventualele spaii de la nceputul i sfritul irului.


Exemplu:
String hello = Hello ;
System.out.println(hello.length()) ;
hello = hello.trim();
System.out.println(hello.length()) ;

//Rezultat: 0
//Rezultat: equal

//Rezultat: 7
//Rezultat: 5

toLowerCase / toUpperCase transform toate literele din ir n


litere mici / mari. Exemplu:
String str = Hello world;
str = str.toUpperCase();

//Rezultat: HELLO WORLD


17

Limbajul Java clasa StringTokenizer





Permite separarea unui ir de caractere n simboluri;


Se instaniaz un obiect StringTokenizer, specificnd irul
de caractere i setul de delimitatori;
Urmtoarea secven de program afieaz pe ecran
simbolurile (cuvintele) irului delimitate prin caracterele
spaiu i virgul:
String apia = "Analiza, proiectarea si implementarea algoritmilor";
StringTokenizer st = new StringTokenizer(apia, " ,");
while(st.hasMoreTokens())
System.out.println(st.nextToken());

Setul de delimitatori poate fi specificat i prin funcia


nextToken:
while(st.hasMoreTokens())
System.out.println(st.nextToken(" ,"));

18

Limbajul Java tablouri




Posibiliti de declarare a tablourilor:






int[] fibo =
int fibo[] =
int n = 10;
int fibo[] =
int fibo[] =

new int[10];
new int[10];
new int[n];
{0, 1, 1, 2, 3, 5, 8, 13, 21, 34};

Tablou cu elemente primitive vs. referin:




int pTab[] = new int[5];

//tablou (referinta!) cu 5 elem. primitive

for(int i=0; i<pTab.length; i++)


pTab[i] = i+1;


Integer rTab[] = new Integer[5];

//tablou (referinta!) cu 5 elem. referinta

for(int i=0; i<rTab.length; i++)


rTab[i] = new Integer(i+1);


Afiarea elementelor unui tablou:


for(int i=0; i<fibo.length; i++)
System.out.println(fibo[i]);
19

Limbajul Java clasa Arrays


Principalele operaii:


fill permite umplerea tabloului sau a unei zone din tablou cu o anumit valoare:
int tab[] = new int[5];
Arrays.fill(tab, 7);
Arrays.fill(tab, 1, 3, 8);

equals compar dou tablouri returnnd true dac au toate elementele egale:
int a[] = {1,2,3,4};
int b[] = {1,2,3,4};
int c[] = {1,2,4,8};
System.out.println(Arrays.equals(a, b) ? "a==b" : "a!=b");
System.out.println(Arrays.equals(a, c) ? "a==c" : "a!=c");

//Rezultat: a==b
//Rezultat: a!=c

sort sorteaz elementele tabloului n ordine cresctoare folosind algoritmul Quicksort pentru tipuri primitive
respectiv Mergesort pentru tipuri referin:
int pTab[] = {9,6,2,1,5,3};
Arrays.sort(pTab,1,4);
Arrays.sort(pTab);
Integer rTab[] = new Integer[5];
for(int i=0, k=rTab.length; i<rTab.length; i++, k--)
rTab[i] = new Integer(k);
Arrays.sort(rTab);

//Rezultat: tab={7,7,7,7,7}
//Rezultat: tab={7,8,8,7,7}

//Rezultat: tab={9,1,2,6,5,3}
//Rezultat: tab={1,2,3,5,6,9}
//Rezultat : tab={5,4,3,2,1}
//Rezultat : tab={1,2,3,4,5}

binarySearch returneaz poziia elementului cutat n tablou sau o valoare negativ dac valoarea cutat
nu este gsit. Algoritmul folosit este cutarea binar, de aceea tabloul trebuie sortat nainte de apelul acestei
metode. Exemplu:
int tab[] = {5,4,1,7,3};
int v = Arrays.binarySearch(tab, 4);
Arrays.sort(tab);
v = Arrays.binarySearch(tab, 4);

//tablou nesortat
//Rezultat greit: -4
//Rezultat: tab={1,3,4,5,7}
//Rezultat corect: 2

20

Limbajul Java matrici




Posibiliti de declarare a matricilor:




int m[][] = new int[3][4];

int nRow=3, nCol=4;


int m[][] = new int[nRow][nCol];

int m[][] = new int[3][];


for(int i=0; i<3; i++)
m[i] = new int[4];
int m[][] = {{1,2,3,4},{5,6,7,8},{9,10,11,12}};

Tablou multidimensional cu numr variabil de coloane. Exemplu de alocare, iniializare i


afiare:
int m[][] = new int[3][];
for(int i=0, k=1; i<3; i++){
m[i] = new int[4+i];
for(int j=0; j<4+i; j++, k++)
m[i][j] = k;
}
for(int i=0; i<3; i++){
for(int j=0; j<4+i; j++)
System.out.print(m[i][j]+"\t");
System.out.println();
}

//Rezultat afiat:
//1 2 3 4
//5 6 7 8 9
//10 11 12 13 14 15

O matrice m are m.length linii i m[0].length coloane.


21

Limbajul Java conversii




Conversia variabilelor primitive




Conversie implicit. Exemplu:


int a = 3, b = 2;
double c = a/b;
Conversie explicit (casting). Exemplu:
double pi = 3.14;
int i = (int)pi;

//Conversie din double in int. Rezultat: 3

Conversia variabilelor primitive n variabile referin. Exemple:


int x = 10;
Integer y = new Integer(x);
float m = 3.14f;
Float n = new Float(m);
String str10 = String.valueOf(x);

//Conversie din int in double. Rezultat: 1.0

//Conversie din int in Integer


//Conversie din float in Float
//Conversie din int in String

Conversia variabilelor referin n variabile primitive. Exemple:


Integer zece = new Integer(10);
int z = zece.intValue();
Double p = new Double(3.14);
double q = p.doubleValue();
String str20 = 20;
int d = Integer.parseInt(str20);
String strPi = 3.14;
double pi = Double.parseDouble(strPi);

//Conversie din Integer in int


//Conversie din Double in duble
//Conversie din String in int
//Conversie din String in double

22

Limbajul Java comparaii




Variabile primitive (comparaie)


int a = 5;
int b = 5;
System.out.println(a==b ? "a==b" : "a!=b");

//Rezultat : "a==b"

Variabile referin


Comparaie greit (se compar adrese!):


Integer a = new Integer(5);
Integer b = new Integer(5);
System.out.println(a==b ? "a==b" : "a!=b");

//Rezultat: "a!=b"

Comparaie corect (se compar valori!):


Integer a = new Integer(5);
Integer b = new Integer(5);
System.out.println(a.equals(b) ? "a==b" : "a!=b");

//Rezultat : "a==b

Comparaie corect (se compar valori!):


Integer a = new Integer(5);
Integer b = new Integer(5);
System.out.println(a.compareTo(b)==0 ? "a==b" : "a!=b");

//Rezultat: "a==b"

Comparaie corect (se compar valori!):


Integer a = new Integer(5);
Integer b = new Integer(5);
System.out.println(a.intValue()==b.intValue() ? "a==b" : "a!=b");

//Rezultat: "a==b"
23

Limbajul Java clasa File (1)


Clasa File ofer informaii despre fiiere i directoare i permite
redenumirea respectiv tergerea acestora. Principalele operaii:


length returneaz dimensiunea n octei a fiierului;

getName returneaz numele fiierului;

getPath / getAbsolutePath / getCanonicalPath returneaz calea fiierului;

getAbsoluteFile / getCanonicalFile returneaz un obiect File aferent fiierului;

isFile / isDirectory returneaz true dac e fiier / director;

canRead / canWrite returneaz true dac aplicaia poate citi / modifica fiierul;

exists verific dac fiierul exist;

delete terge fiierul sau directorul;

deleteOnExit terge fiierul sau directorul la nchiderea mainii virtuale;

list apelat pentru un director returneaz un tablou de tip String cu toate fiierele i
subdirectoarele din acel director. Exemplu:
File file = new File("e:\\algoritmi_curs");
String str[] = file.list();
for(int i=0; i<str.length; i++)
System.out.println(str[i]);

listFile apelat pentru un director returneaz un tablou de tip File cu toate fiierele i
subdirectoarele din acel director;
listRoots returneaz un tablou de tip File reprezentnd rdcinile sistemelor de fiiere
disponibile n sistem (ex.: "C:\\", "D:\\", "E:\\");
24

Limbajul Java clasa File (2)




mkdir creeaz un director nou, returnnd true n caz de succes. Exemplu:


File file = new File("algoritmi");
System.out.println(file.mkdir());




mkdirs creeaz un director nou, inclusiv directoarele inexistente care apar n cale
renameTo permite redenumirea fiierelor, returnnd true n caz de succes. Exemplu:
File file = new File("Algoritmi.pdf");
System.out.println(file.renameTo(new File("algoritmi_curs.pdf")));

separator / separatorChar returneaz un String / char reprezentnd separatorul


dependent de sistem: '/' n UNIX respectiv '\' n Win32.

25

Limbajul Java clasa System


Principalele operaii





currentTimeMillis returneaz un long


reprezentnd timpul n milisecunde. Poate fi folosit ca
parametru n constructorul clasei Date pentru
obinerea datei i orei n formatul dorit.
exit(0) provoac ieirea din aplicaie.
gc ruleaz mecanismul de garbage collector pentru
eliberarea zonelor de memorie ocupate de obiecte
neutilizate.
getProperties returneaz un obiect Properties din
care se pot extrage diferite informaii referitoare la
sistemul de operare.
26

Limbajul Java clasa Math


Cteva exemple
public class Main {
public static void main(String[] args) {
double pi = Math.PI;
System.out.println(pi);
System.out.println(Math.round(pi));
System.out.println(Math.floor(pi));
System.out.println(Math.ceil(pi));
System.out.println(Math.pow(2, 3));
System.out.println(Math.sqrt(9));
System.out.println(Math.exp(1));
double e = Math.E;
System.out.println(e);
System.out.println(Math.min(2, 8));
System.out.println(Math.max(2, 8));
System.out.println(Math.abs(-5));
System.out.println(Math.log(e));
System.out.println(Math.random());
System.out.println(Math.sin(pi/2));
System.out.println(Math.toDegrees(pi/2));
System.out.println(Math.toRadians(180));
}
}

//3.141592653589793
//3 - rotunjire la cel mai apropiat intreg
//3.0 - rotunjire in jos
//4.0 - rotunjire in sus
//8.0 - ridicare la putere
//3.0 - radical
//2.7182818284590455 - valoarea exponentiala
//2.718281828459045
//2 - minimul
//8 - maximul
//5 - valoarea absoluta
//1.0 - logaritmul natural
//valoare aleatoare subunitara
//1.0 - sinusul, exista si celelalte functii
//90.0 - conversie in grade
//3.141592653589793 - conv. in rad.

Aplicaii propuse
1.

Cutarea minimului i a maximului ntr-un tablou de n elemente;

2.

Generarea i afiarea unui tablou cu numerele lui Fibonacci.

3.

Cutarea minimului i a maximului ntr-o matrice;

4.

Adunarea a dou matrici;

5.

nmulirea a dou matrici.

6.

S se scrie un program care, prin intermediul clasei File, s permit navigarea n structura de directoare din sistem.

27

Limbajul Java tratarea excepiilor (1)





Excepiile sunt erorile care apar n timpul execuiei programelor.


O instruciune sau o secven de instruciuni trebuie inclus ntr-un bloc try n
vederea tratrii eventualelor excepii pe care le poate genera. Blocul try este
urmat de unul sau mai multe blocuri catch prin care sunt detectate diferitele
excepii. n blocul opional finally se introduc zonele de cod care trebuie
executate indiferent c apare sau nu o excepie. Forma general:
try{
//instructiuni care pot genera Exceptia1 si Exceptia2
}
catch(Exceptia1 e1){
//instructiunile care se executa daca apare Exceptia1
}
catch(Exceptia2 e2){
//instructiunile care se executa daca apare Exceptia2
}
finally{
//instructiunile care se executa indiferent ca apare sau nu o exceptie
}

Dac nu apar excepii, blocul try execut toate instruciunile. Dac o instruciune
din blocul try genereaz o excepie, se caut blocul catch corespunztor,
trecnd peste restul instruciunilor din try. Dac exist un catch corespunztor,
se execut instruciunile din acel bloc catch. Dac nu este gsit un bloc catch
corespunztor, excepia este transmis mai departe n ierarhia apelant. Dac
excepia ajunge n vrful ierarhiei fr s fie tratat, programul afieaz un
mesaj de eroare i se ntrerupe.

28

Limbajul Java tratarea excepiilor (2)




Este posibil ignorarea excepiilor i transmiterea lor mai sus prin throws n
ierarhia apelant.
n exemplul urmtor, dac n metoda apare Exceptia1 sau Exceptia2, ea este
ignorat, transmis mai departe i tratat n metoda apelant main (ca n
exemplul precedent):
public void metoda() throws Exceptia1, Exceptia2 {
//instructuni care pot genera Exceptia1 si Exceptia2
}
public static void main(String[] args) {
try{
metoda();
}
catch(Exceptia1 e1){
//instructiunile care se executa daca apare Exceptia1
}
catch(Exceptia2 e2){
//instructiunile care se executa daca apare Exceptia2
}
finally{
//instructiunile care se executa indiferent ca apare sau nu o exceptie
}
}
29

Limbajul Java tratarea excepiilor (3)


Exemplul 1


Implementai i apoi rulai urmtoarea secven de cod:


String str = "I'm a String!";
int i = Integer.parseInt(str);
System.out.println("Program execution finished...");

Conversia din String n int determin euarea execuiei programului


datorit coninutului nenumeric al variabilei str. Astfel nu se mai ajunge
la afiarea mesajului "Program execution finished...". Excepia
semnalat este NumberFormatException.


Tratarea excepiei:
String str = "I'm a String!";
try {
int i = Integer.parseInt(str);
}
catch (NumberFormatException nfe) {
System.out.println("Conversia nu a fost posibila!");
}

Excepia fiind tratat, execuia programului nu va mai eua.


30

Limbajul Java tratarea excepiilor (4)


Exemplul 2


Implementai i apoi rulai urmtoarea secven de cod:


int tab[] = new int[10];
tab[10] = 10;

Accesarea unui element inexistent, al 11-lea element, nealocat,


determin o excepie ArrayIndexOutOfBoundsException.


Tratarea excepiei:
int tab[] = new int[10];
try {
tab[10] = 10;
}
catch (ArrayIndexOutOfBoundsException aioobe) {
System.out.println("Ati accesat un element inexistent!");
}

Evident, excepia nu apare dac indexul folosit pentru accesarea


tabloului este ntre 0 i 9.
31

Limbajul Java operaii I/O (1)


Citirea irurilor de caractere de la tastatur


Fluxuri de caractere:
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String str = null;
try {
str = br.readLine();
}
catch (IOException ioe) {
ioe.printStackTrace();
}

Fluxuri de octei:
DataInputStream dis = new DataInputStream(System.in);
String str = null;
try {
str = dis.readLine();
}
catch (IOException ioe) {
ioe.printStackTrace();
}
32

Limbajul Java operaii I/O (2)


Citirea valorilor de la tastatur


Clasa DataInputStream pe lng metoda readLine (folosit pe


pagina anterioar pentru introducerea irurilor de caractere)
dispune i de funcii pentru citirea valorilor (readInt,
readDouble, etc.). Dar aceste metode sunt funcionale doar
pentru valori scrise prin interfaa DataOutput (writeInt,
writeDouble, etc.).
Citirea valorilor poate fi efectuat prin citire de iruri de
caractere urmat de conversia acestora:
DataInputStream dis = new DataInputStream(System.in);
String str = null;
try {
str = dis.readLine();
}
catch (IOException ioe) {
ioe.printStackTrace();
}
int i = Integer.parseInt(str);
33

Limbajul Java operaii I/O (3)


Citirea din fiiere
Urmtoarea secven de cod afieaz pe ecran toate liniile citite din fiierul
input.txt. Citirea se face prin aceeai clas DataInputStream care n loc de un
InputStream va primi ca parametru un FileInputStream:
FileInputStream fis = null;
try{
fis = new FileInputStream("input.txt");
}
catch(FileNotFoundException fnfe){
fnfe.printStackTrace();
}
DataInputStream dis = new DataInputStream(fis);
String str = null;
try{
while((str = dis.readLine()) != null)
System.out.println(str);
dis.close();
System.in.read();
}
catch(IOException ioe){
ioe.printStackTrace();
}
34

Limbajul Java operaii I/O (4)


Scrierea n fiiere


Urmtoarea secven de program scrie n fiierul data.txt ntregul 10 i valoarea


float 3.14
try{
FileOutputStream fos = new FileOutputStream("data.txt");
DataOutputStream dos = new DataOutputStream(fos);
dos.writeInt(10);
dos.writeFloat(3.14f);
dos.close();
}
catch(IOException ioe){
ioe.printStackTrace();
}

Fiind scrise prin metodele writeInt i writeFloat, valorile pot fi citite din fiier
folosind metodele readInt respectiv readFloat ale clasei DataInputStream
try{
FileInputStream fis = new FileInputStream("data.txt");
DataInputStream dis = new DataInputStream(fis);
System.out.println(dis.readInt());
System.out.println(dis.readFloat());
dis.close();
}
catch(IOException ioe){
ioe.printStackTrace();
}

35

Limbajul Java operaii I/O (5)


Arhivare ZIP
Arhivarea unui fiier const n citirea datelor din acel fiier prin FileInputStream i scrierea
lor n arhiv prin ZipOutputStream. Pentru vitez mai mare, transferul datelor se face printrun tablou de tip byte:
String fisier = "Algoritmi.pdf";
//fisierul care se arhiveaza
String zip = "Algoritmi.zip";
//numele arhivei
byte buffer[] = new byte[1024];
try{
FileInputStream fileIn = new FileInputStream(fisier);
FileOutputStream f = new FileOutputStream(zip);
ZipOutputStream zipOut = new ZipOutputStream(f);
zipOut.putNextEntry(new ZipEntry(fisier));
int nBytes;
while((nBytes = fileIn.read(buffer, 0, 1024)) != -1)
zipOut.write(buffer, 0, nBytes);
zipOut.close();
fileIn.close();
f.close();
}
catch(ZipException ze){
System.out.println(ze.toString());
}
catch(FileNotFoundException fnfe){
fnfe.printStackTrace();
}
catch(IOException ioe){
ioe.printStackTrace();
}

36

Limbajul Java operaii I/O (6)


Dezarhivare ZIP
Dezarhivarea unui fiier const n citirea datelor din arhiv prin ZipInputStream i scrierea
lor prin FileOutputStream n fiierul destinaie. Pentru eficien, transferul datelor se face
printr-un tablou de tip byte:
String fisier = "Algoritmi.pdf";
//numele fisierului destinatie
String zip = "Algoritmi.zip";
//numele arhivei
byte buffer[] = new byte[1024];
try{
FileInputStream fileIn = new FileInputStream(zip);
FileOutputStream fileO = new FileOutputStream(fisier);
ZipInputStream zipIn = new ZipInputStream(fileIn);
zipIn.getNextEntry();
int nBytes;
while((nBytes = zipIn.read(buffer, 0, 1024)) != -1)
fileO.write(buffer, 0, nBytes);
fileIn.close();
fileO.close();
}
catch(ZipException ze){
System.out.println(ze.toString());
}
catch(IOException ioe){
ioe.printStackTrace();
}

37

Limbajul Java operaii I/O (7)


Aplicaii propuse
1.

S se scrie un program care cere introducerea numelui utilizatorului i afieaz pe ecran


mesajul Hello urmat de numele introdus (afiare-citire-afiare).

2.

Citirea unui ntreg pn la introducerea unei valori valide (tratnd excepia


NumberFormatException).

3.

S se implementeze un program care citete de la tastatur lungimea unui tablou de tip String
i elementele acestuia (numele studenilor din semigrup). Sortai n ordine alfabetic tabloul
(v. metoda sort a clasei Arrays). Atenie, irurile trebuie transformate dup citire astfel nct
toate literele s fie mici sau toate mari (v. toLowerCase sau toUpperCase din String).

4.

Modificai prima aplicaie propus astfel nct s citeasc i vrsta utilizatorului. Dac vrsta
introdus depete 100 s afieze mesajul "Eti btrn!", altfel s afieze "Eti tnr!";

5.

S se implementeze un program care citete de la tastatur lungimea unui tablou de valori


ntregi i elementele acestuia. S se sorteze tabloul folosind metoda sort a clasei Arrays. S se
afieze pe ecran tabloul sortat.

6.

S se implementeze un program care citete dintr-un fiier ntr-un tablou de tip String numele
studenilor din semigrup. Sortai n ordine alfabetic tabloul (v. metoda sort a clasei Arrays).
Atenie, irurile trebuie transformate dup citire astfel nct toate literele s fie mici sau toate
mari (v. toLowerCase sau toUpperCase din String).

7.

S se citeasc dintr-un fiier un tablou de valori ntregi i s se afieze pe ecran media lor
aritmetic. Separarea valorilor de pe linii se va face prin clasa StringTokenizer prezentat
anterior.

8.

Studiai clasa RandomAccessFile care, spre deosebire de FileInputStream i FileOutputStream


(acces secvenial), permite citirea respectiv scrierea unei anumite locaii din fiier.
38

Internaionalizare i naionalizare
Java ofer suportul prin numeroase clase pentru
internaionalizarea i naionalizarea aplicaiilor


Clasa Locale
Locale locale = Locale.getDefault();
System.out.println(locale.getCountry());
System.out.println(locale.getDisplayCountry());
System.out.println(locale.getDisplayCountry(Locale.FRANCE));
System.out.println(locale.getDisplayLanguage());
System.out.println(locale.getDisplayLanguage(Locale.FRANCE));
System.out.println(locale.getDisplayName());
System.out.println(locale.getLanguage());
Locale g = Locale.GERMANY;
System.out.println(g.getLanguage());

//RO
//Romnia
//Roumanie
//romn
//roumain
//romn (Romnia)
//ro
//de

Clasa NumberFormat
System.out.println(NumberFormat.getInstance(locale).format(12.3));
System.out.println(NumberFormat.getCurrencyInstance(locale).format(6.8));

//12,3
//6,80 LEI

Clasa DateFormat
Date date = new Date(2009-1900, 8-1, 31);
System.out.println(DateFormat.getDateInstance(0, locale).format(date));
System.out.println(DateFormat.getDateInstance(2, locale).format(date));

//Y-1900, M-1, D
//31 august 2009
//31.08.2009
39

Limbajul Java crearea claselor (1)




Definiia unei clase trebuie s conin cuvntul cheie class, numele clasei i corpul clasei.
Opional, nainte de cuvntul class pot fi folosii modificatorii public (clasa este vizibil n
toate pachetele), abstract (v. clase abstracte) sau final (clasa nu poate fi derivat).
Exemplu:
class Person {
private String name;
public void setName(String name){
this.name = name;
}
public String getName(){
return name;
}
}

Clasele pot conine:






Tipuri de acces: private, protected, public








Variabile membru;
Constructori;
Metode.
Variabilele i metodele private pot fi accesate doar n cadrul clasei n care s-au declarat;
Variabilele i metodele protejate pot fi accesate n interiorul clasei, al subclaselor (v. motenirea) sau
n pachetul (package) n care au fost declarate;
Variabilele i metodele publice pot fi accesate oriunde;
Tipul de acces este implicit protejat (dac nu se precizeaz).

Recomandare (ncapsulare, v. cursul POO):





Variabile private;
Set de metode publice care s permit accesarea variabilelor private.

40

Limbajul Java crearea claselor (2)


Exemplul 1 (un singur pachet)
package person;

package person;

public class Person {


private String name;
private String address;
private int age;
private void setName(String name){
this.name = name;
}
private String getName(){
return name;
}
protected void setAddress(String address){
this.address = address;
}
protected String getAddress(){
return address;
}
public void setAge(int age){
this.age = age;
}
int getAge(){
return age;
}
}

public class Main {


public static void main(String[] args) {
Person p = new Person();
p.name = "Popescu";
p.setName("Popescu");
p.setAddress("Str. N. Balcescu, Nr. 5");
p.setAge(103);
System.out.println("Numele: " + p.getName());
System.out.println("Adresa: " + p.getAddress());
System.out.println("Varsta: " + p.getAge());
}
}

//Eroare!
//Eroare!

//Eroare!

41

Limbajul Java crearea claselor (3)


Exemplul 2 (pachete diferite, clasa de baz nepublic)
package person;
class Person {
private String name;
private String address;
private int age;
private void setName(String name){
this.name = name;
}
private String getName(){
return name;
}
protected void setAddress(String address){
this.address = address;
}
protected String getAddress(){
return address;
}
public void setAge(int age){
this.age = age;
}
int getAge(){
return age;
}
}

package main;
import person.Person;
public class Main {
public static void main(String[] args) {
Person p = new Person();
}
}

//Eroare!

42

Limbajul Java crearea claselor (4)


Exemplul 3 (pachete diferite, clasa de baz public)
package person;
public class Person {
private String name;
private String address;
private int age;
private void setName(String name){
this.name = name;
}
private String getName(){
return name;
}
protected void setAddress(String address){
this.address = address;
}
protected String getAddress(){
return address;
}
public void setAge(int age){
this.age = age;
}
int getAge(){
return age;
}
}

package main;
import person.Person;
public class Main {
public static void main(String[] args) {
Person p = new Person();
p.name = "Popescu";
p.setName("Popescu");
p.setAddress("Str. N. Balcescu, Nr. 5");
p.setAge(103);
System.out.println("Numele: " + p.getName());
System.out.println("Adresa: " + p.getAddress());
System.out.println("Varsta: " + p.getAge());
}
}

//Eroare!
//Eroare!
//Eroare!
//Eroare!
//Eroare!
//Eroare!

43

Limbajul Java crearea claselor (5)


Exemplul 4 (o variant corect)
package person;

package person;

public class Person {


private String name;
private String address;
private int age;
public void setName(String name){
this.name = name;
}
public String getName(){
return name;
}
public void setAddress(String address){
this.address = address;
}
public String getAddress(){
return address;
}
public void setAge(int age){
this.age = age;
}
public int getAge(){
return age;
}
}

public class Main {


public static void main(String[] args) {
Person p = new Person();
p.setName("Popescu");
p.setAddress("Str. N. Balcescu, Nr. 5");
p.setAge(103);
System.out.println("Numele: " + p.getName());
System.out.println("Adresa: " + p.getAddress());
System.out.println("Varsta: " + p.getAge());
}
}

44

Limbajul Java constructori (1)




Este o metod public fr tip (nici void) avnd


acelai nume cu al clasei;

Principalul rol al constructorului este acela de a


iniializa obiectul pentru care s-a apelat;

Dac ntr-o clas nu se declar un constructor, atunci


compilatorul genereaz unul implicit, fr parametri;

ntr-o clas pot coexista mai muli constructori cu


parametri diferii (tip, numr);

La instanierea unui obiect se apeleaz constructorul


corespunztor parametrilor de apel;

n Java nu exist destructori. Sistemul apeleaz


periodic mecanismul garbage collector.
45

Limbajul Java constructori (2)


Exemplu
public class Person {
private String name;
private String address;
private int age;
public Person(String name, String address, int age) {
this.name = name;
this.address = address;
this.age = age;
}
public void setName(String name){
this.name = name;
}
public String getName(){
return name;
}
public void setAddress(String address){
this.address = address;
}
public String getAddress(){
return address;
}
public void setAge(int age){
this.age = age;
}
public int getAge(){
return age;
}
}

public class Main {


public static void main(String[] args) {
Person p = new Person("Pop", "Sibiu", 103);
System.out.println("Numele: " + p.getName());
System.out.println("Adresa: " + p.getAddress());
System.out.println("Varsta: " + p.getAge());
p.setName("Rus");
p.setAddress("Avrig");
p.setAge(98);
System.out.println("Numele: " + p.getName());
System.out.println("Adresa: " + p.getAddress());
System.out.println("Varsta: " + p.getAge());
}
}

//Pop
//Sibiu
//103

//Rus
//Avrig
//98

46

Limbajul Java motenirea (1)




Unul dintre marile avantaje ale programrii orientate-obiect (POO) const n


reutilizarea codului;

Toate clasele Java, cu excepia interfeelor, sunt subclase ale clasei rdcin
Object;

Procesul prin care o clas nou refolosete o clas veche se numete motenire;

O clas, numit clas derivat, poate moteni variabilele i metodele unei alte
clase, numit clas de baz;

Dac apare aceeai metod cu aceiai parametri att n clasa de baz ct i n


cea derivat (prin redefinire) i se apeleaz metoda instanei clasei derivate, se
execut metoda clasei derivate;

Derivarea unei clase n Java se face prin cuvntul cheie extends urmat de
numele clasei de baz;

O clas declarat final nu poate fi derivat;

Java nu permite motenire multipl: o clas poate deriva o singur clas de


baz. Motenirea multipl este permis doar folosind interfeele (vor fi
prezentate);

Constructorii clasei derivate pot folosi printr-un apel super constructorii clasei
de baz pentru iniializarea variabilelor motenite;

n exemplul prezentat n continuare, clasele Student i Teacher motenesc clasa


Person;
47

Limbajul Java motenirea (2)


Exemplu
public class Person {
private String name;
private String address;
private int age;
public Person(String name, String address, int age) {
this.name = name;
this.address = address;
this.age = age;
}
public void setName(String name){
this.name = name;
}
public String getName(){
return name;
}
public void setAddress(String address){
this.address = address;
}
public String getAddress(){
return address;
}
public void setAge(int age){
this.age = age;
}
public int getAge(){
return age;
}
}

public class Student extends Person {


private int grade;
//medie
public Student(String name, String address, int age, int grade) {
super(name, address, age); //trebuie sa fie prima instructiune!
this.grade = grade;
}
public void setGrade(int grade){
this.grade = grade;
}
public int getGrade(){
return grade;
}
}
public class Teacher extends Person {
private int courses;
//nr. cursuri
public Teacher(String name, String address, int age, int courses) {
super(name, address, age);
//trebuie sa fie prima instructiune!
this.courses = courses;
}
public void setCourses(int courses){
this.courses = courses;
}
public int getCourses(){
return courses;
}
}
public class Main {
public static void main(String[] args) {
Student s = new Student("Rus", "Avrig", 98, 4);
System.out.println(s.getAge());
}
}

//98

48

Limbajul Java motenirea (3)




Dac un constructor al clasei derivate nu apeleaz prin super un


constructor al clasei de baz, compilatorul va apela implicit
constructorul fr parametri al clasei de baz. Dac ns clasa de baz
are doar constructori cu parametri, compilatorul nu va genera
constructorul implicit. n acest caz, n clasa de baz trebuie declarat i
un constructor fr parametri.
Exemplu:
public class Base {
public Base(){
}
public Base(int p) {
}
}
public class Sub extends Base{
public Sub() {
}
}
49

Limbajul Java motenirea (4)


Suprancrcarea metodelor
public class Base {
public void method(int i) {
System.out.println("Base integer is " + i);
}
public void method(String s){
System.out.println("Base string is " + s);
}
}

public class Sub extends Base {


public void method(int j){
System.out.println("Sub integer is " + j);
}
public static void main(String[] args) {
Base b1 = new Base();
Base b2 = new Sub();
Sub s = new Sub();
b1.method(1);
//"Base integer is 1"
b2.method(2);
//"Sub integer is 2"
s.method(3);
//"Sub integer is 3"
s.method("4");
//"Base string is 4"
}
}

50

Limbajul Java motenirea (5)


Aplicaii
1.

S se implementeze o aplicaie care s permit introducerea de la


tastatur a numrului de studeni din semigrup urmat de datele lor
(ntr-un tablou) i a numrului de profesori din acest semestru urmat de
datele lor (ntr-un alt tablou). Cutai i afiai studentul cu media cea
mai mare respectiv profesorul cu cele mai multe cursuri.

2.

Definii clasa Employee (angajat) derivat din clasa Person prezentat,


avnd cmpul suplimentar salary. Introducei de la tastatur 5 obiecte
de tip Employee ntr-un tablou. Cutai i afiai angajatul cu salariul cel
mai mare.

3.

Definii clasa Product cu cmpul price (pre). Definii clasa Book


(carte) derivat din clasa Product avnd cmpurile suplimentare title,
author i publisher (editor). Introducei de la tastatur 5 obiecte de tip
Book ntr-un tablou. Cutai i afiai cartea cu preul cel mai mic.

4.

Definii clasa Book (carte) cu cmpurile title, author i publisher


(editor). Definii clasa LibraryCard (fi de bibliotec) derivat din clasa
Book avnd cmpul suplimentar copies (nr. exemplare). Introducei de
la tastatur 5 obiecte de tip LibraryCard ntr-un tablou. Cutai i afiai
cartea cu numrul cel mai mare de exemplare.

5.

Definii clasa Vehicle cu cmpul manufacturer (fabricant). Definii


clasa Car derivat din clasa Vehicle avnd cmpurile suplimentare
model, length (lungime), maxSpeed (vitez maxim), price (pre).
Introducei de la tastatur 5 obiecte de tip Car ntr-un tablou. Cutai i
afiai maina cu preul cel mai mic.

51

Limbajul Java clase abstracte






O clas trebuie declarat abstract dac conine cel puin o metod abstract.
Metodele abstracte sunt declarate fr implementare urmnd ca ele s fie
implementate n clasele derivate. O clas abstract nu poate fi instaniat.
Exemplu:
public abstract class Product {
private double price;
public Product(double price) {
this.price = price;
}
public abstract double computeFinalPrice();
public void setPrice(double price){
this.price = price;
}
public double getPrice(){
return price;
}
}
public class Book extends Product {
public Book(double price) {
super(price);
}
public double computeFinalPrice(){
return getPrice() + (9*getPrice())/100;
}
}

public class Car extends Product{


public Car(double price) {
super(price);
}
public double computeFinalPrice(){
return getPrice() + (19*getPrice())/100;
}
}

//TVA=19%

public class Main {


public static void main(String[] args) {
Product p = new Product(10);
//Eroare!
Book b = new Book(100);
System.out.println(b.computeFinalPrice());
Car c = new Car(100000);
System.out.println(c.computeFinalPrice());
}
}
//TVA=9%

52

Limbajul Java interfee (1)




Interfeele ofer avantajele motenirii multiple, evitnd complicaiile


acesteia.

Toate metodele dintr-o interfa sunt implicit publice i abstracte. O


interfa furnizeaz numele metodelor fr implementarea lor.

Interfeele nu pot fi instaniate.

Clasa care folosete o interfa trebuie s implementeze toate


metodele acesteia.

Se poate deriva o interfa din alte interfee prin acelai mecanism


care a fost prezentat la clase (v. motenirea).

n continuare vor fi prezentate cteva exemple:





O interfa Price folosit de clasele Product, Book i Car.


Folosirea interfeelor Comparator sau Comparable pentru sortarea unui
tablou de obiecte prin metoda sort din clasa Arrays. n cazul interfeei
Comparator trebuie implementat metoda compare.
Interfaa Serializable pentru serializarea obiectelor.
53

Limbajul Java interfee (2)


Exemplul 1 (interfaa Price, implementare computeFinalPrice)
public interface Price {
public double computeFinalPrice();
}

public class Car extends Product{


public Car(double price) {
super(price);
}
public double computeFinalPrice(){
return getPrice() + (19*getPrice())/100;
}
}

public abstract class Product implements Price{


private double price;
public Product(double price) {
this.price = price;
}
public void setPrice(double price){
this.price = price;
}
public double getPrice(){
return price;
}
}
public class Book extends Product {
public Book(double price) {
super(price);
}
public double computeFinalPrice(){
return getPrice() + (9*getPrice())/100;
}
}

//TVA=19%

public class Main {


public static void main(String[] args) {
Product p = new Product(10);
//Eroare!
Book b = new Book(100);
System.out.println(b.computeFinalPrice());
Car c = new Car(100000);
System.out.println(c.computeFinalPrice());
}
}

//TVA=9%

54

Limbajul Java interfee (3)


Exemplul 2 (interfaa Comparator, implementare compare)
public class Item {
String str;
int num;
Item(String str, int num) {
this.str = str;
this.num = num;
}
}

public class Main {


public static void main(String[] args) {
Item t[] = new Item[5];
t[0] = new Item("c", 2);
t[1] = new Item("a", 1);
t[2] = new Item("e", 4);
t[3] = new Item("b", 5);
t[4] = new Item("d", 3);
//Sortare dupa campul num
java.util.Arrays.sort(t, new Comparator() {
public int compare(Object o1, Object o2) {
//return ((Item)o1).num-((Item)o2).num;
if(((Item)o1).num<((Item)o2).num) return -1;
if(((Item)o1).num>((Item)o2).num) return 1;
return 0;
}
});
//Sortare dupa campul str
java.util.Arrays.sort(t, new Comparator() {
public int compare(Object o1, Object o2) {
return ((Item)o1).str.compareTo(((Item)o2).str);
}
});
}
}

55

Limbajul Java interfee (4)


Exemplul 3 (interfaa Comparator, implementare compare)
public class Item implements Comparator {
String str;
int num;
Item() {}
Item(String str, int num) {
this.str = str;
this.num = num;
}
public int compare(Object o1, Object o2) {
return ((Item)o1).num-((Item)o2).num;
}
}

public class Main {


public static void main(String[] args) {
Item t[] = new Item[5];
t[0] = new Item("c", 2);
t[1] = new Item("a", 1);
t[2] = new Item("e", 4);
t[3] = new Item("b", 5);
t[4] = new Item("d", 3);
//Sortare dupa campul num
java.util.Arrays.sort(t, new Item());
//Afisare
for (int i=0; i<t.length; i++)
System.out.println(t[i].str + " - " + t[i].num);
//Sortare dupa campul str
java.util.Arrays.sort(t, new Comparator() {
public int compare(Object o1, Object o2) {
return ((Item)o1).str.compareTo(((Item)o2).str);
}
});
//Afisare
for (int i=0; i<t.length; i++)
System.out.println(t[i].str + " - " + t[i].num);
}
}
56

Limbajul Java interfee (5)


Exemplul 4 (interfaa Comparable, implementare compareTo)
public class Item implements Comparable {
String str;
int num;
Item(String str, int num) {
this.str = str;
this.num = num;
}
public int compareTo(Object o) {
return num-((Item)o).num;
//return str.compareTo(((Item)o).str);
}
}

public class Main {


public static void main(String[] args) {
Item t[] = new Item[5];
t[0] = new Item("c", 2);
t[1] = new Item("a", 1);
t[2] = new Item("e", 4);
t[3] = new Item("b", 5);
t[4] = new Item("d", 3);
//Sortare dupa campul num
java.util.Arrays.sort(t);
//Afisare
for (int i=0; i<t.length; i++)
System.out.println(t[i].str + " - " + t[i].num);
//Sortare dupa campul str
java.util.Arrays.sort(t, new Comparator() {
public int compare(Object o1, Object o2) {
return ((Item)o1).str.compareTo(((Item)o2).str);
}
});
//Afisare
for (int i=0; i<t.length; i++)
System.out.println(t[i].str + " - " + t[i].num);
}
}
57

Limbajul Java interfee (6)


Exemplul 5 (interfaa Serializable permite serializarea obiectelor)
try{
oos = new ObjectOutputStream(fos);
ois = new ObjectInputStream(fis);
}
catch(IOException e){
e.printStackTrace();
}
try{
oos.writeObject(new Item("c", 2)); //Scrierea obiectului in fisier
oos.close(); fos.close();
}
catch(IOException e){
e.printStackTrace();
}
try{
Item item=(Item)ois.readObject(); //Citirea obiectului din fisier
System.out.println(item.str + " - " + item.num);
ois.close(); fis.close();
}
catch(IOException e){
e.printStackTrace();
}
catch(ClassNotFoundException e){
e.printStackTrace();
}

public class Item implements Serializable {


String str;
int num;
Item(String str, int num) {
this.str = str;
this.num = num;
}
}

public class Main {


public static void main(String[] args) {
FileOutputStream fos = null;
FileInputStream fis = null;
ObjectOutputStream oos = null;
ObjectInputStream ois = null;
try{
fos = new FileOutputStream("data.txt");
fis = new FileInputStream("data.txt");
}
catch(FileNotFoundException e){
e.printStackTrace();
}
}
}

58

Limbajul Java interfee (7)


Aplicaii
1.

Definii clasa Person cu cmpurile name, address i age. Definii clasa Student
derivat din clasa Person avnd cmpul suplimentar grade (medie). Introducei
dintr-un fiier student.txt numrul de studeni din semigrup urmat de datele lor,
ntr-un tablou. Sortai i afiai studenii n ordinea cresctoare a mediei.

2.

Definii clasa Person cu cmpurile name, address i age. Definii clasa Teacher
derivat din clasa Person avnd cmpul suplimentar courses (nr. cursuri).
Introducei dintr-un fiier teacher.txt numrul de profesori din acest semestru
urmat de datele lor, ntr-un tablou. Sortai i afiai profesorii n ordinea cresctoare
a numrului de cursuri predate.

3.

Definii clasa Person cu cmpurile name, address i age. Definii clasa


Employee (angajat) derivat din clasa Person avnd cmpul suplimentar salary
(salariu). Introducei dintr-un fiier employee.txt numrul de angajai urmat de
datele lor, ntr-un tablou. Sortai i afiai angajaii n ordinea cresctoare a
salariilor.

4.

Definii clasa Product cu cmpul price (pre). Definii clasa Book (carte) derivat
din clasa Product avnd cmpurile suplimentare title, author i publisher
(editor). Introducei dintr-un fiier book.txt numrul de cri urmat de datele lor,
ntr-un tablou. Sortai i afiai crile n ordinea cresctoare a preului.

5.

Definii clasa Book (carte) cu cmpurile title, author i publisher (editor).


Definii clasa LibraryCard (fi de bibliotec) derivat din clasa Book avnd
cmpul suplimentar copies (nr. exemplare). Introducei dintr-un fiier
librarycard.txt numrul de fie urmat de datele acestora, ntr-un tablou. Sortai i
afiai crile n ordinea cresctoare a numrului de exemplare disponibile.

6.

Definii clasa Vehicle cu cmpul manufacturer (fabricant). Definii clasa Car


derivat din clasa Vehicle avnd cmpurile suplimentare model, length
(lungime), maxSpeed (vitez maxim), price (pre). Introducei dintr-un fiier
car.txt numrul de maini, urmat de datele lor, ntr-un tablou. Sortai i afiai
mainile n ordinea cresctoare a preului.

59

Limbajul Java partajarea datelor (1)










Partajarea datelor de ctre obiectele unei clase poate fi realizat prin intermediul membrilor
statici ai clasei respective.
n timp ce variabilele obinuite (non-statice) aparin instanelor clasei (obiectelor),
variabilele declarate statice aparin clasei i sunt partajate de ctre toate obiectele acesteia.
Unei variabile statice i se aloc memorie o singur dat, la prima instaniere a clasei. La
urmtoarele instanieri ale clasei variabilei statice nu i se mai aloc memorie, dar toate
obiectele clasei pot accesa aceeai variabil static, alocat la prima instaniere.
Metodele statice pot fi apelate fr instanierea clasei.
Metodele statice nu pot utiliza variabile i metode non-statice.
Un exemplu de utilizare a unei variabile statice este contorizarea obiectelor instaniate
dintr-o clas:
public class Person {
private String name;
static int counter;
public Person(String name) {
this.name = name;
counter++;
System.out.println(counter + " persoane.");
}
public void setName(String name){
this.name = name;
}
public String getName(){
return name;
}
}

public class Main {


public static void main(String[] args) {
Person p1 = new Person("Popescu");
Person p2 = new Person("Ionescu");
}
}

//"1 persoane."
//"2 persoane."

60

Limbajul Java partajarea datelor (2)


Exemple de folosire a metodelor statice:
public class Person {
private String name;
private int age;
static int counter;
public Person(String name, int age) {
this.name = name;
this.age = age;
increaseCounter();
}
public static void increaseCounter(){
counter++;
System.out.println(counter + " persoane.");
}
public static void increaseAge(){
age++;
//Eroare!
}
public void setName(String name){
this.name = name;
}
public String getName(){
return name;
}
public void setAge(int age){
this.age = age;
}
public int getAge(){
return age;
}
}

public class Main {


public static void main(String[] args) {
Person p1 = new Person("Popescu", 61);
Person p2 = new Person("Ionescu", 72);
Person.increaseCounter() ;
p1 = new Person("Petrescu", 53);
}
}

//"1
//"2
//"3
//"4

persoane."
persoane."
persoane."
persoane."

61

Limbajul Java partajarea datelor (3)


Alte exemple de folosire a variabilelor i metodelor statice:
public class Person {
private String name;
private int age;
static int counter;
public Person(String name, int age) {
this.name = name;
this.age = age;
increaseCounter();
}
public static void increaseCounter(){
counter++;
System.out.println(counter + " persoane.");
}
public void printCounter(){
System.out.println(counter);
}
public void setName(String name){
this.name = name;
}
public String getName(){
return name;
}
public void setAge(int age){
this.age = age;
}
public int getAge(){
return age;
}

public static void main(String[] args) {


Person p1 = new Person("Popescu", 61);
Person p2 = new Person("Ionescu", 72);
Person.increaseCounter() ;
p1 = new Person("Petrescu", 53);
printCounter();
p2.printCounter();
}

//"1 persoane."
//"2 persoane."
//"3 persoane."
//"4 persoane.
//Eroare!
//4

62

Limbajul Java atribuire vs. clonare (1)


Folosirea operatorului de atribuire
n cazul obiectelor operatorul de atribuire determin atribuirea referinelor (adreselor)
public class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setAge(int age) {
this.age = age;
}
public int getAge() {
return age;
}
}

public class Main {


public static void main(String[] args) {
Person p1 = new Person("Pop", 61);
Person p2 = p1;
System.out.println(p1.getName() + ",
System.out.println(p2.getName() + ",
p1.setAge(p1.getAge() + 1);
System.out.println(p1.getName() + ",
System.out.println(p2.getName() + ",
p2.setName("Rus");
System.out.println(p1.getName() + ",
System.out.println(p2.getName() + ",
p1 = new Person("Lup", 53);
System.out.println(p1.getName() + ",
System.out.println(p2.getName() + ",
p1.setAge(p1.getAge() + 1);
System.out.println(p1.getName() + ",
System.out.println(p2.getName() + ",
}
}

" + p1.getAge());
" + p2.getAge());

//"Pop, 61"
//"Pop, 61"

" + p1.getAge());
" + p2.getAge());

//"Pop, 62"
//"Pop, 62"

" + p1.getAge());
" + p2.getAge());

//"Rus, 62"
//"Rus, 62"

" + p1.getAge());
" + p2.getAge());

//"Lup, 53"
//"Rus, 62"

" + p1.getAge());
" + p2.getAge());

//"Lup, 54"
//"Rus, 62"

63

Limbajul Java atribuire vs. clonare (2)


Clonarea obiectelor
public class Person implements Cloneable {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public Object clone() { //protected in Object
Object obj = null;
try {
obj = super.clone();
}
catch (CloneNotSupportedException ex) {
}
return obj;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setAge(int age) {
this.age = age;
}
public int getAge() {
return age;
}
}

public class Main {


public static void main(String[] args) {
Person p1 = new Person("Pop", 61);
Person p2 = (Person)p1.clone();
System.out.println(p1.getName() + ",
System.out.println(p2.getName() + ",
p1.setAge(p1.getAge() + 1);
System.out.println(p1.getName() + ",
System.out.println(p2.getName() + ",
p2.setName("Rus");
System.out.println(p1.getName() + ",
System.out.println(p2.getName() + ",
}
}

" + p1.getAge());
" + p2.getAge());

//"Pop, 61"
//"Pop, 61"

" + p1.getAge());
" + p2.getAge());

//"Pop, 62"
//"Pop, 61"

" + p1.getAge());
" + p2.getAge());

//"Pop, 62"
//"Rus, 61"

64

Limbajul Java interfa grafic (1)




O component foarte important a aplicaiilor


moderne este interfaa grafic prin care
acestea comunic cu utilizatorul: se citesc
datele i se afieaz rezultatele.
Mediile de dezvoltare Java ofer numeroase
pachete cu diverse componente vizuale.
n urmtoarea aplicaie vom folosi
componente din pachetul AWT (Advanced
Windowing Toolkit) pentru citirea studenilor
ntr-o list
Fereastra neredimensionabil a aplicaiei este
prezentat pe pagina urmtoare.
65

Limbajul Java interfa grafic (2)


Fereastra aplicaiei

Numele studentului se introduce printr-un TextField;

Acionarea butonului Add determin adugarea textului din


TextField n componenta List respectiv tergerea din TextField;

Adugarea n componenta List determin apariia unui scroll


atunci cnd numrul de linii introduse trece de limita de
vizualizare.
66

Limbajul Java interfa grafic (3)


addButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
addButton_actionPerformed(e);
}
});
this.setSize(400, 220);
this.setResizable(false);
this.setLayout(null); //componentele pot fi asezate cu mouse-ul
this.setTitle("Students");
this.setBackground(new Color(240, 240, 240));
this.add(addButton, null);
this.add(studentTextField, null);
this.add(studentList, null);
}

Codul surs al aplicaiei


public class StudentFrame extends Frame {
private List studentList = new List();
private TextField studentTextField = new TextField();
private Button addButton = new Button();
public StudentFrame() {
try {
jbInit();
}
catch(Exception e) {
e.printStackTrace();
}
show();
}
public static void main(String[] args) {
StudentFrame studentFrame = new StudentFrame();
}
private void jbInit() throws Exception {
this.addWindowListener(new java.awt.event.WindowAdapter() {
public void windowClosing(WindowEvent e) {
this_windowClosing(e);
}
});
studentList.setBounds(new Rectangle(210, 60, 160, 140));
studentTextField.setBounds(new Rectangle(25, 60, 160, 30));
addButton.setLabel("Add");
addButton.setBounds(new Rectangle(70, 120, 80, 25));

void this_windowClosing(WindowEvent e) {
System.exit(0);
//inchiderea aplicatiei
}
void addButton_actionPerformed(ActionEvent e) {
studentList.add(studentTextField.getText());
studentTextField.setText("");
//stergere
}
}

67

Limbajul Java interfa grafic (4)


Tratarea evenimentelor


Evenimentele sunt generate de aciunile utilizatorului asupra


componentelor interfeei grafice.
Pentru tratarea unui anumit eveniment ntr-o clas, trebuie
implementat interfaa Listener corespunztoare care s prelucreze
evenimentul respectiv. De exemplu, pentru tratarea evenimentelor
ActionEvent, se implementeaz interfaa ActionListener.

Astfel, evenimentele sunt recepionate de obiecte de tip Listener care


apeleaz metode de tratare a evenimentelor.

Aplicaia anterioar trateaz evenimentele de nchidere a ferestrei i de


click pe butonul Add.

n continuare vom extinde aplicaia astfel nct s rspund la


apsarea tastei ENTER, tratnd evenimentul KeyEvent. Pentru asta se
poate folosi interfaa KeyListener implementnd toate metodele
(keyPressed, keyReleased, keyTyped) sau clasa abstract KeyAdapter
care ne permite s implementm doar metodele necesare (n cazul
nostru keyPressed).
68

Limbajul Java interfa grafic (5)


addButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
addButton_actionPerformed(e);
}
});
this.setSize(400, 220);
this.setResizable(false);
this.setLayout(null); //componentele pot fi asezate cu mouse-ul
this.setTitle("Students");
this.setBackground(new Color(240, 240, 240));
this.add(addButton, null);
this.add(studentTextField, null);
this.add(studentList, null);
}

public class StudentFrame extends Frame {


private List studentList = new List();
private TextField studentTextField = new TextField();
private Button addButton = new Button();
public StudentFrame() {
try {
jbInit();
}
catch(Exception e) {
e.printStackTrace();
}
show();
studentTextField.requestFocus();
}
public static void main(String[] args) {
StudentFrame studentFrame = new StudentFrame();
}
private void jbInit() throws Exception {
this.addWindowListener(new java.awt.event.WindowAdapter() {
public void windowClosing(WindowEvent e) {
this_windowClosing(e);
}
});
studentList.setBounds(new Rectangle(210, 60, 160, 140));
studentTextField.setBounds(new Rectangle(25, 60, 160, 30));
studentTextField.addKeyListener(new java.awt.event.KeyAdapter() {
public void keyPressed(KeyEvent e) {
studentTextField_keyPressed(e);
}
});
addButton.setLabel("Add");
addButton.setBounds(new Rectangle(70, 120, 80, 25));

void this_windowClosing(WindowEvent e) {
System.exit(0);
//inchiderea aplicatiei
}
void addButton_actionPerformed(ActionEvent e) {
studentList.add(studentTextField.getText());
studentTextField.setText("");
//stergere
studentTextField.requestFocus();
}
void studentTextField_keyPressed(KeyEvent e) {
if(e.getKeyCode()==e.VK_ENTER)
addButton_actionPerformed(new ActionEvent(this, 0, null));
}
}

69

Limbajul Java interfa grafic (6)


Layout manager
(aranjarea componentelor)


Toate obiectele grafice de tip container (Frame,


Panel, etc.) au o proprietate layout prin care se
specific cum s fie aezate i dimensionate
componentele: null, XYLayout, BorderLayout,
FlowLayout, GridLayout, GridBagLayout, etc.
Un layout null (folosit i n aplicaia prezentat) sau
XYLayout pstreaz poziiile i dimensiunile originale
ale componentelor. Se pot folosi n cazul
containerelor neredimensionabile.

BorderLayout, FlowLayout, GridLayout i


GridBagLayout repoziioneaz i/sau rescaleaz

obiectele n cazul redimensionrii containerului.


70

Limbajul Java interfa grafic (7)


BorderLayout permite aranjarea componentelor din
container n 5 zone: nord, sud, est, vest i centru.
Componentele din nord i sud i pstreaz nlimea
original i sunt scalate la limea containerului.
Componentele din est i vest i pstreaz limea original
i sunt scalate vertical astfel nct s acopere spaiul dintre
nord i sud. Componenta din centru se expandeaz pentru
acoperirea ntreg spaiului rmas.

public class BorderFrame extends Frame {


private BorderLayout bLayout = new BorderLayout();
private Button northButton = new Button("North Button");
private Button southButton = new Button("South Button");
private Button westButton = new Button("West Button");
private Button eastButton = new Button("East Button");
private Button centerButton = new Button("Center Button");
public BorderFrame() {
this.setSize(400, 220);
this.setTitle("BorderLayout");
this.setLayout(bLayout);
this.setBackground(new Color(240, 240, 240));
this.add(northButton, BorderLayout.NORTH);
this.add(southButton, BorderLayout.SOUTH);
this.add(westButton, BorderLayout.WEST);
this.add(eastButton, BorderLayout.EAST);
this.add(centerButton, BorderLayout.CENTER);
this.show();
}

Constructori:
BorderLayout() fr distan ntre componente;
BorderLayout(int hgap, int vgap) primete ca parametri
distanele orizontale i verticale dintre componente.

public static void main(String[] args) {


new BorderFrame();
}
}

71

Limbajul Java interfa grafic (8)


FlowLayout aranjeaz componentele pe linii pstrnd
dimensiunile. Aliniaz componentele care ncap ntr-o linie
i dac e nevoie continu pe linia urmtoare. Se folosete
de obicei pentru aranjarea butoanelor ntr-un Panel.
Constructori:
FlowLayout() aliniere centrat i distan implicit de 5
ntre componente att pe orizontal ct i pe vertical;

public class FlowFrame extends Frame {


private FlowLayout fLayout = new FlowLayout();
private Button firstButton = new Button("First Button");
private Button secondButton = new Button("Second Button");
private Button thirdButton = new Button("Third Button");
private Button fourthButton = new Button("Fourth Button");
private Button fifthButton = new Button("Fifth Button");
private Button lastButton = new Button("Last Button");
public FlowFrame() {
this.setSize(400, 220);
this.setTitle("FlowLayout");
this.setLayout(fLayout);
this.setBackground(new Color(240, 240, 240));
this.add(firstButton);
this.add(secondButton);
this.add(thirdButton);
this.add(fourthButton);
this.add(fifthButton);
this.add(lastButton);
this.show();
}

FlowLayout(int align) primete ca parametru tipul de


aliniere (LEFT, RIGHT, CENTER din FlowLayout), distana
dintre componente fiind implicit 5;
FlowLayout(int align, int hgap, int vgap) primete ca
parametri tipul de aliniere (LEFT, RIGHT, CENTER din
FlowLayout) i distanele orizontale i verticale dintre
componente.

public static void main(String[] args) {


new FlowFrame();
}
}

72

Limbajul Java interfa grafic (9)


GridLayout mparte containerul n linii i coloane i
pstreaz componentele n celulele astfel obinute. Toate
celulele au aceeai dimensiune. Fiecare component este
expandat la dimensiunea celulei. n cazul unor interfee
complexe, se pot introduce n celule containere Panel cu
subcomponente aranjate tot prin GridLayout. Pentru
obinerea unor spaii libere se pot introduce componente
Panel goale n celulele corespunztoare.

public class GridFrame extends Frame {


private GridLayout gLayout = new GridLayout(2, 3, 50, 100);
private Button firstButton = new Button("First Button");
private Button secondButton = new Button("Second Button");
private Button thirdButton = new Button("Third Button");
private Button fourthButton = new Button("Fourth Button");
private Button fifthButton = new Button("Fifth Button");
private Panel emptyPanel = new Panel();

Constructori:
GridLayout() creeaz o singur linie cu cte o coloan
pentru fiecare component adugat, fr distan ntre
componente;

public GridFrame() {
this.setSize(400, 220);
this.setTitle("GridLayout");
this.setLayout(gLayout);
this.setBackground(new Color(240, 240, 240));
this.add(firstButton);
this.add(secondButton);
this.add(thirdButton);
this.add(fourthButton);
this.add(emptyPanel);
this.add(fifthButton);
show();
}

GridLayout(int rows, int cols) primete ca parametri


numrul de linii i coloane;
GridLayout(int rows, int cols, int hgap, int vgap)
primete ca parametri numrul de linii i coloane
respectiv distanele orizontale i verticale dintre
componente.

public static void main(String[] args) {


new GridFrame();
}
}

73

Limbajul Java interfa grafic (10)


Alinierea componentelor:
GridBagLayout mparte containerul n celule care
pot avea dimensiuni diferite. O component poate
ocupa mai multe celule. Exemplu:

First Button [0,0]

Second Button [0,2]

Third Button [1,0]


Fourth
Button
[2,0]

Fifth Button [2,1]

Last Button [4,1]

First Button:
gridy = 0,
gridx = 0 (celula [0,0])
gridwidth = 2, gridheight = 1 (dou coloane, o linie)
weightx = 0.6 (0.6 din extraspaiul orizontal)
weighty = 0.0 (0.0 din extraspaiul vertical)
Second Button:
gridy = 0, gridx = 2 (celula [0,2])
gridwidth = 2, gridheight = 1 (dou coloane, o linie)
weightx = 0.3 (0.3 din extraspaiul orizontal)
weighty = 0.0 (0.0 din extraspaiul vertical)
Third Button:
gridy = 1, gridx = 0 (celula [1,0])
gridwidth = 4, gridheight = 1 (patru coloane, o linie)
weightx = 0.0 (0.0 din extraspaiul orizontal)
weighty = 0.3 (0.3 din extraspaiul vertical)
Fourth Button:
gridy = 2, gridx = 0 (celula [2,0])
gridwidth = 1, gridheight = 3 (o coloan, trei linii)
weightx = 0.0 (0.0 din extraspaiul orizontal)
weighty = 0.3 (0.3 din extraspaiul vertical)
Fifth Button:
gridy = 2, gridx = 1 (celula [2,1])
gridwidth = 3, gridheight = 2 (trei coloane, dou linii)
weightx = 0.6 (0.6 din extraspaiul orizontal)
weighty = 0.6 (0.6 din extraspaiul vertical)
Last Button:
gridy = 4, gridx = 1 (celula [4,1])
gridwidth = 3, gridheight = 1 (trei coloane, o linie)
weightx = 0.6 (0.6 din extraspaiul orizontal)
74
weighty = 0.3 (0.3 din extraspaiul vertical)

Limbajul Java interfa grafic (11)


gbc.gridy = 1; //linia 1
gbc.gridx = 0; //coloana 0
gbc.gridwidth = 4; //ocupa 4 coloane
gbc.weightx = 0.0; //resetare
gbc.weighty = 0.3; //0.3 din extraspatiul vertical
gbLayout.setConstraints(thirdButton, gbc);
this.add(thirdButton);
gbc.gridy = 2; //linia 2
gbc.gridx = 0; //coloana 0
gbc.gridwidth = 1; //resetare
gbc.gridheight = 3; //ocupa trei linii
gbLayout.setConstraints(fourthButton, gbc);
this.add(fourthButton);
gbc.gridy = 2; //linia 2
gbc.gridx = 1; //coloana 1
gbc.gridwidth = 3; //ocupa trei coloane
gbc.gridheight = 2; //ocupa doua linii
gbc.weighty = 0.6; //0.6 din extraspatiul vertical
gbc.weightx = 0.6; //0.6 din extraspatiul orizontal
gbLayout.setConstraints(fifthButton, gbc);
this.add(fifthButton);
gbc.gridy = 4; //linia 4
gbc.gridx = 1; //coloana 1
gbc.gridheight = 1; //resetare
gbc.weighty = 0.3; //0.3 din extraspatiul vertical
gbLayout.setConstraints(lastButton, gbc);
this.add(lastButton);
show();

GridBagLayout codul surs


public class GridBagFrame extends Frame {
private GridBagLayout gbLayout = new GridBagLayout();
private GridBagConstraints gbc = new GridBagConstraints();
private Button firstButton = new Button("First Button");
private Button secondButton = new Button("Second Button");
private Button thirdButton = new Button("Third Button");
private Button fourthButton = new Button("Fourth Button");
private Button fifthButton = new Button("Fifth Button");
private Button lastButton = new Button("Last Button");
public GridBagFrame() {
this.setSize(400, 220);
this.setTitle("GridBagLayout");
this.setLayout(gbLayout);
this.setBackground(new Color(240, 240, 240));
gbc.fill = GridBagConstraints.BOTH; //directii de extindere
gbc.insets = new Insets(5, 5, 5, 5); //dist. fata de marginile celulei
gbc.gridy = 0; //linia 0
gbc.gridx = 0; //coloana 0
gbc.gridwidth = 2; //ocupa doua coloane
gbc.weightx = 0.6; //0.6 din extraspatiul orizontal
gbLayout.setConstraints(firstButton, gbc);
this.add(firstButton);
gbc.gridy = 0; //linia 0
gbc.gridx = 2; //coloana 2
gbc.weightx = 0.3; //0.3 din extraspatiul orizontal
gbLayout.setConstraints(secondButton, gbc);
this.add(secondButton);

}
public static void main(String[] args) {
new GridBagFrame();
}
}

75

Limbajul Java interfa grafic (12)


Crearea tabelelor



O clas care permite crearea tabelelor este JTable;


Gestionarea componentelor JTable se poate face prin clasa
DefaultTableModel;
Pentru o funcionare corect cu scroll, obiectul JTable trebuie
adugat pe un JScrollPane i nu pe ScrollPane!
Aplicaia urmtoare folosete dou tabele, unul prencrcat, iar
cellalt cu ncrcare dinamic a datelor:

76

Limbajul Java interfa grafic (13)


Codul surs al aplicaiei cu tabele
public class TableFrame extends Frame {
private GridLayout gLayout = new GridLayout(1, 2, 10, 10);
private JScrollPane leftScrollPane = new JScrollPane();
private JScrollPane rightScrollPane = new JScrollPane();
private String leftTableColumns[] = {"Name", "Age"}; //header
private Object leftTableData[][] = {{"Popescu", "103"}, {"Ionescu", "98"}}; //continut
private JTable leftTable = new JTable(leftTableData, leftTableColumns); //tabel cu date preincarcate
private JTable rightTable = new JTable(); //tabel gol
private String rightTableColumns[] = {"Column 1", "Column 2"}; //header
private DefaultTableModel rightTableModel = new DefaultTableModel(rightTableColumns, 0);
public TableFrame() {
this.setSize(400, 150);
this.setLayout(gLayout);
this.setTitle("Tables");
this.setBackground(new Color(240, 240, 240));
this.add(leftScrollPane);
this.add(rightScrollPane);
leftScrollPane.getViewport().add(leftTable, null);
rightScrollPane.getViewport().add(rightTable, null);
rightTable.setModel(rightTableModel);
for(int i=1; i<=10; i++){
String row[] = {"Row" + i + ", Col 1", "Row" + i + ", Col 2"};
rightTableModel.addRow(row);
}
show();
}
public static void main(String[] args) {
new TableFrame();
}
}

77

Limbajul Java interfa grafic (14)


Aplicaii
1.

Introducei n fereastra aplicaiei care gestioneaz lista de


studeni un buton Clear care s permit tergerea coninutului
listei. tergerea coninutului componentei List (din pachetul
AWT) se poate face prin metodele clear sau removeAll.

2.

Modificai funcia de adugare n list astfel nct aceasta s


pstreze lista sortat la introducerea unui nou student. Preluarea
coninutului componentei List (din AWT) ntr-un tablou de tip
String se poate efectua prin metoda getItems, iar preluarea liniei
de pe o anumit poziie se poate face prin metoda getItem cu un
parametru de tip int, reprezentnd poziia n list. Inserarea pe o
poziie n list se poate efectua prin metoda add cu un
parametru String i unul de tip int, reprezentnd poziia. De
asemenea, getItemCount returneaz numrul de linii din list.

3.

nlocuii lista din aplicaia prezentat cu un tabel.

4.

Dezvoltai aplicaia astfel nct, pe lng nume, s se introduc


n tabel adresa, vrsta i media studentului.

5.

Rearanjai componentele pe fereastr prin GridLayout sau


GridBagLayout i setai fereastra redimensionabil.
78

Limbajul Java fire de execuie (1)




Un fir de execuie (thread) este o secven de instruciuni executat de un


program.

Firul de execuie primar este metoda main i atunci cnd acesta se termin, se
ncheie i programul.

Un program poate utiliza fire multiple care sunt executate concurenial.

Utilizarea firelor multiple este util n cazul programelor complexe care


efectueaz seturi de activiti multiple.

Fiecare fir de execuie are o prioritate care poate lua valori de la 1 (prioritate
mic) la 10 (prioritate maxim). Firele cu prioritate mare sunt avantajate la
comutare, ele primesc mai des controlul procesorului.
Pentru implementarea unui fir de execuie n Java, se poate extinde clasa
Thread. Deoarece Java nu accept motenirea multipl, n cazul n care a fost
deja extins o clas, pentru crearea unui fir de execuie trebuie implementat
interfaa Runnable. Indiferent de metoda utilizat, se suprascrie metoda run
care trebuie s conin instruciunile firului.
Aplicaia urmtoare pornete dou fire de execuie: unul pentru afiarea
numerelor i cellalt pentru afiarea literelor. Pentru a observa diferenele dintre
cele dou metode de implementare, firul de execuie Numbers extinde clasa
Thread, n timp ce Letters implementeaz interfaa Runnable.
79

Limbajul Java fire de execuie (2)


Afiare concurenial de numere i litere:
public class Numbers extends Thread {
public void run(){
for(int i=0; i<1000; i++){
System.out.println(i);
}
}
}

//extinde clasa Thread

public class Letters implements Runnable {


char a = 'a';
public void run(){
for(int i=0; i<1000; i++){
int c = a + i%26;
System.out.println((char)c);
}
}
}

//implementeaza interfata Runnable

public class Main {


public static void main(String[] args) {
Numbers numbers = new Numbers();
Thread letters = new Thread(new Letters());
letters.start();
numbers.start();
}
}

80

Limbajul Java fire de execuie (3)




Principalele operaii care pot fi efectuate dup


crearea unui fir de execuie:



start pornete firul de execuie


setPriority seteaz prioritatea firului de execuie (valoare
ntre 1 i 10)
getPriority returneaz prioritatea firului de execuie
(valoare ntre 1 i 10)
sleep suspend execuia unui fir pentru o perioad
precizat n milisecunde.
yield suspend temporar execuia firului curent n
favoarea altor fire de execuie.

Se recomand oprirea firului prin ncheierea execuiei


metodei run.

Urmtoarea aplicaie folosete un fir de execuie


pentru deplasarea unei mingi pe orizontal.
81

Limbajul Java fire de execuie (4)


public class Ball extends Thread {
private int px = 0;
//pozitia x
private int py = 0;
//pozitia y
private int size = 0;
private Color color = null;
private MyFrame parent = null;
public Ball(MyFrame parent, int px, int py, int size, Color color) {
this.parent = parent;
//referinta la fereastra
this.px = px;
this.py = py;
this.size = size;
this.color = color;
}
public int getPX(){
return px;
}
public int getPY(){
return py;
}
public int getSize(){
return size;
}
public Color getColor(){
return color;
}
public void run(){
while(px < parent.getSize().width){
px++;
parent.paint();
}
}
}

//iesire din fereastra

82

Limbajul Java fire de execuie (5)


public class MyFrame extends Frame {
Ball ball = null;
Image buffer = null;
public MyFrame() {
this.setSize(new Dimension(400, 300));
this.setTitle("Balls");
this.addWindowListener(new java.awt.event.WindowAdapter() {
public void windowClosing(WindowEvent e) {
this_windowClosing(e);
}
});
setVisible(true);
buffer = createImage(getSize().width, getSize().height);
ball = new Ball(this, 20, 50, 20, Color.red);
ball.start();
}

//detectia evenimentului de inchidere a ferestrei

void paint(){
Graphics gbuffer = buffer.getGraphics();
//se deseneaza mai intai in buffer (tehnica Double Buffering)
gbuffer.setColor(Color.white);
gbuffer.fillRect(0, 0, getSize().width, getSize().height);
gbuffer.setColor(ball.getColor());
gbuffer.fillOval(ball.getPX(), ball.getPY(), ball.getSize(), ball.getSize());
paint(gbuffer);
//se copiaza imaginea din buffer pe fereastra (tehnica Double Buffering)
Graphics g = getGraphics();
g.drawImage(buffer, 0, 0, getSize().width, getSize().height, 0, 0, getSize().width, getSize().height, this);
}
void this_windowClosing(WindowEvent e) {
System.exit(0);
}
public static void main(String[] args){
new MyFrame();
}
}

//evenimentul de inchidere a ferestrei

83

Limbajul Java fire de execuie (6)


Sincronizarea firelor de execuie


Dac n cadrul unui program Java exist un fir de


execuie care creeaz (produce) date i un al doilea
fir de execuie care le prelucreaz (consum), de
regul se declar un bloc synchronized, ceea ce
permite ca un singur fir s aib acces la resurse
(metode, date) la un moment dat.
Atunci cnd un fir de execuie apeleaz wait n cadrul
unui bloc de cod synchronized, alt fir poate accesa
codul.
Iar atunci cnd un fir de execuie ncheie procesarea
codului synchronized, el apeleaz metoda notify
pentru a anuna alte fire de execuie s nceteze
ateptarea.
Relum n continuare aplicaia care afieaz numere
i litere sincroniznd cele dou fire de execuie.
84

Limbajul Java fire de execuie (7)


public class Numbers extends Thread {
Main m;
public Numbers(Main m){
this.m = m;
}
public void run(){
m.numbers();
}
}
public class Letters implements Runnable {
Main m;
public Letters(Main m){
this.m = m;
}
public void run(){
m.letters();
}
}
public class Main {
public Main(){
Numbers numbers = new Numbers(this);
Thread letters = new Thread(new Letters(this));
letters.start();
numbers.start();
}

public synchronized void numbers(){


for(int i=0; i<1000; i++){
if(i%26==0){
try {
this.notify();
this.wait();
}
catch (InterruptedException ex) { }
}
System.out.println(i);
}
this.notify();
}
public synchronized void letters(){
char a = 'a';
for(int i=0; i<1000; i++){
if(i%26==0){
try {
this.notify();
this.wait();
}
catch (InterruptedException ex) { }
}
int c = a + i%26;
System.out.println((char)c);
}
this.notify();
}
public static void main(String[] args) {
new Main();
}
}

85

Limbajul Java fire de execuie (8)


Aplicaii propuse:
1.

Introducerea unei ntrzieri de 10 ms n algoritmul de micare a bilei din aplicaia prezentat.

2.

Modificarea aplicaiei astfel nct s permit pornirea mai multor mingi simultan.

3.

S se nlocuiasc algoritmul de deplasare a mingii pe orizontal cu urmtorul algoritm de micare:


dx = 1;
dy = 1;
while (true){
px += dx;
py += dy;
if((px <= 0) || (px >= frame_width))
dx = -dx;
if((py <= 0) || (py >= frame_height))
dy = -dy;
paint();
}

Un alt algoritm de micare:


gravy = 1;
speed = -30
speedy = -30;
speedx = 0;
while(true){
speedy += gravy;
py += speedy;
px += speedx;
if(py > frameheight){
speedy = speed;
speed += 3;
}
if(speed == 0) break;
paint();
}

86

Limbajul Java colecii (1)


O colecie grupeaz date ntr-un singur obiect i permite manipularea acestora.
Clasele Vector i ArrayList


Permit implementarea listelor redimensionabile cu elemente referin de orice


tip, inclusiv null.
O diferen important: Vector este sincronizat, iar ArrayList este nesincronizat,
ceea ce-l face mai rapid. Dac un ArrayList este accesat i modificat de mai
multe fire de execuie concurenial, necesit sincronizare extern (a obiectului
care ncapsuleaz lista). O alt soluie const n crearea unei instane
sincronizate, prevenind astfel eventualele accese nesincronizate:
List list = Collections.synchronizedList(new ArrayList(...));

Clasa Vector s-a pstrat pentru compatibilitate cu versiuni JDK mai vechi de 1.2.

Exemple
Vector vector = new Vector();
vector.addElement(new Integer(1));
vector.add(new Integer(3));
vector.insertElementAt(new Integer(5), 1);
vector.setElementAt(new Integer(2), 1);

//vector
//vector
//vector
//vector
//vector

gol
= {1}
= {1, 3}
= {1, 5, 3}
= {1, 2, 3}

ArrayList list = new ArrayList();


list.add(new Integer(1));
list.add(new Integer(3));
list.add(1, new Integer(5));
list.set(1, new Integer(2));

//lista goala
//list = {1}
//list = {1, 3}
//list = {1, 5, 3}
//list = {1, 2, 3}

87

Limbajul Java colecii (2)


Clasa Stack


Permite implementarea sincronizat a stivelor

Extinde clasa Vector cu operaiile specifice stivei:








push introduce un element n vrful stivei;


pop scoate elementul din vrful stivei;
peek preia (citete) elementul din vrful stivei, fr s-l scoat;
empty verific dac stiva e goal;
search returneaz poziia unui obiect din stiv fa de vrf.

Exemple:
Stack stack = new Stack();
//stiva goala
System.out.println(stack.empty());
//true
stack.push(new Integer(1));
//stack = {1}
stack.push(new Integer(2));
//stack = {1, 2}
stack.push(new Integer(3));
//stack = {1, 2, 3}
System.out.println(stack.search(new Integer(3))); //1
System.out.println(stack.search(new Integer(2))); //2
System.out.println(stack.empty());
//false
System.out.println(stack.pop());
//3, stack = {1, 2}
System.out.println(stack.peek());
//2, stack = {1, 2}
System.out.println(stack.pop());
//2, stack = {1}
System.out.println(stack.pop());
//1, stiva goala
System.out.println(stack.empty());
//true
88

Limbajul Java colecii (3)


Clasa LinkedList



Permite implementarea stivelor i a cozilor.


Diferena fa de Stack: LinkedList este nesincronizat (deci mai rapid). Nefiind
sincronizat, LinkedList necesit sincronizare extern n caz de accesare
concurenial multifir.
Exemple:
LinkedList stack = new LinkedList();
stack.addLast(new Integer(1));
stack.addLast(new Integer(2));
stack.addLast(new Integer(3));
System.out.println(stack.removeLast());
System.out.println(stack.getLast());
System.out.println(stack.removeLast());
System.out.println(stack.removeLast());

//stiva goala
//stack = {1}
//stack = {1, 2}
//stack = {1, 2, 3}
//3, stack = {1, 2}
//2, stack = {1, 2}
//2, stack = {1}
//1, stiva goala

LinkedList queue = new LinkedList();


queue.addFirst(new Integer (1));
queue.addFirst(new Integer(2));
queue.addFirst(new Integer(3));
System.out.println(queue.removeLast());
System.out.println(queue.removeLast());
System.out.println(queue.removeLast());

//coada goala
//queue = {1}
//queue = {2, 1}
//queue = {3, 2, 1}
//1, queue = {3, 2}
//2, queue = {3}
//3, coada goala
89

Limbajul Java colecii (4)


Clasele HashSet, TreeSet i LinkedHashSet



Interfaa Set permite folosirea mulimilor colecii de date n care elementele


sunt unice.
Clasa HashSet pstreaz elementele adugate n ordinea stabilit de o funcie
de dispersie, asigurnd astfel operaii de introducere i preluare a unui element
rapide, de complexitate O(1). Funcia de dispersie poate fi schimbat prin
redefinirea metodei hashCode().
Clasa TreeSet pstreaz elementele sortate n ordine cresctoare, ceea ce
determin operaii de introducere i preluare a unui element mai lente, de
complexitate O(log n).
Clasa LinkedHashSet (disponibil ncepnd cu versiunea JDK 1.4) pstreaz
elementele n ordinea n care au fost introduse asigurnd operaii de accesare a
unui element de complexitate O(1).
Exemple













HashSet hs = new HashSet();


hs.add(new Integer(1));
hs.add(new Integer(2));
hs.add(new Integer(4));
hs.add(new Integer(2));

//hs
//hs
//hs
//hs
//hs

=
=
=
=
=

{}
{1}
{2, 1}
{2, 4, 1}
{2, 4, 1}

TreeSet ts = new TreeSet(hs);


ts.add(new Integer(3));

//ts = {1, 2, 4}
//ts = {1, 2, 3, 4}

LinkedHashSet lhs = new LinkedHashSet(); //lhs = {}


lhs.add(new Integer(1));
//lhs = {1}
lhs.add(new Integer(2));
//lhs = {1, 2}
lhs.add(new Integer(4));
//lhs = {1, 2, 4}
lhs.add(new Integer(3));
//lhs = {1, 2, 4, 3}

90

Limbajul Java colecii (5)


Implementarea interfeei Comparable pentru
obiectele ncrcate n TreeSet


Obiectele ncrcate n TreeSet sunt sortate prin intermediul funciei compareTo. De


aceea, clasa obiectelor ncrcate trebuie s implementeze interfaa Comparable.
Proprietatea de set (mulime) se aplic cmpului dup care se face comparaia n
compareTo. Dac valoarea acelui cmp este aceeai n dou obiecte, chiar dac celelalte
cmpuri difer, n set rmne doar unul din obiecte. De aceea, dac n compareTo
valorile cmpului comparat sunt egale se poate ine cont de celelalte cmpuri, aplicnd
astfel proprietatea de set pe ntregul obiect.
Exemplu:
public class Person implements Comparable{
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public int compareTo(Object p){
return this.name.compareTo(((Person)p).name);
}

public class Main {


public static void main(String[] args) {
Person p = new Person("Popescu", 103);
TreeSet ts = new TreeSet();
ts.add(p); //{Popescu-103}
Person q = new Person("Ionescu", 98);
ts.add(q); //{Ionescu-98, Popescu-103}
Person r = new Person("Petrescu", 49);
ts.add(r); //{Ionescu-98, Petrescu-49, Popescu-103}
}
}

91

Limbajul Java colecii (6)


Clasele HashMap, TreeMap i LinkedHashMap







Interfaa Map permite pstrarea de perechi cheie-valoare, ambele de tip


referin, cu chei unice. Principalele operaii:

put(k, v) asociaz cheii k valoarea v. Dac exist deja cheia k atunci
vechea valoare se nlocuiete cu v.

get(k) returneaz valoarea corespunztoare cheii k.
Clasa HashMap pstreaz cheile n ordinea stabilit de o funcie de dispersie
asigurnd astfel accesri rapide, de complexitate O(1).
Clasa TreeMap pstreaz cheile ordonate cresctor, accesarea fiind astfel mai
lent, de complexitate O(log n).
Clasa LinkedHashMap (disponibil ncepnd cu JDK 1.4) pstreaz cheile n
ordinea n care au fost introduse asigurnd accesri de complexitate O(1).
Exemple















HashMap hm = new HashMap();


hm.put("Romania", "Bucuresti");
hm.put("Franta", "Paris");
hm.put("Germania", "Bonn");
hm.put("Germania", "Berlin");
System.out.println(hm);
//{Romania=Bucuresti, Germania=Berlin, Franta=Paris}
System.out.println(hm.get("Germania")); //Berlin
TreeMap tm = new TreeMap(hm);
System.out.println(tm);

//{Franta=Paris, Germania=Berlin, Romania=Bucuresti}

LinkedHashMap lhm = new LinkedHashMap();


lhm.put("Romania", "Bucuresti");
lhm.put("Franta", "Paris");
lhm.put("Germania", "Berlin");
System.out.println(lhm);
//{Romania=Bucuresti, Franta=Paris, Germania=Berlin}

92

Limbajul Java colecii (7)


Implementarea interfeei Comparable pentru
cheile ncrcate n TreeMap


Perechile cheie-valoare ncrcate n TreeMap sunt sortate n ordinea cresctoare a


cheilor, prin intermediul funciei compareTo. De aceea, clasa obiectelor cheie trebuie s
implementeze interfaa Comparable.
Exemplu:
public class Person implements Comparable{
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public int compareTo(Object p){
return this.name.compareTo(((Person)p).name);
}
}

public class Main {


public static void main(String[] args) {
Person p = new Person("Pop", 54);
TreeMap tm = new TreeMap();
tm.put(p, "Romania");
//tm={Pop-54-Romania}
Person q = new Person("Brown", 98);
tm.put(q, "Anglia");
//tm={Brown-98-Anglia, Pop-54-Romania}
Person r = new Person("Schmitt", 49);
tm.put(r, "Germania");
//tm={Brown-98-Anglia, Pop-54-Romania, Schmitt-49-Germania}
}
}

93

Limbajul Java colecii (8)


Iteratori


Iteratorii permit traversarea n ordine a coleciilor de date.

Exemplu:








TreeSet ts = new TreeSet();


ts.add("Romania");
ts.add("Anglia");
ts.add("Germania");
ts.add("Franta");
Iterator i = ts.iterator();
while(i.hasNext()) System.out.println(i.next());

Secvena de cod afieaz:







Anglia
Franta
Germania
Romania
94

Limbajul Java colecii (9)


Aplicaii propuse
1.

S se modifice programele prezentate la TreeSet i TreeMap astfel nct sortarea


persoanelor s se fac dup vrst n cazul n care au acelai nume.

2.

Definii clasa Course cu cmpurile title, teacher (profesor), credits (nr. credite) i
year (an de studiu). Introducei de la tastatur cinci obiecte de tip Course ntr-un
TreeSet i afiai cursul cu cel mai mic numr de credite.

3.

Definii clasa Course cu cmpurile title, teacher (profesor), credits (nr. credite) i
year (an de studiu). Introducei de la tastatur cinci obiecte de tip Course ntr-un
TreeSet i afiai cursul cu cel mai mare numr de credite.

4.

Definii clasa Course cu cmpurile title, teacher (profesor), credits (nr. credite) i
year (an de studiu). Introducei de la tastatur cinci obiecte de tip Course ntr-un
TreeSet i afiai-le n ordinea descresctoare a numrului de credite.

5.

Definii clasa Course cu cmpurile title, teacher (profesor), credits (nr. credite) i
year (an de studiu). Introducei de la tastatur cinci obiecte de tip Course ntr-un
TreeSet i afiai-le n ordinea cresctoare a anului de studiu.

6.

Definii clasa Course cu cmpurile title, teacher (profesor), credits (nr. credite) i
year (an de studiu). Introducei de la tastatur cinci obiecte de tip Course ntr-un
TreeSet i afiai-le n ordinea alfabetic a titlului.

7.

Definii clasa Course cu cmpurile title, teacher (profesor), credits (nr. credite) i
year (an de studiu). Introducei de la tastatur cinci obiecte de tip Course ntr-un
TreeSet i afiai-le n ordinea alfabetic a profesorului.

95

Limbajul Java test




Test gril (T1) susinut la curs din noiunile


predate n cadrul capitolului Limbajul Java;
Test (T2) susinut la laborator din aplicaiile
propuse la laborator se va implementa i
rula pe calculator o aplicaie care implic o
motenire respectiv folosirea unor colecii de
date.

96

Partea II
Analiza algoritmilor

Analiza algoritmilor


Algoritmul este o secven de operaii care


transform mulimea datelor de intrare n datele de
ieire.
Analiza algoritmului se refer la evaluarea
performanelor acestuia (timp de execuie, spaiu de
memorie). Scopul este acela de a gsi algoritmul cel
mai eficient pentru o anumit problem.
La analiza algoritmilor trebuie avut n vedere modelul
de implementare (secvenial, paralel) i arhitectura
mainii de calcul (superscalar, multithreading,
multicore) respectiv dac aceasta permite sau nu
execuia speculativ a instruciunilor.
98

Analiza algoritmilor maina Turing




Conjectura Church-Turing postuleaz c pentru orice algoritm


exist o main Turing echivalent. Cu alte cuvinte, nicio
procedur de calcul nu este algoritm dac nu poate fi executat
de o main Turing. n esen, maina Turing reprezint ceea
ce astzi numim algoritm. Aadar, o main Turing este
echivalent cu noiunea de algoritm.
O main Turing const din:


O band mprit n celule, fiecare coninnd un simbol (inclusiv


cel vid) dintr-un alfabet finit.
Un cap care poate scrie i citi i care se poate deplasa la stnga
sau la dreapta.
Un registru de stare care stocheaz starea mainii Turing. Numrul
strilor este finit i exist o stare iniial.
O funcie de tranziie (tabel de aciuni) care, n funcie de starea
curent i simbolul citit, determin ce simbol s se scrie, cum s se
deplaseze capul (la stnga sau la dreapta) i care va fi noua stare.

Maina Turing se oprete dac se ajunge ntr-o stare final sau


dac nu exist combinaia de simbol-stare n tabela de aciuni.
99

Analiza algoritmilor complexitate (1)




Complexitatea unui algoritm, exprimat n funcie de dimensiunea


datelor de intrare (n), are urmtoarele componente:


Complexitate temporal numrul de operaii necesare pentru rezolvarea


unei probleme
Complexitate spaial spaiul de memorie utilizat

Complexitatea temporal este indicatorul principal al performanei unui


algoritm.
Complexitatea temporal a unui algoritm poate fi determinat
experimental (prin msurarea timpului de rulare) sau prin analiz
teoretic (prin aproximarea numrului de operaii primitive).
Complexitatea unui algoritm este de regul exprimat (aproximat) prin
notaii asimptotice [Cor00] care rein doar termenul dominant al
expresiei, ceilali termeni devenind neglijabili pentru valori mari ale lui n.
Exemple:


Dac execuia unui algoritm necesit 2n+n5+8 operaii, atunci complexitatea


temporal este 2n;
Un algoritm cu 7n4+10n2+1000n operaii elementare are complexitate n4.
100

Analiza algoritmilor complexitate (2)


-notaia
( g (n)) = { f (n) c1 , c 2 , n0 > 0 a. . 0 c1 g (n) f (n) c 2 g (n), n n0 }
c2g(n)
f(n)
c1g(n)

n0

-notaia delimiteaz o funcie asimptotic inferior i


superior, g(n) este o margine asimptotic tare pentru f(n).
101

Analiza algoritmilor complexitate (3)


O-notaia
O( g (n)) = { f (n) c, n0 > 0 a. . 0 f (n) c g (n), n n0 }
c g(n)
f(n)

n0

O-notaia delimiteaz o funcie asimptotic superior,


g(n) este o margine asimptotic superioar.
102

Analiza algoritmilor complexitate (4)


-notaia
( g (n)) = { f (n) c, n0 > 0 a.. 0 c g (n) f (n), n n0 }
f(n)
c g(n)

n0

-notaia delimiteaz o funcie asimptotic inferior,


g(n) este o margine asimptotic inferioar.
103

Analiza algoritmilor complexitate (5)




o-notaia: Delimitarea asimptotic superioar dat de notaia O


poate sau nu s fie o delimitare asimptotic strns. De exemplu,
2n2=O(n2) este o delimitare asimptotic strns, pe cnd 2n2=O(n3)
nu este. Vom folosi o-notaia pentru a desemna o delimitare
superioar care nu este asimptotic strns: 2n2=o(n3).

o( g (n)) = { f (n) c > 0, n0 > 0 a. . 0 f (n) < c g (n), n n0 }




-notaia desemneaz o delimitare asimptotic inferioar care nu


este asimptotic strns: 2n2=(n).

( g (n)) = { f (n) c > 0, n0 > 0 a.. 0 c g (n) < f (n), n n0 }




Teorem: Pentru orice dou funcii f(n) i g(n), avem f(n)=(g(n))


dac i numai dac f(n)=O(g(n)) i f(n)=(g(n)).
Convenie: n orice ecuaie n care se folosesc notaii asimptotice
membrul drept ofer un nivel de detaliu mai sczut dect membrul
stng. Exemplu: 2n2+3n+1 = 2n2+(n) = (n2). Putem scrie
2n2+3n+1 = (n2), dar nu scriem niciodat (n2) = 2n2+3n+1.
104

Analiza algoritmilor complexitate (6)


Alte exemple [Knu00]


tim c
12 + 2 2 + ... + n 2 =

n(n + 1)(2n + 1) 1 3 1 2 1
= n + n + n
6
3
2
6

(1)

Rezult c
12 + 2 2 + ... + n 2 = O(n 4 )

(2)

12 + 2 2 + ... + n 2 = O(n 3 )

(3)

1
12 + 2 2 + ... + n 2 = n 3 + O(n 2 )
3

(4)

Ecuaia (2) este destul de nerafinat, dar nu incorect; ecuaia


(3) este mai puternic, iar ecuaia (4) i mai puternic.

105

Analiza algoritmilor complexitate (7)


Ordinul de complexitate
Constant
Logaritmic
Liniar
Liniar logaritmic
Ptratic
Polinomial (p>2)
Exponenial

O(1)
O(log n)
O(n)
O(n log n)
O(n2)
O(np)
O(an)

106

Analiza algoritmilor complexitate (8)


Exprimai urmtoarele complexiti cu ajutorul
notaiei :
1) n 3 + 100n 2
2) 2 n + 5n + 3
3) n

2n

+ 4 2n

4) 2 n 2 + n ln n
5) n k + n + n k ln n
6) 1 + 2 + ... + n
7) 12 + 2 2 + ... + n 2
8) 13 + 2 3 + ... + n 3
9) 1 2 + 2 3 + ... + n (n + 1)
10) 12 + 3 2 + ... + (2n 1) 2

107

Analiza algoritmilor logaritmi (1)




Vom utiliza urmtoarele notaii:


lg n = log 2 n
ln n = log e n
lg k n = (lg n) k
lg lg n = lg(lg n)

Deoarece schimbarea bazei unui logaritm de la o


constant la alta schimb valoarea logaritmului doar
printr-un factor constant, vom folosi notaia lg n
atunci cnd factorii constani nu vor fi importani.

108

Analiza algoritmilor logaritmi (2)


Pentru orice numere reale a>0, b>0, c>0 i n,

a = b logb a
log c (ab) = log c a + log c b
log b a n = n log b a
log c a
log b a =
log c b
log b a =

1
log a b

log b a log a b = 1
log b a = log b c log c a
c
= log b c log b a
a
1
log b = log b a
a
a logb n = n log b a
log b

109

Analiza algoritmilor recurene (1)


O recuren este o ecuaie care descrie o funcie exprimnd valoarea sa pentru
argumente mai mici. Cnd un algoritm conine o apelare recursiv la el nsui,
timpul su de execuie poate fi descris printr-o recuren. Recurenele pot fi
rezolvate prin metoda substituiei, metoda iteraiei sau metoda master [Cor00].
Metoda master ofer o soluie simpl pentru rezolvarea recurenelor de forma:

n
T ( n) = a T + f ( n)
b
unde a1, b>1, iar f(n) este o funcie dat.
Teorema master. Fie a1 i b>1 constante, f(n) o funcie i T(n) definit pe
ntregii nenegativi prin recurena

n
T ( n) = a T + f ( n)
b
atunci T(n) poate fi delimitat asimptotic dup cum urmeaz:
1. dac f (n) = O(n logb a ), > 0 T (n) = (n logb a )
2. dac f (n) = (n logb a ) T (n) = (n logb a lg n)
n
3. dac f (n) = (n logb a + ), > 0 i af cf (n), c < 1 i n suficient de mari T (n) = ( f (n)).
b
110

Analiza algoritmilor recurene (2)


Exemplu de utilizare a metodei master

n
S considerm T (n) = 9 T + n
3
Pentru aceast recuren a=9, b=3, f(n)=n, astfel

n log b a = n log 3 9 = n 2
log 9
) = O(n), = 1,
Deoarece f (n) = O(n
aplicnd cazul 1 al teoremei master,
3

T (n) = (n log3 9 ) = (n 2 )
111

Analiza algoritmilor recurene (3)


Exemplu de neaplicabilitate a metodei master
S considerm urmtoarea recuren:
T ( n) = 2T ( n / 2) + n lg n
Pentru aceast recuren a=2, b=2, f(n)=n lg n. Astfel,
n log b a = n log 2 2 = n1 = n
Se poate observa c niciunul din cazurile teoremei master
nu se poate aplica:

1. n lg n O(n1 ), > 0
2. n lg n (n)
3. n lg n (n1+ ), > 0 (ex. = 0.01, n1.01 > n lg n)
Vom folosi n continuare metoda iteraiei pentru rezolvarea
acestei recurene.
112

Analiza algoritmilor recurene (4)


Rezolvare prin metoda iteraiei a recurenei
T (n) = 2T (n / 2) + n lg n

Iterm recurena dup cum urmeaz:


n
T (n) = 2T + n lg n
2
n

2 n n
n
n
2T = 22T + lg = 2 2 T 2
2
2
2 2 2

+ n lg
2

n n
n
n
n
n
2 2 T 2 = 2 2 2T 3 + 2 lg 2 = 2 3 T 3 + n lg 2
2
2
2
2
2 2
n
n
n
2 q 1 T q 1 = 2 q T q + n lg q 1
2
2
2

Considernd condiia la limit T(1)=(1), recurena se termin pentru


n
q
=
1

2
= n q = lg n
q
2

113

Analiza algoritmilor recurene (5)


Am artat c la limita T(1)=(1), q=lg n. Obinem:
T ( n) = 2

lg n

T (1) +

lg n 1

n lg
k =0

T ( n) = 2

n
2k

lg n 1

lg n

(1) + n lg n lg 2 k
k =0

lg n 1

T (n) = n (1) + n lg n lg n n lg 2 k
lg 2

k =0

lg n 1

T (n) = n (1) + n lg n n k
1

k =0

n(n 1)
k
=

2
k =0
n 1

lg n 1

k =
k =0

lg n (lg n 1)
2

n lg n (lg n 1)

T (n) = n + n lg 2 n

T (n) = n lg 2 n

114

Analiza algoritmilor recurene (6)


Exerciii. Dai o delimitare asimptotic strns
pentru urmtoarele recurene:
1) T(n) = T(2n/3) + 1
2) T(n) = 3T(n/4) + n lg n
3) T(n) = 3T(n/3) + n/2
4) T(n) = 2T(n/2) + n
5) T(n) = 16T(n/4) + n
6) T(n) = 4T(n/2) + n2
7) T(n) = 4T(n/2) + n3

115

Analiza algoritmilor tipuri de analiz




Principalele tipuri de analiz




Analiza cazului cel mai favorabil cel mai scurt


timp de execuie posibil pe date de intrare de
dimensiune constant n;
Analiza cazului cel mai defavorabil cel mai mare
timp de execuie posibil relativ la orice date de
intrare de dimensiune constant n;
Analiza cazului mediu timpul mediu de execuie
al unui algoritm considernd toate datele de
intrare de dimensiune constant n. Exist ns
probleme la care nu e prea clar care sunt datele
de intrare de complexitate medie.

Urmeaz cteva exemple de analiz a unor


algoritmi: cutare, sortare, etc.
116

Analiza algoritmilor cutarea maximului (1)


Se d un tablou X de n elemente. S se gseasc m astfel nct
m = max1knX[k], considernd cel mai mare indice k care
satisface aceast relaie.
1.
2.
3.
4.
5.

k  n-1, m  X[n].
Dac k=0, algoritmul se ncheie.
Dac X[k]m, mergei la pasul 5.
m  X[k].
Decrementai k cu 1 i revenii la pasul 2.

Pasul Cost

Nr. execuii

1.

c1

2.

c2

3.

c3

n-1

4.

c4

5.

c5

n-1

Pentru ca analiza s fie


complet trebuie s
determinm mrimea A, care
reprezint numrul de
modificri ale valorii maxime
curente.
117

Analiza algoritmilor cutarea maximului (2)


Determinarea mrimii A
 Cazul cel mai favorabil: A=0, se obine atunci cnd
maximul este X[n];
 Cazul cel mai defavorabil: A=n-1, se obine atunci
cnd maximul este X[1];
 Cazul mediu: presupunnd c cele n valori sunt
distincte, conteaz doar ordinea lor relativ. Dac
n=3, exist urmtoarele posibiliti echiprobabile:
Situaie

X[1]>X[2]>X[3]

X[1]>X[3]>X[2]

X[2]>X[1]>X[3]

X[2]>X[3]>X[1]

X[3]>X[1]>X[2]

X[3]>X[2]>X[1]

0
118

Analiza algoritmilor cutarea maximului (3)


Determinarea valorii A pentru cazul mediu


Probabilitatea ca A s aib valoarea k va fi


pnk=(nr. situaii n care A=k)/n!

n exemplul anterior p30=1/3, p31=1/2, p32=1/6

Valoarea medie a lui A este definit astfel:

An = k p nk
k

An reprezint de fapt media ponderat a valorilor lui A.




n exemplul anterior valoarea medie a lui A pentru n=3


va fi 5/6. Knuth arat c pentru n mare An=ln n.
119

Analiza algoritmilor cutarea maximului (4)


Determinarea complexitii


Cazul cel mai favorabil:


c1 + c2n + c3(n-1) + 0 + c5(n-1) =
(c2+c3+c5)n + (c1-c3-c5) = an+b = (n)
Cazul cel mai defavorabil:
c1 + c2n + c3(n-1) + c4(n-1) + c5(n-1) =
(c2+c3+c4+c5)n + (c1-c3-c4-c5) = an+b = (n)

Cazul mediu:
c1 + c2n + c3(n-1) + c4ln n + c5(n-1) =
(c2+c3+c5)n + c4ln n + (c1-c3-c5) = an + b ln n + c = (n)
120

Analiza algoritmilor cutarea maximului (5)


Punnd problema mai simplu,
m  X[n]
for k  n-1 downto 1 do
if X[k]>m then m  X[k]

Cost
c1
c2
c3

Execuii
1
n
n-1

considernd operaie elementar fiecare iteraie a ciclului, e


uor de observat c bucla este parcurs n ntregime, deci
algoritmul are aceeai complexitate
(c2+c3)n + (c1-c3) = an+b = (n)
indiferent de ordinea relativ a celor n valori.
121

Analiza algoritmilor cutarea secvenial


Se d un tablou X de n elemente. Se parcurge secvenial tabloul X pn la primul element care
are valoarea k.
Cost
Execuii
1. i  1.
c1
1
2. Dac X[i] = k, algoritmul se ncheie cu succes.
c2
C
C-S
3. i  i+1.
c3
4. Dac in se revine la pasul 2.
c4
C-S
n caz contrar, algoritmul se ncheie fr succes.
unde C este numrul de comparaii de chei i S este 1 n caz de succes respectiv 0 n caz de
cutare fr succes. Complexitatea algoritmului este:
c1 + c2C + c3(C-S) + c4(C-S)
n cazul n care valoarea nu este gsit, avem C=n, S=0, cu o complexitate
(c2+c3+c4)n + c1 = an+b = (n)
n caz de succes, cu X[i]=k, avem C=i, S=1, cu o complexitate
(c2+c3+c4)i + (c1-c3-c4)
Considernd c valorile din tablou sunt distincte i echiprobabile, valoarea medie a lui C este

1 + 2 + ... + n n + 1
=
n
2
deci complexitatea n cazul mediu este tot (n).

122

Analiza algoritmilor cutarea binar (1)


Se d un tablou X de n elemente ordonate cresctor. Valoarea cutat k
se compar cu elementul din mijlocul tabloului, iar rezultatul acestei
comparaii ne arat n care jumtate trebuie continuat cutarea.
1. s  1, d  n
2. Dac d<s alg. se ncheie fr succes.
Altfel, i  (s+d)/2.
3. Dac k<X[i] se trece la pasul 4.
Dac k>X[i] se trece la pasul 5.
Dac k=X[i] alg. se ncheie cu succes.
4. d  i-1 i se revine la pasul 2.
5. s  i+1 i se revine la pasul 2.

Cost
c1
c2

Execuii
1
C+1-S

c3

c45

C-S

unde C este numrul de comparaii de chei i S este 1 n caz de succes


respectiv 0 n caz de cutare fr succes. Complexitatea algoritmului
este:
c1 + c2(C+1-S) + c3C + c45(C-S)
123

Analiza algoritmilor cutarea binar (2)


Determinarea valorii C pentru cazul cel mai defavorabil
Valoarea maxim a lui C (numrul comparaiilor de chei) poate
fi exprimat prin urmtoarea recuren
n
T ( n) = T + (1)
2
care descrie njumtirea recurent a spaiului de cutare cu un
cost constant (1).
Aplicnd terorema master, avem a=1 (cutarea se continu pe
o singur ramur st./dr.), b=2 (spaiul de cutare se reduce la
jumtate) i f(n)=(1). Astfel,

n log b a = n log 2 1 = n 0 = 1
deci putem aplica cazul 2 al teoremei master. Prin urmare,
T (n) = (n logb a lg n) = (n 0 lg n) = (lg n)
Astfel, n cazul cel mai defavorabil, C=(lg n) iar complexitatea
temporal este:
(c2+c3+c45)(lg n) + (c1+c2) = (lg n).
124

Analiza algoritmilor cutarea binar (3)


Determinarea valorii C pentru cazul mediu
Considernd c valorile din tablou sunt distincte i echiprobabile,
n cazul mediu valoarea cutat este gsit la jumtatea
procesului de cutare, ceea ce n numr de iteraii este echivalent
cu parcurgere total dar divizarea recurent a spaiului de cutare
la un sfert:
n
T (n) = T + (1)
4

Aplicnd teorema master, avem a=1, b=4 i f(n)=(1). Astfel,


n logb a = n log 4 1 = n 0 = 1
deci putem aplica cazul 2 al teoremei master. Prin urmare,
T (n) = (n logb a lg n) = (n 0 lg n) = (lg n)
Astfel, n cazul mediu, la fel ca n cazul cel mai defavorabil,
C=(lg n), deci complexitatea temporal este tot (lg n).
125

Analiza algoritmilor sortare prin inserie (1)


Se d un tablou X de n elemente. Se consider pe rnd vectorii formai
din primele 2, 3, ..., n elemente din tablou, ordonate prin aducerea noului
element (al 2-lea, al 3-lea, ..., al n-lea) pe poziia corespunztoare valorii
sale. Aceasta presupune deplasarea la dreapta a elementelor cu valori
mai mari, astfel nct noul element s poat fi inserat naintea lor:
1

sortat

nesortat

Cost
c1

Execuii
n

k  X[j]

c2

n-1

i  j-1

c3

n-1

while i>0 and X[i]>k do

c4

X[i+1]  X[i]

c5

(t

1)

i  i-1

c6

(t

1)

c7

n-1

for j  2 to n do

X[i+1]  k

j =2
n

j =2
n
j =2

unde am notat cu tj numrul de execuii ale testului while

126

Analiza algoritmilor sortare prin inserie (2)


Determinarea complexitii n cazul cel mai favorabil


Vectorul de intrare este deja sortat, deci bucla while nu


se execut niciodat (se verific doar condiiile o singur
dat n fiecare iteraie for), astfel tj=1, rezult:
n

t
j =2

= n 1

(t
j =2

1) = 0

c1n + c2 (n 1) + c3 (n 1) + c4 (n 1) + c7 (n 1) =
(c1 + c2 + c3 + c4 + c7 )n (c2 + c3 + c4 + c7 ) = an + b = (n)
127

Analiza algoritmilor sortare prin inserie (3)


Determinarea complexitii n cazul cel mai defavorabil


Vectorul de intrare este sortat n ordine invers, deci bucla while se


execut de 1, 2, ..., n-1 ori (condiiile fiind verificate de 2, 3, ..., n ori)
pentru j=2, 3, ...,n, astfel tj=j,


j =2

j =2

t j = j =
n

(t j 1) =
j =2

n(n + 1)
1
2

n(n + 1)
n(n 1)
1 (n 1) =
2
2

n(n 1)
n(n 1)
n(n + 1)
1 + c 5
c1 n + c 2 (n 1) + c3 (n 1) + c 4
+ c6
+ c7 (n 1) =
2
2
2

c 4 c5 c 6
c 4 c5 c 6 2

+
+
n
+
c
+
c
+
c
+

+
c

1
2
3
7 n (c 2 + c 3 + c 4 + c 7 ) =
2 2
2 2 2
2

an 2 + bn + c = (n 2 )

128

Analiza algoritmilor sortare prin inserie (4)


Determinarea complexitii n cazul mediu


S presupunem c alegem la ntmplare n numere distincte i aplicm


sortarea prin inserie.
Cte iteraii sunt necesare pentru inserarea elementului X[j] n
subvectorul X[1...j-1]? n medie jumtate din elementele subvectorului
X[1...j-1] sunt mai mici dect X[j] i jumtate sunt mai mari. Prin
urmare, n medie, trebuie verificate jumtate din elementele
subvectorului X[1...j-1], deci tj=j/2,
1 n
1 n(n + 1) n 2 + n 2
tj = j =
1 =

2
2
2
4

j =2
j =2
n

n2 + n 2
n 2 3n + 2
(t j 1) =
( n 1) =

4
4
j =2
n

Astfel, complexitatea n cazul mediu va fi tot (n2), la fel ca n cazul cel


mai defavorabil.
129

Analiza algoritmilor sortare prin selecie (1)


Se d un tablou X de n elemente. Se consider pe rnd
subtablourile formate din elementele i, ..., n (cu i=1, 2, ..., n) i
se aduce prin interschimbare elementul minim al fiecrui
subtablou pe poziia i:

min

sortat

nesortat

SELSORT1 (X)
for i  1 to n-1 do
min  i
for j  i+1 to n do
if X[j] < X[min] then
min  j
X[i]  X[min]
130

Analiza algoritmilor sortare prin selecie (2)


O alt variant a sortrii prin
selecie:

SELSORT2 (X)
for i  1 to n-1 do
for j  i+1 to n do
if X[j] < X[i] then
X[i]  X[j]

Complexitatea algoritmului este:

n(n 1)
C = (n 1) + (n 2) + ... + 1 =
= ( n 2 )
2
131

Analiza algoritmilor Bubblesort (1)


Se d un tablou X de n elemente. Algoritmul Bubblesort parcurge
repetat tabloul X interschimbnd dac e cazul elementele
consecutive:

BUBBLESORT1 (X)
n  X.size
for i  1 to n do
for j  1 to n-1 do
if X[j] > X[j+1] then
X[j]  X[j+1]

Complexitatea algoritmului este:

C = n(n 1) = (n 2 )
132

Analiza algoritmilor Bubblesort (2)


Elementul de pe ultima poziie a iteraiei curente poate fi exclus
din iteraia urmtoare:

BUBBLESORT2 (X)
n  X.size
for i  1 to n-1 do
for j  1 to n-i do
if X[j] > X[j+1] then
X[j]  X[j+1]

Complexitatea algoritmului este:

C = (n 1) + (n 2) + ... + 1 =

n( n 1)
= ( n 2 )
2
133

Analiza algoritmilor Bubblesort (3)


O alt variant n care elementul de pe prima poziie a iteraiei curente
poate fi exclus din iteraia urmtoare:

BUBBLESORT3 (X)
n  X.size
for i  1 to n-1 do
for j  n-1 downto i do
if X[j] > X[j+1] then
X[j]  X[j+1]

Complexitatea algoritmului este:

C = (n 1) + (n 2) + ... + 1 =

n(n 1)
= ( n 2 )
2
134

Analiza algoritmilor Bubblesort (4)


Algoritmul poate fi mbuntit reducnd numrul de iteraii de la n la cte sunt
necesare pn la obinerea tabloului sortat. i n acest caz elementul de pe ultima
poziie a iteraiei curente poate fi exclus din iteraia urmtoare:
BUBBLESORT4 (X)
sortat  false
n  X.size-1
while not sortat do
sortat  true
for i  1 to n do
if X[i] > X[i+1] then
X[i]  X[i+1]
sortat  false
nn-1
Complexitatea algoritmului n cazul cel mai favorabil (o singur parcurgere) este
(n) iar n cazul cel mai defavorabil rmne:

C = ( n 1) + ( n 2) + ... + 1 =

n(n 1)
= ( n 2 )
2
135

Analiza algoritmilor Quicksort (1)


Algoritmul de sortare rapid se bazeaz pe paradigma divide et impera. Tabloul
este rearanjat n dou subtablouri astfel nct fiecare element al primului
subtablou este mai mic sau egal cu orice element din al doilea subtablou. Cele
dou subtablouri sunt sortate prin apeluri recursive ale algoritmului de sortare
rapid.
QUICKSORT (X, primul, ultimul)
i  primul
j  ultimul
pivot  X[primul]
while i<j do
while X[i]<pivot do
i  i+1
while X[j]>pivot do
j  j-1
if i<j then
X[i]  X[j]
if ij then
i  i+1
j  j-1
if primul<j then QUICKSORT (X, primul, j)
if i<ultimul then QUICKSORT (X, i, ultimul)
136

Analiza algoritmilor Quicksort (2)


Analiza cazului cel mai defavorabil


Cazul cel mai defavorabil este acela n care toate


partiionrile sunt total dezechilibrate: un subtablou
de un element i unul de n-1 elemente. Astfel, cazul
cel mai defavorabil poate fi descris prin urmtoarea
recuren:
T ( n) = T (1) + T (n 1) + (n)
Unde (n) este timpul de partiionare. Deoarece
T(1)=(1), se ajunge la recurena
T (n) = T (n 1) + ( n)

Apoi, iternd recurena, obinem:


n
n(n + 1)
2
T (n) = (k ) = k =
= ( n )
2
k =1
k =1
n

137

Analiza algoritmilor Quicksort (3)


Analiza cazului cel mai favorabil


Atunci cnd partiiile sunt aproximativ egale se ajunge la


urmtoarea recuren:
n
T (n) = 2T + ( n)
2
Folosind teorema master avem a=2 (sortarea se continu pe
ambele partiii), b=2 (vectorul de sortat se njumtete) i
f(n)=(n) (timpul de partiionare). Astfel,

n log b a = n log 2 2 = n1 = n


Deci putem aplica cazul 2 al teoremei master. Prin urmare,


avem:

T (n) = (n logb a lg n) = (n log 2 2 lg n) = (n lg n)


138

Analiza algoritmilor Quicksort (4)


Analiza cazului mediu


Atunci cnd partiionrile echilibrate i dezechilibrate alterneaz,


combinarea unei partiionri defavorabile i a uneia favorabile produce
trei subvectori de dimensiuni 1, (n-1)/2 i (n-1)/2 cu un cost total:
n + n-1 = 2n-1 = (n)

Se poate observa c o partiionare defavorabil de un cost (n) poate


fi absorbit de o partiionare echilibrat de cost (n), i partiionarea
rezultat este favorabil.
Astfel, complexitatea medie este aceeai ca n cazul cel mai favorabil,
O(n lg n), doar constanta din notaia O este mai mare. Alternana
partiionrilor dezechilibrate cu cele echilibrate poate fi descris prin
recurena
n 1
n 1
T (n) = (n) + T (1) + T (n 1) = (n) + T (1) + (n) + T
+
T

2
2
unde T(1)=(1), iar (n)+(1)+(n)=(n), deci obinem recurena
n 1
T ( n) = 2T
+ ( n)
2
139

Analiza algoritmilor Quicksort (5)


Rezolvarea recurenei cazului mediu
Metoda master nu e aplicabil pentru recurena
n 1
T (n) = 2T
+ ( n)
2

Prin urmare, vom folosi metoda iteraiei:


n 1
T ( n) = 2T
+ ( n )
2

n 1

n 1
+ n 1 = 2 2 T n 2 3 + 21 n 1 1
2T
= 22T 2
2

2
2
2
2

n3

2
n 3
+ n 3 = 2 3 T n 7 + 2 2 n 3
2 2 T 2 = 2 2 2T 2
2
3
2
2

2
2
2
2

q 1
q
q 1
+ 1
+ 1
q 1 n 2
q n 2 + 1
q 1 n 2

=
+

2 T
2
T
2
q 1
q
q 1

2
2
2

140

Analiza algoritmilor Quicksort (6)


Considernd condiia la limit T(1)=(1), recurena se termin pentru

n 2q + 1
q +1
=
1

2
= n + 1 q + 1 = lg(n + 1) q = lg(n + 1) 1
q
2
Astfel, obinem:

T (n) = 2 lg( n +1) 1 T (1) +

lg( n +1) 1

k =1

T ( n) = 2

lg( n +1) 1

(1) +

k 1 n 2 k 1 + 1
2

k

lg( n +1) 1

( n)
k =1

T (n) = (n) + (lg(n + 1) 1) (n)

T (n) = (n + n lg(n + 1) n )
T (n) = (n lg n)

141

Analiza algoritmilor cutare i sortare


Aplicaii
1. S se rezolve recurena aferent cazului cel mai defavorabil al
algoritmului de cutare binar folosind metoda iteraiei.
2. S se determine complexitatea temporal a algoritmului de
sortare prin interclasare (Mergesort). Pseudocodul algoritmului
este prezentat pe pagina urmtoare.
3. S se rezolve recurena aferent cazului cel mai favorabil al
algoritmului Quicksort folosind metoda iteraiei.
4. S se implementeze algoritmii de sortare prezentai.
5. Comparai algoritmii de sortare, pe un tablou mare, msurnd
timpii de execuie.

142

Analiza algoritmilor mergesort


MERGE (X, primul, pivot, ultimul)
k  primul
i  primul
j  pivot+1;
while ipivot and jultimul do
if X[i]<X[j] then
T[k]  X[i]
k  k+1
i  i+1
else
T[k]  X[j]
k  k+1
j  j+1
if j>ultimul then
for j  i to pivot do
T[k]  X[j]
k  k+1
if i>pivot then
for i  j to ultimul do
T[k]  X[i]
k  k+1
for i  primul to ultimul do
X[i]  T[i]

MERGESORT (X, primul, ultimul)


if primul<ultimul then
pivot  (primul+ultimul)/2
MERGESORT (X, primul, pivot)
MERGESORT (X, pivot+1, ultimul)
MERGE (X, primul, pivot, ultimul)

143

Analiza algoritmilor tabele de dispersie (1)

Funcii de dispersie
Mapeaz o cheie k ntr-una din cele m locaii ale tabelei de dispersie


Metoda diviziunii
h( k ) = k mod m
Metoda nmulirii

h(k ) = m(kA mod 1) , 0 < A < 1




Dispersia universal
r

h(k ) = ai k i mod m,
i =0

unde cheia k s-a descompus n r+1 octei, astfel nct

k={k0, k1, ..., kr}, ki<m


a={a0, a1, ..., ar} valori alese aleator din mulimea {0, 1, ..., m-1}
144

Analiza algoritmilor tabele de dispersie (2)


Rezolvarea coliziunilor prin nlnuire


Elementele care se disperseaz n aceeai locaie se ncarc ntr-o list


nlnuit.
T
k1
k1
k2

K (chei)
k4

k2

k3

k3

k4

Locaia j conine un pointer ctre capul listei elementelor care se


disperseaz n locaia j, sau NULL dac nu exist astfel de elemente.
Operaia de cutare, n cazul cel mai defavorabil (cnd toate cele n
chei se disperseaz n aceeai locaie), este (n).
145

Analiza algoritmilor tabele de dispersie (3)


Rezolvarea coliziunilor prin adresare deschis



Toate elementele sunt memorate n interiorul tabelei de dispersie.


Locaia j conine elementul dispersat n locaia j sau NULL dac
nu exist un astfel de element.
Pentru inserare se examineaz succesiv tabela de dispersie,
ncepnd cu locaia indexat, pn la gsirea unei locaii libere.
Pentru cutarea unei chei se examineaz secvena de locaii
folosit de algoritmul de inserare. Cutarea se termin cu succes
dac se gsete cheia k sau fr succes dac se ntlnete o
locaie liber.
La tergerea unei chei nu poate fi marcat locaia ca fiind liber
pentru c ar face imposibil accesarea cheilor a cror inserare a
gsit aceast locaie ocupat. Prin urmare, locaia se marcheaz
cu o valoare special (TERS, -1, etc.). Evident c la inserare
locaiile marcate astfel se consider libere.
146

Analiza algoritmilor tabele de dispersie (4)


Verificarea liniar


Fiind dat o funcie de dispersie h, metoda verificrii liniare


folosete funcia de dispersie

h(k , i ) = (h(k ) + i ) mod m


pentru i=0, 1, ..., m-1.


n cazul accesrii tabelei de dispersie cu o cheie k, secvena


locaiilor examinate este:
T[h(k)], T[h(k)+1], ..., T[m-1], T[0], T[1], ..., T[h(k)-1].
Verificarea liniar poate genera grupri primare (iruri lungi de
locaii ocupate care tind s se lungeasc) crescnd timpul mediu
de cutare.

147

Analiza algoritmilor tabele de dispersie (5)


Verificarea ptratic


Fiind dat funcia de dispersie h, verificarea ptratic folosete


o funcie de dispersie de forma

h( k , i ) = h (k ) + c1i + c 2 i 2 mod m,

unde c1, c2 0 sunt constante auxiliare i i=0, 1, ..., m-1.




Locaia verificat iniial este T[h(k)], urmtoarele locaii


examinate depinznd ntr-o manier ptratic de i.
Dac dou chei au aceeai poziie de start a verificrii, atunci
secvenele locaiilor verificate coincid:

h(k1 ,0) = h(k 2 ,0) h(k1 , i) = h(k 2 , i )


Aceast situaie poate conduce la o form mai uoar de
grupare, numit grupare secundar.
148

Analiza algoritmilor tabele de dispersie (6)


Dispersia dubl


Se folosete o funcie de dispersie de forma:


h(k , i) = (h(k ) + i h(k ) ) mod m,

unde h i h sunt funcii de dispersie auxiliare




Spre deosebire de verificarea liniar sau ptratic, secvena


locaiilor examinate depinde prin dou funcii de dispersie de
cheia k.
n cazul dispersiei duble, cnd cheia variaz, poziia iniial a
verificrii h(k) i decalajul h(k) pot varia independent,
evitnd astfel gruprile primare i secundare.

149

Analiza algoritmilor tabele de dispersie (7)

Exerciii [Cor00]
1.

Se consider o tabel de dispersie de dimensiune m=1000 i


funcia de dispersie
5 1
h(k ) = m(kA mod 1) , A =
2
Calculai locaiile n care se pun cheile 61, 62, 63, 64 i 65.

2.

Se consider c se insereaz cheile 10, 22, 31, 4, 15, 28, 17,


88, 59 ntr-o tabel de dispersie cu m=11 locaii folosind
adresarea deschis cu funcia primar de dispersie h=k mod
m. Ilustrai rezultatul inserrii acestor chei folosind verificarea
liniar, verificarea ptratic cu c1=1 i c2=3 respectiv
dispersia dubl cu h (k)=1+(k mod (m -1)).

150

Analiza algoritmilor arbori binari (1)




Arborele este o particularizare a unei structuri de date mai generale,


graful, care va fi prezentat n capitolul urmtor.

Utilizarea unei structuri arborescente binare face posibil inserarea


i tergerea rapid, precum i cutarea eficient a datelor.

Dac orice nod din arbore poate avea cel mult doi fii, atunci arborele se
numete arbore binar.

Pe lng un cmp cheie i date adiionale, fiecare nod al arborelui binar


conine cmpurile st, dr i p referine spre nodurile corespunztoare
fiului stng, fiului drept i printelui.
ntr-un arbore binar de cutare cheile sunt ntotdeauna astfel
memorate nct ele satisfac urmtoarea proprietate:
Fie x un nod dintr-un arbore binar de cutare. Dac y este un nod din
subarborele stng al lui x, atunci y.cheiex.cheie. Dac y este un nod din
subarborele drept al lui x, atunci y.cheiex.cheie.

Exemplu:
6
3
2

7
5

151

Analiza algoritmilor arbori binari (2)


Implementarea clasei Node n Java
public class Node {
int key;
float data;
Node leftChild;
Node rightChild;
Node parent;

//cheia
//alte informatii
//fiul stang
//fiul drept
//parintele

public Node(int k){ //constructorul


key = k;
//initializarea cheii
}
}

152

Analiza algoritmilor arbori binari (3)


Inserarea const n inserarea nodului z pe poziia corespunztoare n
arborele binar de cutare cu rdcina r.
INSEREAZA (z)
y  NULL
xr
while xNULL do
yx
if z.cheie<x.cheie then
x  x.st
else
x  x.dr
z.p  y
if y=NULL then
rz
else if z.cheie<y.cheie then
y.st  z
else
y.dr  z

6
3
2

7
5

Inserarea nodului 4:

6
3
2

7
5

4
153

Analiza algoritmilor arbori binari (4)


Implementarea inserrii n Java
public class BinaryTree {
Node root = null;

//nodul radacina

public BinaryTree() {
insert(new Node(7));
insert(new Node(1));
insert(new Node(5));
}

//inserarea unui nod cu cheia 7


//inserarea unui nod cu cheia 1
//inserarea unui nod cu cheia 5

public void insert(Node z){


Node y = null;
Node x = root;
while(x!=null){
y=x;
if(z.key<x.key) x=x.leftChild;
else x=x.rightChild;
}
z.parent=y;
if(y==null) root=z;
else if(z.key<y.key) y.leftChild=z;
else y.rightChild=z;
}

//parintele nodului curent x


//nodul curent
//deplasarea in jos in arbore
//deplasarea in jos pe subarborele stang
//deplasarea in jos pe subarborele drept
//x==null, z este inserat pe aceasta pozitie null, cu y parinte
//daca parintele este null, z devine radacina arborelui
//setarea nodului z ca fiu stang al lui y
//setarea nodului z ca fiu drept al lui y

public static void main(String[] args) {


BinaryTree binaryTree1 = new BinaryTree();
}
}

154

Analiza algoritmilor arbori binari (5)




Traversarea arborelui n inordine viziteaz nodurile n ordinea cresctoare


a cheilor. Rdcina se viziteaz ntre nodurile din subarborele su stng i cele
din subarborele su drept. n exemplul anterior: 2, 3, 5, 6, 7, 8.
INORDINE (x)
if xNULL then
INORDINE (x.st)
AFIEAZ (x.cheie)
INORDINE (x.dr)

Traversarea arborelui n preordine viziteaz rdcina naintea nodurilor


din subarbori. n exemplul anterior: 6, 3, 2, 5, 7, 8.
PREORDINE (x)
if xNULL then
AFIEAZ (x.cheie)
PREORDINE (x.st)
PREORDINE (x.dr)

Traversarea arborelui n postordine viziteaz rdcina dup nodurile din


subarbori. n exemplul anterior: 2, 5, 3, 8, 7, 6.
POSTORDINE (x)
if xNULL then
POSTORDINE (x.st)
POSTORDINE (x.dr)
AFIEAZ (x.cheie)

155

Analiza algoritmilor arbori binari (6)


Cutarea unei chei



Cutarea returneaz nodul avnd cheia k dac exist sau NULL n caz contrar.
Cutarea recursiv
CAUTA_REC (x, k)
if x=NULL or k=x.cheie then
return x
if k<x.cheie then
return CAUTA_REC(x.st, k)
else
return CAUTA_REC(x.dr, k)
Cutarea iterativ (de obicei mai eficient dect varianta recursiv)
CAUTA_IT (x, k)
while xNULL and kx.cheie do
if k<x.cheie then
x  x.st
else
x  x.dr
return x
156

Analiza algoritmilor arbori binari (7)




Minimul determinarea nodului cu cheia minim dintr-un


arbore binar de cutare se realizeaz prin deplasare n jos pe
subarborele stng pn cnd se ajunge la un nod frunz.
MINIM (x)
while x.stNULL do
x  x.st
return x

6
3

7
5

Maximul este nodul cu cheia maxim i se determin prin


deplasare n jos pe subarborele drept pn cnd se ajunge la un
nod frunz.
MAXIM (x)
while x.drNULL do
x  x.dr
return x

6
3
2

7
5

8
157

Analiza algoritmilor arbori binari (8)


Succesorul unui nod x este nodul avnd cea mai mic cheie mai mare
dect cheia lui x, sau NULL, dac x are cea mai mare cheie din arbore.
Trebuie tratate dou alternative:


Dac x are subarbore drept, atunci succesorul lui x este nodul cu cheia
minim din acest subarbore. n exemplul anterior, succesorul lui 3 este 5.
Dac x nu are fiu drept, atunci succesorul lui x se determin traversnd
arborele de la x n sus pn cnd se ntlnete un nod care este fiu stng,
printele acelui nod fiind succesorul lui x. n exemplul anterior, succesorul
lui 5 este 6.

SUCCESOR (x)
if x.drNULL then
return MINIM (x.dr)
y  x.p
while yNULL and x=y.dr do
xy
y  y.p
return y

Succesorul lui 3 este 5


Succesorul lui 5 este 6

6
3
2

7
5

8
158

Analiza algoritmilor arbori binari (9)




tergerea unui nod z const n tratarea urmtoarelor trei


situaii:
Dac z nu are fii, se va modifica printele su pentru a-i nlocui fiul
z cu NULL.
Dac z are un fiu, z va fi eliminat prin setarea unei legturi de la
printele lui z la fiul lui z.
Dac z are doi fii, se va elimina din arbore succesorul y al lui z i
apoi se vor nlocui cheia i informaiile adiionale ale lui z cu cele
ale lui y.

Exemplu n care z are doi fii:


15

12
10

16

15

20
13

18

16

6
3
23

12
10

20
13

18

23

7
7

159

Analiza algoritmilor arbori binari (10)




Exemplu n care z are un singur fiu:


15
16

5
3

12

16

5
20

13

10

15

18

3
23

12

20
13

10

18

23

7
7

Exemplu n care z nu are fii:


15
16

5
3

12
10

15

20
13

18

16

5
3
23

12
10

20
13

18

23

6
7

160

Analiza algoritmilor arbori binari (11)


Algoritmul determin nodul y care se terge i reface legturile
(n al 3-lea caz chiar i cheia) nodurilor implicate
STERGE (z)
if z.st=NULL or z.dr=NULL then
yz
else
y  SUCCESOR (z)
if y.stNULL then
x  y.st
else
x  y.dr
if xNULL then
x.p  y.p
if y.p=NULL then
radacina  x
else if y=y.p.st then
y.p.st  x
else
y.p.dr  x
if yz then
z.cheie  y.cheie
return y
161

Analiza algoritmilor arbori binari (12)


Complexitatea operaiilor


Operaiile de baz pe arborii binari INSEREAZA, CAUTA, MINIM,


MAXIM, SUCCESOR i STERGE consum un timp proporional cu
nlimea arborelui.
Pentru un arbore binar relativ echilibrat cu n noduri, aceste operaii se
execut n cazul cel mai defavorabil ntr-un timp (lg n). n acest caz,
complexitatea temporal poate fi exprimat prin recurena

n
T ( n) = T + (1)
2
rezolvat deja pentru algoritmul de cutare binar.


Dac arborele binar este degenerat (ex. lan liniar de n noduri), atunci
timpul consumat n cazul cel mai defavorabil este (n).
Operaiile INORDINE, PREORDINE i POSTORDINE au nevoie de un
timp (n) pentru traversarea unui arbore binar de cutare cu n noduri.
162

Analiza algoritmilor arbori binari (13)


Aplicaii
1.

Fie secvena de valori: 4, 7, 2, 5, 3, 1, 6.


a) Reprezentai grafic arborele binar construit prin inserarea secvenei de valori de mai sus.
b) n ce ordine se afieaz valorile printr-o traversare n preordine? Dar printr-o traversare n
postordine?
c) Care este succesorul nodului cu cheia 4? Dar succesorul nodului cu cheia 6?
d) Reprezentai grafic arborele binar obinut dup tergerea nodului 4.

2.

S se completeze clasa BinaryTree prezentat cu traversarea arborelui binar de cutare n


inordine, preordine i postordine.

3.

S se implementeze n Java (n clasa BinaryTree) cutarea recursiv i cutarea iterativ a unei


chei n arborele binar.

4.

S se introduc n clasa BinaryTree metode pentru determinarea cheii minime i maxime n


arborele binar de cutare.

5.

S se implementeze n clasa BinaryTree o metod care s identifice succesorul unui nod n


arborele binar de cutare.

6.

S se implementeze n clasa BinaryTree algoritmul de tergere a unui nod din arborele binar de
cutare.

7.

S se modifice clasa Node i operaiile implementate n clasa BinaryTree astfel nct cheia s
fie numele studentului.

8.

S se rezolve prin metoda iteraiei recurena aferent operaiilor de baz (inserare, cutare,
minim, maxim, succesor i tergere) pe un arbore binar de cutare echilibrat cu n noduri.

163

Analiza algoritmilor heap-uri (1)




Heap-ul (movila) este un arbore binar complet (pn la ultimul nivel) cu


urmtoarea proprietate:


orice nod dintr-un heap minimizant trebuie s aib o cheie mai mic (sau egal)
dect oricare dintre fiii si.
orice nod dintr-un heap maximizant trebuie s aib o cheie mai mare (sau egal)
dect oricare dintre fiii si.

Reprezentarea heap-urilor se face prin tablouri. ntr-un tablou indexat de la 1, fiii


nodului k au indicii 2k i 2k+1, iar printele nodului k are indicele k/2. ntr-un
tablou indexat de la 0 (ca n Java), fiii nodului k au indicii 2k+1 i 2k+2, iar
printele nodului k are indicele (k-1)/2. Exemplu de heap minimizant:
5

34

27

42

53

49

5
6

5
34
27
42
53
49

Heap-ul permite selecia rapid a elementului cu cheie minim sau maxim (care
este chiar rdcina), operaie realizat n O(1).

Heap-ul binar este slab ordonat n raport cu arborele binar de cutare, de aceea,
traversarea nodurilor n ordine este dificil.

Pentru o structur heap A notm cu A.size dimensiunea total a tabloului


respectiv A.heapsize dimensiunea heap-ului.

164

Analiza algoritmilor heap-uri (2)


Inserarea unui nod


Const n dou operaii:



Adugarea nodului pe ultimul nivel, sau pe un nou nivel dac arborele este
complet. n cazul reprezentrii prin tablouri, noul element se adaug n prima
poziie disponibil.

Propagarea n sus (spre rdcin) a nodului inserat pn la ndeplinirea condiiei
de heap.
Exemplu de inserare a valorii 3 ntr-un heap minimizant
5

34

27

34

27

42

53

49

42

53

49

34

34

42

53

49

27

42

53

49

27

165

Analiza algoritmilor heap-uri (3)


Determinarea printelui sau fiilor nodului cu indicele i ntr-un heap reprezentat prin tablou.
PARINTE (i)
return i/2
STANGA (i)
return 2i
DREAPTA (i)
return 2i+1
Inserarea nodului z n heap-ul minimizant A:
INSEREAZA (A, z)
A.heapsize  A.heapsize+1
i  A.heapsize
while i>1 and A[PARINTE(i)]>z do
A[i]  A[PARINTE(i)]
i  PARINTE(i)
A[i]  z
166

Analiza algoritmilor heap-uri (4)


Extragerea rdcinii


Const n dou operaii:



Copierea ultimului nod n rdcin.

Propagarea n jos a rdcinii temporare pn la ndeplinirea condiiei de
heap (reconstituirea proprietii de heap). Propagarea se face spre fiul cu
cheia cea mai mic ntr-un heap minimizant respectiv spre fiul cu cheia
mai mare ntr-un heap maximizant.
Exemplu de extragere a rdcinii dintr-un heap minimizant

3
1

27
1

34
2
42
4

5
3
53
5

49
6

5
1

34

5
3

2
27
7

42
4

53
5

49
6

34

27
3

2
42
4

53
5

49
6

167

Analiza algoritmilor heap-uri (5)


La reconstituirea heap-ului se consider c subarborii care au ca rdcin
STANGA(i) respectiv DREAPTA (i) sunt heap-uri.
RECONSTITUIE (A, i)
s  STANGA(i)
d  DREAPTA(i)
if sA.heapsize and A[s]<A[i] then
min  s
else
min  i
if dA.heapsize and A[d]<A[min] then
min  d
if mini then
A[i]  A[min]
RECONSTITUIE (A, min)

EXTRAGE (A)
min  A[1]
A[1]  A[A.heapsize]
A.heapsize  A.heapsize-1
RECONSTITUIE (A, 1)
return min
168

Analiza algoritmilor heap-uri (6)


Construcia heap-urilor


Prin reconstituirea recursiv a proprietii de heap de la nodul n/2 n


jos nodurile n/2+1...n sunt frunze i ndeplinesc condiia de heap:
CONSTRUIESTE (A)
A.heapsize  A.size
for i  A.size/2 downto 1 do
RECONSTITUIE (A, i)

Prin inserare repetat n heap considernd c primul element al


tabloului formeaz deja un heap:
CONSTRUIESTE (A)
A.heapsize  1
for i  2 to A.size do
INSEREAZA (A, A[i])
169

Analiza algoritmilor heap-uri (7)


Heapsort
Algoritmul heapsort ncepe cu apelul procedurii CONSTRUIESTE
prin care transform vectorul de intrare A n heap. Sortarea se
face prin interschimbarea repetat a rdcinii cu ultimul element
din heap urmat de excluderea lui din heap. Sortarea este
descresctoare cu un heap minimizant respectiv cresctoare cu
heap maximizant.

HEAPSORT (A)
CONSTRUIESTE (A)
for i  A.size downto 2 do
A[1]  A[i]
A.heapsize  A.heapsize-1
RECONSTITUIE (A, 1)
170

Analiza algoritmilor heap-uri (8)


Complexitatea operaiilor n heap


Operaiile INSEREAZA, EXTRAGE i RECONSTITUIE sunt de complexitate O(lg n), la fel


ca operaiile ntr-un arbore binar de cutare (v. capitolul precedent).

Operaia de construire prin inserare repetat apeleaz de O(n) ori INSEREAZA de


complexitate O(lg n), deci, timpul total de execuie este O(n lg n).

n cazul operaiei de construire prin reconstituire recursiv se observ c nodurile de pe


ultimul nivel (aproximativ jumtate) ndeplinesc condiia de heap, deci nu sunt
propagate deloc. Nodurile de pe nivelul deasupra frunzelor (aproximativ un sfert) sunt
propagate cel mult un nivel. Nodul aflat n rdcin este propagat cel mult h-1 nivele,
(lg n rotunjit n jos). Astfel, numrul de propagri este
lg n n
lg n k
n
n
n
n
0 + 1 + 2 + ... + k +1 k = k +1 O(k ) = O n k +1
2
4
8
2
k =0 2
k =0 2

k
tim c pentru orice x subunitar k x =
k =0

(1 x )2

lg n

k
n
1
2
Astfel rezult c O n k +1 = O k = O
2
2
2
2

1
k
=
0

k =0 2

2
k

= O ( n)

Timpul de execuie al algoritmului heapsort este O(n lg n) deoarece CONSTRUIESTE se


execut n O(n) iar operaia RECONSTITUIE de O(lg n) este apelat de n-1 ori.
171

Analiza algoritmilor heap-uri (9)


Aplicaii
1. Ilustrai modul de funcionare al procedurii CONSTRUIESTE, prin reconstituire
heap minimizant, pentru vectorul A={5,3,17,10,84,19,6,22,9}.
2. Ilustrai modul de funcionare al procedurii CONSTRUIESTE, prin inserare n
heap minimizant, pentru vectorul A={5,3,17,10,84,19,6,22,9}.
3. Ilustrai modul de funcionare al procedurii CONSTRUIESTE, prin reconstituire
heap maximizant, pentru vectorul A={5,3,17,10,84,19,6,22,9}.
4. Ilustrai modul de funcionare al procedurii CONSTRUIESTE, prin inserare n
heap maximizant, pentru vectorul A={5,3,17,10,84,19,6,22,9}.
5. Ilustrai modul de funcionare al procedurii HEAPSORT pentru vectorul
A={5,3,17,10,84,19,6,22,9}.
6. S se implementeze n Java operaiile de construire, inserare, extragere i
reconstituire.
7. S se implementeze n Java algoritmul heapsort.
8. S se rescrie funcia RECONSTITUIE pentru un heap maximizant.
9. S se implementeze n Java algoritmul heapsort folosind un heap maximizant,
astfel nct sortarea s se fac n ordine cresctoare.
10. S se adapteze i s se reutilizeze clasa Node de la arbori binari (cu informaie
suplimentar nume student) pentru heap-uri.
172

Analiza algoritmilor grafuri (1)





Grafurile au o form determinat de o problem concret.


Nodurile grafului se numesc vrfuri i ele pot fi conectate prin muchii. Notm
un graf G=(V,E), unde V este mulimea vrfurilor i E este mulimea muchiilor.
Notm cu |V| numrul vrfurilor i cu |E| numrul muchiilor.

Fiecare vrf conine cmpurile i (index), c (color), d (distance/discovered), p


(predecessor), f (finalized).

Dou vrfuri se numesc adiacente dac sunt conectate direct printr-o muchie.

Un drum reprezint o secven de muchii.

Un graf se numete conex dac exist cel puin un drum ntre toate vrfurile.

Un graf n care muchiile nu au o direcie (deplasarea se poate face n orice sens)


se numete neorientat. Un graf n care muchiile au o singur direcie (marcat
prin sgeat) se numete orientat.
Un graf n care muchiile au asociate ponderi (costul drumurilor dintre vrfuri) se
numete ponderat.
Complexitatea unui algoritm pe un graf G=(V,E) se exprim n funcie de
dimensiunea intrrii descris prin doi parametri: numrul de vrfuri |V| i
numrul de muchii |E|. n cadrul notaiei asimptotice simbolul V nseamn |V|,
iar simbolul E nseamn |E|.
173

Analiza algoritmilor grafuri (2)


Podurile din Knigsberg
C
d

A
a

D
f

C
d

A
a

g
e

D
f

Unul dintre primii matematicieni care a


studiat grafurile a fost Leonhard Euler, n
secolul al XVIII-lea. El a rezolvat celebra
problem a podurilor din Knigsberg,
demonstrnd c nu exist un drum care s
cuprind toate cele apte poduri, fr a
traversa de dou ori acelai pod.
174

Analiza algoritmilor grafuri (3)


Implementarea clasei Vertex n Java
ntr-o implementare abstract vrfurile pot fi valori ntregi. n majoritatea aplicaiilor ns
pentru fiecare vrf trebuie pstrate mai multe informaii, ca n clasa Vertex de mai jos:
package graphs;
import java.awt.*;
public class Vertex {
Color color;
Vertex predecessor;
int distance;
int discovered; //for DFS
int finalized; //for DFS
char label;
int index;
int infinite = 100;
public Vertex(int i) {
index = i;
color = Color.white;
distance = infinite;
predecessor = null;
}
}

175

Analiza algoritmilor grafuri (4)


Reprezentarea grafurilor prin matrice de adiacen


Matricea de adiacen este un tablou bidimensional, n care elementele indic


prezena unei muchii ntre dou vrfuri. Dac graful are |V| vrfuri, numerotate
cu 1,2,...,|V| n mod arbitrar, matricea de adiacen este un tablou A=(aij) cu
|V|x|V| elemente, unde

1 dac (i, j ) E ,
aij =
0 altfel.


Matricea de adiacen poate fi folosit i pentru grafuri ponderate. n acest caz,


costul w(i,j) al unei muchii (i,j) E este memorat ca element din linia i i
coloana j a matricei de adiacen:

w(i, j ) dac (i, j ) E ,


aij =
0 altfel.


Avantajul const n verificarea rapid a adiacenelor. Dezavantajul const n


faptul c necesarul de memorie pentru matricea de adiacen a unui graf este
(V2) i nu depinde de numrul de muchii. Astfel, reprezentarea prin matrice de
adiacen este indicat n cazul grafurilor cu un numr relativ mic de vrfuri sau
atunci cnd graful este dens (|E| aproximativ egal cu |V|2).
176

Analiza algoritmilor grafuri (5)


Implementarea n Java a unui graf neponderat reprezentat prin matrice de adiacen
package graphs;
import java.awt.*;
import java.util.*;
public class Graph {
int maxVerts = 20;
int nVerts = 0;
ArrayList vertexList = new ArrayList();
int A[][] = new int[maxVerts][maxVerts];
public Graph() {
for(int i=0; i<maxVerts; i++)
for(int j=0; j<maxVerts; j++)
A[i][j] = 0;
}

public static void main(String[] args) {


Graph graph = new Graph();
graph.addVertex(); //0
graph.addVertex(); //1
graph.addVertex(); //2
graph.addVertex(); //3
graph.addEdge(0, 1);
graph.addEdge(1, 2);
graph.addEdge(0, 3);
}
}

public void addVertex(){


vertexList.add(new Vertex(nVerts++));
}
public void addEdge(int v1, int v2){
A[v1][v2] = 1;
A[v2][v1] = 1;
}

0
3
177

Analiza algoritmilor grafuri (6)


Reprezentarea grafurilor prin liste de adiacen


Se folosete un tablou A cu |V| liste, cte una pentru fiecare


vrf din V. Pentru fiecare i V, lista de adiacen A[i] conine
toate vrfurile j pentru care exist o muchie (i,j) E.
Dac graful este orientat, suma lungimilor tuturor listelor de
adiacen este |E|. Dac graful este neorientat, lungimea total
a listelor de adiacen este 2|E| deoarece, dac (i,j) este o
muchie, atunci i apare n lista de adiacen a lui j dar i j apare
n lista de adiacen a lui i.
Dac graful este ponderat, costul w(i,j) al muchiei (i,j) E este
memorat mpreun cu vrful j n lista de adiacen a lui i.
Avantajul const n necesarul de memorie O(max(V,E)).
Reprezentarea prin liste de adiacen este preferat pentru c
ofer un mod compact de reprezentare a grafurilor rare (cu |E|
mult mai mic dect |V|2). Dezavantajul const n faptul c
verificarea adiacenelor implic operaii de cutare n liste.
178

Analiza algoritmilor grafuri (7)


Reprezentarea grafurilor neponderate. Exemple
Graf neorientat

Listele de adiacen

2
3

Graf orientat







2
1
2
2
1







5
345
4
35
24

Listele de adiacen

3
5

1
2
3
4
5

1
2
3
4
5







25
34
4
5
2

Matricea de adiacen
1

Matricea de adiacen
1

179

Analiza algoritmilor grafuri (8)


Reprezentarea grafurilor ponderate. Exemple
Graf neorientat

1
15

12
17

Listele de adiacen

26

18
29

21

Graf orientat

1
15

12
17
21







2/12
1/12
2/26
2/18
1/15







5/15
3/26  4/18  5/17
4/29
3/29  5/21
2/17  4/21

Listele de adiacen

26

18
29

1
2
3
4
5

1
2
3
4
5







2/12  5/15
3/26  4/18
4/29
5/21
2/17

Matricea de adiacen
1

12

15

12

26

18

17

26

29

18

29

21

15

17

21

Matricea de adiacen
1

12

15

26

18

29

21

17

180

Analiza algoritmilor grafuri (9)


Parcurgerea grafurilor n lime (breadth-first search)





Parcurgerea n lime a unui graf G=(V,E) pornete de la un vrf surs


s i exploreaz sistematic graful descoperind toate vrfurile accesibile
din s. Algoritmul calculeaz distana de la s la toate aceste vrfuri
accesibile.
Parcurgerea n lime lrgete uniform frontiera dintre vrfurile
descoperite i cele nedescoperite. Astfel, algoritmul descoper toate
vrfurile aflate la distana k fa de s nainte de cele aflate la distana
k+1.
Acest algoritm este implementat cu ajutorul unei cozi Q.
Pentru a ine evidena avansrii, parcurgerea n lime coloreaz fiecare
vrf cu alb (nedescoperit), gri (descoperit, cu lista de adiacen n curs
de explorare) sau negru (descoperit, cu lista de adiacen explorat).
Algoritmul pstreaz pentru fiecare vrf v V culoarea n v.c,
predecesorul n v.p i distana de la sursa s n cmpul v.d.
Complexitatea algoritmului const n operaiile efectuate cu coada
(fiecare vrf este inserat i scos o singur dat) cu un cost O(V) i n
examinarea listelor de adiacen cu un cost O(E), astfel timpul total de
execuie este O(V+E).

181

Analiza algoritmilor grafuri (10)


BFS (G, s)
foreach u V do
u.c  ALB
u.d 
u.p  NULL
s.c  GRI
s.d  0
Q.INSERT (s)
while Q do
u  Q.HEAD
PRINT (u.i)
foreach v A[u] do
if v.c=ALB then
v.c  GRI
v.d  u.d+1
v.p  u
Q.INSERT (v)
Q.DELETE (Q.HEAD)
u.c  NEGRU

182

Analiza algoritmilor grafuri (11)


Implementarea n Java a parcurgerii grafurilor n lime
public void BFS(int s){
LinkedList queue = new LinkedList();
((Vertex)vertexList.get(s)).color = Color.gray;
((Vertex)vertexList.get(s)).distance = 0;
queue.addFirst(vertexList.get(s));
while(!queue.isEmpty()){
Vertex u = (Vertex)queue.getLast();
System.out.println(u.index);
for(int v=0; v<nVerts; v++)
if(A[v][u.index]==1 && ((Vertex)vertexList.get(v)).color==Color.white){
((Vertex)vertexList.get(v)).color = Color.gray;
((Vertex)vertexList.get(v)).distance = u.distance+1;
((Vertex)vertexList.get(v)).predecessor = u;
queue.addFirst(vertexList.get(v));
}
queue.removeLast();
u.color = Color.black;
}
}
183

Analiza algoritmilor grafuri (12)


Parcurgerea grafurilor n adncime (depth-first search)


Algoritmul exploreaz n adncime subgraful succesor al celui mai recent


descoperit vrf v dintr-un graf G=(V,E). Cnd toate muchiile care pleac din v
au fost explorate, algoritmul revine pentru explorarea urmtoarelor muchii care
pleac din predecesorul lui v.
Parcurgerea n adncime se implementeaz cu ajutorul stivei, fiind astfel natural
o abordare recursiv.
Pentru a ine evidena avansrii, parcurgerea n adncime coloreaz fiecare vrf
v V cu alb (nedescoperit), gri (descoperit, cu zona de graf accesibil din v n
curs de explorare) sau negru (descoperit, cu zona de graf accesibil din v
explorat).
Algoritmul pstreaz pentru fiecare vrf v V culoarea n v.c i predecesorul n
v.p. De asemenea, algoritmul folosete un ceas t al parcurgerii care crete
atunci cnd un nod i schimb culoarea. Algoritmul creeaz marcaje de timp
pentru fiecare vrf v V: momentul cnd v este descoperit (devine gri) este
pstrat n v.d, iar momentul n care explorarea zonei grafului accesibil din v a
fost finalizat este pstrat n v.f.

Marcajele de timp precum i predecesorii se pot folosi pentru o serie extins de


prelucrri.

Complexitatea algoritmului const n explorarea vrfurilor (V) i n examinarea


listelor de adiacen (E), astfel timpul total de execuie este (V+E).
184

Analiza algoritmilor grafuri (13)


DFS (G)
foreach u V do
u.c  ALB
u.p  NULL
t0
foreach u V do
if u.c=ALB then
EXPLORARE (u)

EXPLORARE (u)
u.c  GRI
PRINT (u.i)
u.d  t  t+1
foreach v A[u] do
if v.c=ALB then
v.p  u
EXPLORARE (v)
u.c  NEGRU
u.f  t  t+1

185

Analiza algoritmilor grafuri (14)


Drumuri minime. Algoritmul Dijkstra


Algoritmul de cutare n lime determin drumurile minime n grafuri


neponderate. Algoritmul Dijkstra permite determinarea drumurilor
minime de la vrful surs s ctre toate vrfurile unui graf ponderat cu
costuri nenegative. Astfel, vom presupune c w(u,v)0 pentru fiecare
muchie (u,v) E.
Pentru fiecare vrf v V algoritmul pstreaz n v.d estimarea drumului
minim fa de s, iar n v.p pstreaz predecesorul. Algoritmul folosete
o coad de prioriti Q iniializat cu V (conine toate vrfurile grafului).
La fiecare iteraie while, se extrage din Q vrful u cu drumul minim.
Pentru fiecare vrf v adiacent cu u se reactualizeaz v.d i v.p n cazul
n care drumul minim ctre v poate fi ameliorat dac trece prin u
(operaie de relaxare a muchiilor).
Complexitatea algoritmului const n extragerea minimului (operaie
O(V) efectuat de |V| ori) cu un cost O(V2) i n examinarea listelor de
adiacen (fiecare muchie este examinat o singur dat) cu un cost
O(E), astfel timpul total de execuie este O(V2+E)=O(V2).
186

Analiza algoritmilor grafuri (15)


DIJKSTRA (G, w, s)
foreach u V do
u.d 
u.p  NULL
s.d  0
QV
while Q do
u  MIN (Q, d)
Q  Q-{u}
foreach v A[u] do
if v.d>u.d+w(u,v) then
v.d  u.d+w(u,v)
v.p  u
187

Analiza algoritmilor grafuri (16)


Cutare n spaiul strilor: algoritmul A*
A* (G, w, s, t)
foreach u V do
u.d 
u.h 
u.f 
u.p  NULL
s.d  0
s.h  H (s, t)
s.f  s.h
Q  {s}
C
while Q do
u  MIN (Q, f)
if u=t then return true
Q  Q - {u}
C  C U {u}
foreach v A[u] do
if v C then continue
if v Q then Q  Q U {v}
if v.d>u.d+w(u,v) then
v.d  u.d+w(u,v)
v.h  H(v, t)
v.f  v.d+v.h
v.p  u
return false

s=surs, t=int/target

H=heuristic
Q=openset
C=closedset

188

Analiza algoritmilor grafuri (17)


Aplicaii
1.

S se modifice clasa Graph, inclusiv metoda BFS,


astfel nct grafurile s fie reprezentate prin liste
de adiacen n loc de matrice de adiacen.

2.

S se implementeze n clasa Graph algoritmul de


parcurgere a grafurilor n adncime.

3.

S se implementeze n clasa Graph algoritmul


Dijkstra care s afieze drumurile minime ntr-un
graf ponderat. Ponderile notate cu w(u,v) pot fi
pstrate n matricea de adiacen A(u,v)
pentru asta e necesar adugarea unei noi
metode addEdge n clasa Graph.
189

Partea III
Proiectarea algoritmilor

Proiectarea algoritmilor divide et impera (1)




Divide et impera este o metod de construire a algoritmilor.


Rezolvarea unei probleme prin aceast metod const n:





mprirea problemei n dou sau mai multe subprobleme de dimensiune


mai mic.
rezolvarea subproblemelor.
combinarea rezultatelor pentru obinerea soluiei problemei iniiale.

Divizarea problemei se poate face recursiv pn cnd subproblemele


devin elementare i pot fi rezolvate direct.

Forma general a algoritmului de rezolvare a problemei P de


dimensiune n cu soluia S:
DIVIZARE (P, n, S)
if nn0 then
SOLUTIE (P, n, S)
else
SEPARARE (P, n) n (P1, n1), ..., (Pk, nk)
DIVIZARE (P1, n1, S1)
...
DIVIZARE (Pk, nk, Sk)
COMBINARE (S1, ..., Sk) n S

191

Proiectarea algoritmilor divide et impera (2)


Turnurile din Hanoi


Problema turnurilor din Hanoi a fost introdus n 1883 de


matematicianul francez douard Lucas. Problema are la baz o
legend hindus conform creia zeul Brahma a aezat n templul
din Benares o stiv de 64 de discuri din aur cu diametre diferite,
aezate n ordinea descresctoare a diametrelor. Clugrii
templului au sarcina de a muta toate discurile pe o alt tij
astfel nct:


La un moment dat doar un disc, aflat n vrful unei tije, poate fi


mutat pe o alt tij;
Nu este permis aezarea unui disc de dimensiune mai mare peste
un disc de dimensiune mai mic.

Conform legendei, lumea se va sfri atunci cnd clugrii i


vor termina treaba.

192

Proiectarea algoritmilor divide et impera (3)


Algoritmul HANOI

Algoritmul mut n discuri de pe tija A pe tija C folosind tija B.


Pentru asta, trebuie mutate n-1 discuri de pe A pe B prin C,
ultimul disc de pe A pe C i apoi n-1 discuri de pe B pe C prin A.
HANOI (n, A, C, B)
if n1 then
HANOI (n-1, A, B, C)
PRINT (A  C)
HANOI (n-1, B, C, A)
193

Proiectarea algoritmilor divide et impera (4)

Exemplu (n=2)
A

AB
A

AC

BC

194

Proiectarea algoritmilor divide et impera (5)


Complexitatea algoritmului HANOI
Numrul de mutri poate fi descris prin recurena
T (n) = T ( n 1) + 1 + T (n 1) = 2T ( n 1) + 1

Aplicm metoda iteraiei:


T (n) = 21 T ( n 1) + 2 0

2T (n 1) = 2 (2T ( n 2) + 1) = 2 2 T ( n 2) + 21

2 2 T ( n 2) = 2 2 (2T (n 3) + 1) = 2 3 T ( n 3) + 2 2

2 q 1 T (n q + 1) = 2 q T (n q ) + 2 q 1

Considernd condiia la limit T(0)=0, recurena se termin


pentru
nq =0 q = n
195

Proiectarea algoritmilor divide et impera (6)


Am artat c la limit T(0)=0, q=n. Obinem
n 1

T ( n ) = 2 T ( 0) + 2 k
n

k =0

n 1

n 1

T ( n) = 2 0 + 2 = 2 k
n

k =0

k =0

tim c
x n +1 1
x =

x 1
k =0
n

Rezult astfel c
2n 1
T ( n) =
= 2n 1
2 1

Complexitatea algoritmului este O(2n), deci clugrii mai au


mult de lucru...
196

Proiectarea algoritmilor divide et impera (7)

Aplicaii
1.

Care din algoritmii prezentai anterior au la baz metoda


divide et impera?

2.

S se implementeze n Java algoritmul de rezolvare a


problemei turnurilor din Hanoi.

3.

Se d un tablou de valori ntregi. S se determine cel mai


mare divizor comun al valorilor din tablou prin metoda divide
et impera. Este evident c putem calcula separat cel mai
mare divizor comun pentru cele dou jumti ale tabloului,
iar soluia este cel mai mare divizor comun al celor dou.
Procesul de divizare continu pn cnd se ajunge la
subtablouri de un element.
197

Proiectarea algoritmilor greedy (1)


Algoritmii greedy aleg la fiecare moment cel mai bun candidat
posibil. Metoda greedy face optimizri locale, cu sperana c
acestea vor conduce la un optim global. Aceti algoritmi sunt de
obicei rapizi i furnizeaz o soluie relativ bun, dar nu
ntotdeauna cea mai bun. Forma general a unui algoritm
greedy:

GREEDY (C)
S
while C do
x  BEST (C)
C  C-{x}
if FEASIBLE (S U {x}) then
S  S U {x}
198

Proiectarea algoritmilor greedy (2)


Problema fracionar a rucsacului

Se consider c dispunem de un rucsac cu o anumit


capacitate G (greutate maxim) i de n obiecte, definite prin
greutate g i pre p. S se umple rucsacul cu obiecte, astfel
nct valoarea total s fie maxim. Pot fi introduse i
fraciuni din obiecte.
199

Proiectarea algoritmilor greedy (3)




Algoritmul greedy pentru rezolvarea problemei fracionare a


rucsacului const n urmtorii pai:
1. v[i]  p[i]/g[i], i = 1, n ;
2. sorteaz vectorii v, p, g n ordinea descresctoare a valorilor din v;
3. caut k astfel nct
k +1

g
i =1

G < gj
j =1

g i , pentru i = 1, k

k
soluia fiind
G g i , pentru k + 1
i =1

Timpul de execuie al algoritmului este O(n lg n), deoarece sortarea


se execut n O(n lg n), iar complexitatea operaiei de cutare din
pasul 3 este O(n).
200

Proiectarea algoritmilor greedy (4)


Coduri Huffman


Codificarea Huffman este o tehnic foarte util pentru compactarea datelor.


Algoritmul greedy propus de David Albert Huffman ofer o modalitate optim de
reprezentare a caracterelor prin coduri binare unice.
Fie un fiier cu 100 de caractere care conine doar literele a-f, cu urmtoarele
frecvene:
Caracter

Frecven

45

13

12

16

Cod cu lungime fix

000

001

010

011

100

101

Cod cu lungime variabil

101

100

111

1101

1100

Dac folosim un cod binar de lungime fix, avem nevoie de trei bii pentru a
reprezenta ase caractere (a=000, b=001, ..., f=101). Aceast metod necesit
300 de bii pentru codificarea celor 100 de caractere din fiier.
O codificare cu lungime variabil, care atribuie coduri scurte caracterelor frecvente
i coduri lungi caracterelor cu frecven redus, poate codifica fiierul prin 224 de
bii (45x1+13x3+12x3+16x3+9x4+5x4), economisind 25% din spaiu.
O codificare optim pentru un fiier este reprezentat printr-un arbore binar
complet.
201

Proiectarea algoritmilor greedy (5)


Decodificarea


Codurile i lungimile acestora se genereaz de algoritm astfel


nct distincia simbolurilor este asigurat.

n exemplul anterior







a=0
b = 101
c = 100
d = 111
e = 1101
f = 1100

Astfel, dac un cod ncepe cu 0 e format dintr-un singur bit i


este a. Dac ncepe cu 1, sigur e format din cel puin trei bii,
iar dac primii trei bii sunt 110 nseamn c exist i un al
patrulea bit, etc.
De exemplu, decodificnd pas cu pas secvena binar
1000110011010, vei obine cuvntul cafea.
202

Proiectarea algoritmilor greedy (6)


Construcia unui cod Huffman


Algoritmul Huffman pornete de la |C| frunze, fiecare


reprezentnd cte un caracter c C cu o frecven dat f[c].

Se realizeaz |C-1| operaii de fuzionare, pn la obinerea


arborelui final.

La fiecare pas, se aleg doi arbori (iniial frunze) cu frecvena cea


mai redus i se nlocuiesc cu arborele obinut prin fuzionarea
lor. Frecvena noului arbore este suma frecvenelor celor doi
arbori care au fuzionat.
Prin fuzionarea a doi arbori A1 i A2 se obine un nou arbore
binar, n care arborii A1 i A2 sunt fii stng respectiv drept al
rdcinii.
n arborele final frunzele sunt caracterele i interpretm codul
binar pentru un caracter ca fiind drumul de la rdacin pn la
frunza corespunztoare, unde o deplasare pe fiul stng este
reprezentat prin 0, iar o deplasare pe fiul drept prin 1.
203

Proiectarea algoritmilor greedy (7)


Construcia unui cod Huffman
f:5

e:9

c:12

b:13

d:16

a:45

c:12

b:13

d:16

0
f:5

0
c:12

e:9

a:45

25

25

b:13

a:45

30
0

1
b:13

e:9

55

1
d:16

14
0
f:5

25
0
c:12

d:16

100

55
0

14
0
f:5

a:45

a:45

30
1
b:13

0
c:12

a:45

1
e:9

0
f:5

14

d:16

14

1
e:9

25
0
c:12

30
0

1
b:13

1
d:16

14
0
f:5

1
e:9

204

Proiectarea algoritmilor greedy (8)


Algoritmul lui Huffman
HUFFMAN (C)
n  |C|
QC
for i  1 to n-1 do
z  CREATENODE ()
x  z.st  MIN (Q)
Q  Q-{x}
y  z.dr  MIN (Q)
Q  Q-{y}
z.cheie  x.cheie + y.cheie
Q.INSERT (z)
return MIN (Q)

205

Proiectarea algoritmilor greedy (9)


Complexitatea algoritmului Huffman


Presupunem implementarea structurii Q sub


forma unui heap binar.
Astfel, construirea lui Q prin reconstituire
heap, poate fi realizat n O(n).
Bucla for are n-1 iteraii n care apeleaz
operaii heap de complexitate O(lg n).
Rezult un timp total de execuie, pe o
mulime de n caractere, de O(n lg n).
206

Proiectarea algoritmilor greedy (10)


Aplicaii
1.

S se ilustreze construcia arborelui Huffman pentru


urmtoarele caractere i frecvene:
C={p:100, q:17, r:2, x:58, y:80, z:5}
Decodificai apoi secvena binar 1111011001.

2.

Stabilii o codificare Huffman pentru urmtoarea secven de


frecvene format din primele numere ale irului Fibonacci:
C={a:1, b:1, c:2, d:3, e:5, f:8, g:13, h:21}

3.

Desenai arborele Huffman pentru cuvntul ABRACADABRA.

4.

Care din algoritmii prezentai anterior au la baz strategia


greedy?

5.

Implementai n Java algoritmul Huffman.

6.

Implementai n Java problema fracionar a rucsacului.


207

Proiectarea algoritmilor programare dinamic (1)




Conceptul de programare dinamic a fost introdus n


1957 de matematicianul american Richard Bellman.
Programarea dinamic, asemenea metodei divide et
impera, rezolv probleme combinnd soluiile unor
subprobleme.
Programarea dinamic este aplicabil atunci cnd
subproblemele au n comun sub-subprobleme.
Spre deosebire de metoda divide et impera, un
algoritm bazat pe programare dinamic rezolv
fiecare sub-subproblem o singur dat, memoreaz
soluia, evitnd astfel recalcularea.
208

Proiectarea algoritmilor programare dinamic (2)


Un prim exemplu: irul lui Fibonacci


irul lui Fibonacci este definit astfel:


0, n = 0

F (n) = 1, n = 1
F (n 1) + F (n 2), n > 1

Arborele recursiv pentru calculul F(5) este urmtorul:


F(5)
F(4)
F(3)
F(2)
F(1)

F(1)

F(3)
F(2)

F(1)

F(2)

F(0) F(1)

F(1)
F(0)

F(0)

n cazul implementrii recursive, termenii sunt determinai de mai multe ori: F(2)
de trei ori i F(3) de dou ori, pentru calculul F(5). Astfel, varianta recursiv are
complexitate exponenial: O(2n).
Varianta iterativ memoreaz tot timpul rezultatele, deci are la baz programarea
dinamic. Calculnd o singur dat termenii, complexitatea este liniar: O(n).

209

Proiectarea algoritmilor programare dinamic (3)


Cel mai lung subir cresctor


Fie A un ir de n numere ntregi. Se cere


determinarea subirului cresctor de lungime
maxim, nu neaprat contiguu, n irul A.
Pentru rezolvarea problemei construim vectorii:


L[i] = lungimea subirului cresctor care ncepe pe poziia i


i are ca prim element A[i].
S[i] = k, succesorul elementului A[i] n subirul cresctor, cu
L[k]=max{L[j]| j>i i A[j]>A[i]}, iar S[i]=-1 dac nu exist
un astfel de succesor.

Cel mai lung subir cresctor va ncepe pe acea


poziie i n A pentru care L[i] este maxim, iar afiarea
se poate face cu ajutorul vectorului S.
210

Proiectarea algoritmilor programare dinamic (4)


Algoritmul de determinare a subirului cresctor maximal
CMLSC (A)
imax  n
for i  n downto 1 do
S[i]  -1
L[i]  1
for j  i+1 to n do
if A[j]>A[i] and L[j]+1>L[i] then
L[i]  L[j]+1
S[i]  j
if L[i]>L[imax] then
imax  i
i  imax
while i-1 do
PRINT (A[i])
i  S[i]
211

Proiectarea algoritmilor programare dinamic (5)

Exemplu:


Fie irul de ntregi:


A=3, 5, 76, 1, 45, 2, 68, 52, 90, 0, 4, 15
Aplicnd algoritmul CMLSC, obinem
1

10

76 1

45 2

68 52 90 0

15

-1 11 12 -1

11

12

Astfel, cel mai lung subir cresctor este:


3, 5, 45, 68, 90
212

Proiectarea algoritmilor programare dinamic (6)

Complexitatea algoritmului CMLSC




Operaiile din bucla for exterioar, de cost c1, sunt


apelate de n ori.
Numrul de apeluri ale operaiilor din bucla for interioar,
de cost c2, este
n 1
n(n 1)
1 + 2 + ... + n 1 = k =
2
k =1
Operaiile din bucla while, de cost c3, sunt executate de
cel mult n ori.
Astfel, complexitatea algoritmului este

c1 n + c 2

n( n 1)
+ c3 n = an 2 + bn + c = O (n 2 )
2
213

Proiectarea algoritmilor programare dinamic (7)


Aplicaii propuse
1.

Se consider un triunghi de numere, reprezentat ntr-o matrice A, ca


n exemplul de mai jos:
10
82

81

10

14

35

41

52

26

15

32

90

11

87

56

23

54

65

89

32

71

31

i o bil care cade n jos sau spre dreapta-jos. S se determine


drumul prin care bila ar strnge numrul maxim de puncte. Se va
folosi o matrice P de predecesori (-1=nu exist, 1=pas n jos, 0=pas
spre dreapta-jos) i o matrice S pentru sumele maxime.
2.

Se dau poziiile de start i de final respectiv dimensiunea tablei de


ah. Se cere determinarea celui mai scurt drum al unui cal ntre cele
dou poziii. Se va folosi o matrice L care s pstreze lungimea
minim din fiecare poziie a tablei de ah i un tablou P de
predecesori.

214

Proiectarea algoritmilor backtracking (1)




Backtracking este o metod de cutare sistematic cu ncercri repetate i


reveniri n caz de nereuit.
Soluia este construit n mod progresiv, prin adugarea cte unei componente
Sk+1 la o soluie parial (S1,S2,...,Sk) care reprezint o selecie din primele k
oferte din totalul celor n, astfel nct (S1,S2,...Sk,Sk+1) formeaz o nou soluie
parial.
Soluia final se obine n momentul n care selecia cuprinde toate cele n oferte,
deci k=n.
Metoda backtracking este n general ineficient, avnd complexitate
exponenial. De aceea, se folosete doar atunci cnd nu exist metode mai
eficiente de rezolvare a problemei.
Forma general a algoritmului backtracking recursiv:
BACKTRACKING (k)
for i  1 to n do
if ACCEPT (k, i) then
S[k]  i
if FINAL(k) then
return S
else BACKTRACKING (k+1)
215

Proiectarea algoritmilor backtracking (2)


Problema celor n regine


Fie o tabl de ah de dimensiune n x n. Determinai toate


posibilitile de a amplasa n regine pe aceast tabl, astfel nct
ele s nu se atace reciproc. Dou regine se atac reciproc dac se
afl pe aceeai linie, coloan sau diagonal.
Prima observaie este c pe fiecare linie poate fi amplasat o
singur regin. Astfel, pentru o tabl de ah de dimensiune n x n,
problema celor n regine poate fi reprezentat printr-un tablou de n
elemente, unde S[k]=i semnific o regin amplasat pe poziia
(k,i) a tablei de ah.

Condiia ca dou regine i i j s nu fie pe aceeai coloan este


S[i]S[j].

Condiia ca dou regine i i j s nu fie pe aceeai diagonal este


|j-i||S[j]-S[i]|.

Pentru n=2 i 3 nu exist soluii, pentru n=4 sunt dou soluii, etc.
216

Proiectarea algoritmilor backtracking (3)


QUEENS (k)
for i  1 to n do
if ACCEPT(k, i) then
S[k]  i
if k=n then
PRINT (S)
else QUEENS (k+1)

ACCEPT (k, i)
for j  1 to k-1 do
if S[j]=i then
return FALSE
if ABS(j-k)=ABS(S[j]-i) then
return FALSE
return TRUE
217

Proiectarea algoritmilor backtracking (4)


Aplicaii propuse
1.

S se implementeze n Java algoritmul prezentat


pentru rezolvarea problemei celor n regine.

2.

Fie o tabl de ah de dimensiune n x n. Determinai


toate posibilitile de a amplasa n ture pe aceast
tabl, astfel nct ele s nu se atace reciproc. Dou
ture se atac reciproc dac se afl pe aceeai linie
sau coloan.

3.

Fie o tabl de ah de dimensiune n x n i poziia de


start a calului. S se determine toate drumurile
calului care s acopere toat tabla de ah i s
treac o singur dat prin toate poziiile.
218

Proiectarea algoritmilor algoritmi genetici (1)




Un algoritm genetic este o procedur iterativ de cutare global.

Algoritmul proceseaz o populaie de soluii poteniale (cromozomi) distribuite


peste ntreg spaiul de cutare.

Pentru rezolvarea unei probleme folosind un algoritm genetic este necesar


definirea unei funcii F care s evalueze performana fiecrui cromozom.

n fiecare iteraie se creeaz o nou populaie P, numit generaie. Toate


generaiile au acelai numr de indivizi. n general, noua generaie const din
indivizi mai performani.

Evoluia spre optimul global este asigurat prin recombinarea (ncruciarea) i


modificarea (mutaia) cromozomilor.

Condiia de oprire se refer, de regul, la atingerea unui anumit numr de


generaii ng.

Forma general a algoritmului genetic fundamental:


P1  RANDOM()
for t  1 to ng do
EVALUARE (Pt)
P = SELECTIE (Pt)
P  RECOMBINARE (P)
Pt+1  MODIFICARE (P)
219

Proiectarea algoritmilor algoritmi genetici (2)




Evaluarea populaiei de cromozomi

vi = F (ci ), i = 1, nc


Selecia


Se calculeaz suma valorilor obinute n urma evalurii


nc

S = vi
i =1

Se determin probabilitile cumulative de selecie


j

pj =
i =1

vi
,
S

j = 1, nc ,

p nc = 1

Pentru selecia noii populaii se genereaz aleator nc valori


subunitare. Fiecare valoare ri generat aleator va selecta acel
cromozom ck pentru care ri [pk, pk+1].

Recombinarea a doi cromozomi const n interschimbarea unor


gene (bii).

Modificarea unui cromozom const n inversarea unor gene (bii).


220

Proiectarea algoritmilor algoritmi genetici (3)


Determinarea maximului unei funcii


Se va determina maximul unei funcii F(x), definit n exemplul nostru SIN(x).


Maximul se caut n intervalul [li, ls], deci x[li, ls].

Funcia X(v) normalizeaz valoarea v, aducnd-o n intervalul [li, ls].

Funciile GETBIT(v, i), SETBIT(v, i) i RESETBIT(v, i) preiau, seteaz respectiv


reseteaz bitul de pe poziia i din v.

Funcia INCRUCISARE(C, p1, p2) recombin biii cromozomilor p1 i p2.

Funcia MUTATIE(C, p) modific cromozomul p.

Funcia INITIALIZARE iniializeaz populaia de cromozomi cu valori generate aleator.

Funcia SELECTIE evalueaz populaia de cromozomi i genereaz o populaie nou


pstrnd doar cromozomii performani.

Funcia RECOMBINARE realizeaz o selecie n vederea ncrucirii.

Funcia MODIFICARE realizeaz operaia de mutaie a populaiei de cromozomi.

Funcia MAX reprezint algoritmul genetic n sine, care determin maximul funciei
F(x), cu x[li, ls]. Funcia folosete o populaie C de nc cromozomi. Cutarea se
termin dup ng=50 de generaii.
221

Proiectarea algoritmilor algoritmi genetici (4)


li  0
ls  2
nc  500
ng  50
pincrucisare  0.3
pmutatie  0.1
X (v)
return li+v/65535*(ls-li)
F (x)
return SIN (x)
GETBIT (v, i)
return v>>i&1
SETBIT (v, i)
return v|(1<<i)
RESETBIT (v, i)
return v&~(1<<i)
222

Proiectarea algoritmilor algoritmi genetici (5)


INCRUCISARE (C, p1, p2)
v1  C[p1]
v2  C[p2]
r  RANDOM (0, 16)
for j  r to 16 do
if GETBIT(v2, j)=1 then
SETBIT(C[p1], j)
else RESETBIT(C[p1], j)
if GETBIT(v1, j)=1 then
SETBIT(C[p2], j)
else RESETBIT(C[p2], j)

MUTATIE (C, p)
cp  C[p]
for j  1 to 16 do
if pmutatie>RANDOM(0, 1) then
if GETBIT(cp, j)=1 then
RESETBIT(cp, j)
else SETBIT(cp, j)
if F(X(cp))>F(X(C[p])) then
C[p]  cp
223

Proiectarea algoritmilor algoritmi genetici (6)


INITIALIZARE (C)
for i  1 to nc do
C[i]  RANDOM(0, 65536)
xmax  X(C[1])
fmax  F(xmax)
SELECTIE (C)
s0
for i  1 to nc do
V[i]  F(X(C[i]))
s  s+V[i]
P[1]  V[1]/s
for i  2 to nc do
P[i]  P[i-1]+V[i]/s
for i  1 to nc do
r  RANDOM(0, 1)
for j  1 to nc do
if r>P[j] and rP[j+1] then
C[i]  C[j]
for i  1 to nc do
C[i]  C[i]

224

Proiectarea algoritmilor algoritmi genetici (7)


RECOMBINARE (C)
primul  TRUE
for i  1 to nc do
if RANDOM(0, 1)<pincrucisare then
if primul then
primul  FALSE
p1  i
else
primul  TRUE
p2  i
INCRUCISARE (C, p1, p2)

MODIFICARE (C)
for i  1 to nc do
MUTATIE (C, i)
225

Proiectarea algoritmilor algoritmi genetici (8)


MAX (ng)
INITIALIZARE (C)
for t  1 to ng do
SELECTIE (C)
RECOMBINARE (C)
MODIFICARE (C)
maxiteri  1
maxiterf  F(X(C[1]))
for i  2 to nc do
if F(X(C[i]))>maxiterf then
maxiteri  i
maxiterf  F(X(C[i]))
if maxiterf>fmax then
fmax  maxiterf
xmax  X(C[maxiteri])
PRINT (xmax, fmax)
226

Proiectarea algoritmilor algoritmi genetici (9)


Aplicaii propuse
1.

S se implementeze n Java algoritmul genetic prezentat.

2.

S se modifice algoritmul genetic prezentat astfel nct s


determine minimul unei funcii. S se implementeze
algoritmul modificat n Java.

3.

S se implementeze un algoritm genetic pentru rezolvarea


problemei comis-voiajorului (traveling salesman problem). Se
consider n orae i se cunosc distanele dintre oricare dou
orae. Un comis-voiajor trebuie s treac prin toate cele n
orae. Se cere s se determine drumul minim care s
porneasc dintr-un ora oarecare, s treac o singur dat
prin toate oraele celelalte i s revin n oraul iniial.

227

Proiectarea algoritmilor reele neuronale (1)




Reelele neuronale sunt folosite pentru rezolvarea unor


probleme dificile, cum sunt cele de estimare, identificare i
predicie.
Exist probleme practice de mare complexitate pentru care
elaborarea unui algoritm este dificil sau chiar imposibil.
Pornind de la o mulime de exemple, reelele neuronale sunt
capabile s sintetizeze un model al problemei. Un mare avantaj
al reelelor neuronale const n capacitatea lor de a nva din
exemple i apoi s trateze cazuri similare.
Reelele neuronale sunt formate dintr-o multitudine de neuroni,
elemente simple de calcul care opereaz n paralel.
Modelul de neuron a fost propus de McCulloch i Pitts n 1943.
Hebb a introdus n 1949 un mecanism de nvare prin
modificarea conexiunilor sinaptice dintre neuroni. Rosenblatt a
propus apoi n 1957 primul model de reea neuronal numit
perceptron, care interconecteaz o mulime de neuroni.
228

Proiectarea algoritmilor reele neuronale (2)


Perceptronul multistrat


Structura perceptronului multistrat cu un singur strat ascuns este


prezentat n figura urmtoare:
VIN
x1

VHID
VOUT
o1

xN

oP

Fiecare intrare xi ntr-un neuron are asociat o pondere wi. Ieirea


neuronului se obine prin nsumarea ponderat a intrrilor,
n

y = wi xi
i =1

asupra creia se aplic o funcie de activare.


229

Proiectarea algoritmilor reele neuronale (3)


Funcii de activare


Funcia de activare are rolul de a restrnge domeniul de variaie al


ieirii neuronului. Cele mai uzuale funcii de activare sunt urmtoarele:
1 ey
f ( y) =
1 + ey

1
f ( y) =
1 + ey

1
y
y

-1

Vom folosi n continuare funcia de activare

1 ey
f ( y) =
1 + ey

care restrnge ieirea neuronului la intervalul (-1, 1).


230

Proiectarea algoritmilor reele neuronale (4)


Algoritmul de nvare backpropagation [Mit97]


Algoritmul backpropagation ajusteaz ponderile reelei neuronale astfel


nct eroarea s scad
Algoritmul de nvare backpropagation, cu funcia de activare

1 e y
f ( y) =
1+ ey
i intrri codificate cu -1 i 1, const n urmtorii pai:
1. Se creeaz o reea neuronal cu N intrri, M uniti ascunse i P
uniti de ieire.
2. Se iniializeaz ponderile

wij1 ; i = 1, N ; j = 1, M
w 2jk ; j = 1, M ; k = 1, P
cu valori aleatoare mici [Mit97] din intervalul (-0.05, 0.05).

231

Proiectarea algoritmilor reele neuronale (5)


( )

1 P
EW =
t k ok2
2 k =1

3. Ct timp

>T

repet

3.1. Se aplic reelei intrarea X 1 i se calculeaz ieirea O 2


N

net = wij1 xi1 ,


1
j

j = 1, ..., M

i =1

x 2j = o1j = f ( net 1j ),
M

net = w 2jk x 2j ,
2
k

j = 1, ..., M
k = 1, ..., P

j =1

o k2 = f ( net k2 ),

k = 1, ..., P

3.2. Pentru fiecare neuron din stratul de ieire k , k = 1 , P


2
se calculeaz eroarea k fa de valoarea corect tk

k2 = t k ok2 f (net k2 ) =

)(

1
t k ok2 1 ok2 ok2
2

232

Proiectarea algoritmilor reele neuronale (6)


3.3. Pentru fiecare neuron din stratul de ieire j , j = 1, M
1
se calculeaz eroarea j

1j

k =1

k2

w 2jk

(net 1j )

P
1
1
1
= 1 o j o j k2 w 2jk
2
k =1

3.4. Se actualizeaz toate ponderile reelei neuronale

w 2jk = w 2jk + k2 x 2j ,
wij1 = wij1 + 1j xi1 ,
unde

j = 1, M ,
i = 1, N ,

k = 1, P
j = 1, M

este rata de nvare.

233

Proiectarea algoritmilor reele neuronale (7)

Aplicaii propuse
1.

S se rescrie algoritmul backpropagation pentru funcia de


activare

1
f ( y) =
1 + e y
2.

S se implementeze n Java o reea neuronal cu un strat


ascuns care, pe baza algoritmului backpropagation prezentat, s
nvee cifrele 0-9.

3.

S se implementeze n Java o reea neuronal cu un strat


ascuns care, folosind algoritmul backpropagation, s nvee
literele alfabetului limbii engleze.
234

Nota final
Nota laborator (NL) = 0,2*T1 + 0,2*T2 + 0,1*A + 0,5*C
Nota final = 0,5*NL + 0,5*E


T1 = Test gril susinut din noiunile predate n cadrul


capitolului Limbajul Java;

T2 = Test susinut la laborator din aplicaiile propuse la


laborator n cadrul capitolului Limbajul Java;

A = Activitatea la laborator (teme);

C = Colocviu de laborator din aplicaiile propuse la laborator n


cadrul capitolelor Analiza algoritmilor respectiv Proiectarea
algoritmilor;
E = Examen susinut din capitolele Analiza algoritmilor i
Proiectarea algoritmilor.
235

Bibliografie
Algoritmi
[Knu00] Knuth D., Arta programrii calculatoarelor, Vol. 1 Algoritmi fundamentali, Teora, 2000.
[Knu02] Knuth D., Arta programrii calculatoarelor, Vol. 3 Sortare i cutare, Teora, 2002.
[Cor00] Cormen T., Leiserson C., Rivest R., Introducere n algoritmi, Agora, 2000.
[Giu04] Giumale C., Introducere n analiza algoritmilor, Polirom, 2004.
[Log07] Logoftu D., Algoritmi fundamentali n Java, Polirom, 2007.
[Wai01] Waite M., Lafore R., Structuri de date i algoritmi n Java, Teora, 2001.
[Cri98] Cristea V., Athanasiu I., Kalisz E., Iorga V., Tehnici de programare, Teora 1998.
[Mit97] Mitchell T., Machine Learning, McGraw-Hill, 1997.

Programare n Java
[Rob00] Roberts S., Heller P., Ernest M., Complete Java 2 Certification, Second Edition, SYBEX, USA, 2000.
[Cha01] Chan M., Griffith S., Iasi A., Java 1001 secrete pentru programatori, Teora, 2000.
[Tan07] Tanas ., Andrei ., Olaru C., Java de la 0 la expert, Polirom, 2007.
[Hun01] Hunter J., Crawford W., Java Servlet Programming, Second Edition, OReilly, USA, 2001.
[Gea01] Geary D., Advanced JavaServer Pages, Prentice Hall, USA, 2001.
[Gor98] Gordon R., Java Native Interface, Prentice Hall, USA, 1998.
236

Webliografie
[Web01]
[Web02]
[Web03]
[Web04]
[Web05]

http://java.sun.com/docs/codeconv/html/CodeConvTOC.doc.html
http://www.javapassion.com/javaintro/
http://thor.info.uaic.ro/~acf/java/curs/cursuri.html
http://labs.cs.utt.ro/labs/sdaa/html/LabSDA.html
http://www.personal.kent.edu/~rmuhamma/Algorithms/algorithm.html

237

S-ar putea să vă placă și