Structuri de Date în Java (IV) -...

32
1 Structuri de Date în Java (IV) Vectori în Java: excepţii, clonare Colecţii: adăugare, ştergere, numărare, fuzionare, clonare Liste înlănţuite: creare, modificare noduri, ştergere, duplicare Liste dublu înlănţuite Comparaţie de performanţe între liste şi vectori

Transcript of Structuri de Date în Java (IV) -...

1

Structuri de Date în Java (IV)

● Vectori în Java: excepţii, clonare● Colecţii: adăugare, ştergere, numărare, fuzionare,

clonare● Liste înlănţuite: creare, modificare noduri,

ştergere, duplicare● Liste dublu înlănţuite● Comparaţie de performanţe între liste şi vectori

2

Vectori Java● clase colecţii – stochează obiecte de acelaşi fel● un vector – secvenţă cu un anumit număr de componente

7 22 19 56

[0] [1] [2] [3]

int[] scores;// scores este tot o// variabilă referinţă!// ce valoare are scores?// se alocă un array cu 4// componente întregiscores = new int [4];scores.length; // 4

scores

[0] [1] [2] [3]

3

Excepţii folosite de vectori

● NullPointerException – variabilă vector nealocată (null)● ArrayIndexOutOfBounds – de exemplu acces la scores[-1]

int[] scores;int[] exams;scores = new int [4];System.out.println (scores.length);scores[0] = 7;scores[1] = 22;scores[2] = 19;scores[3] = 56;exams = scores;

scores

7 22 19 56

[0] [1] [2] [3]exams

4

Clonarea vectorilor

● Realizează o copie perfectă fără a afecta originalul● Toate obiectele Java au această metodă clone()● Metoda clone() întoarce întotdeauna o referinţă la Object

int[] scores;int[] exams;scores = new int [4];scores[0] = 7;scores[1] = 22;scores[2] = 19;scores[3] = 56;exams = (int[]) scores.clone ();

// necesită conversie explicită!

scores

7 22 19 56

[0] [1] [2] [3]

exams

7 22 19 56

[0] [1] [2] [3]

5

Teste cu vectori

// test 1: care este cel mai mic respectiv cel mai mare index permis ?int[] b = new int[42];

// test 2: ce se afişează?int[] a, b;a = new int [10];a[5] = 1;b = a;a[5] = 42;System.out.println (b[5]);

// test 3: idemint[] a, b;a = new int [10];a[5] = 2;b = (int[]) a.clone ();a[5] = 42;System.out.println (b[5]);

6

Implementarea unei colecţii

● Colecţia de întregi trebuie să permită:● stocarea întregilor într-un vector● adăugarea unui element● ştergerea unui element anume● aflarea numărului total de elemente● determinarea numărului de elemente egale cu

un element dat● fuzionarea cu altă colecţie

7

Definirea clasei

// clasa va implementa interfata Cloneable pentru a suporta duplicareapublic class IntArrayBag implements Cloneable {

// aici stocăm întregiiprivate int[] data;

// câţi întregi sunt în colecţie (spaţiul disponibil e păstrat în ... ?)private int manyIems;

// metodele publice pe care vom expune pe slide-urile următoare// ...

}

8

Constructorii

public IntArrayBag (int initialCapacity) {if (initialCapacity < 0)

throw new IllegalArgumentException (“initial capacity < 0”);manyItems = 0;data = new int [initialCapacity];

}

public IntArrayBag (void) { // constructorii au grijă să punămanyItems = 0; // ceva valid în variabileledata = new int [6]; // membre

}

9

ensureCapacitypublic void ensureCapacity (int minumumCapacity) {

int biggerArray [];if (data.length < minimumCapacity) {

biggerArray = new int [minimumCapacity];System.arraycopy (data, 0, biggerArray, 0, manyItems);data = biggerArray;

}

2 7 9 3

[0] [1] [2] [3] [4] [5]

manyItems 4

data

biggerArray 2 7 9 3

[0] [1] [2] [3] [4] [5] [6] [7]

10

Adăugarea

public void add (int element){

if (manyItems == data.length){

// dublează capacitatea şi adaugă un element// dacă manyItems * 2 + 1 > Integer.MAX_VALUE, va apare// o depăşire aritmetică şi operaţia eşueazăensureCapacity (manyItems * 2 + 1);

}

data[manyItems] = element;manyItems ++;

}

// de exemplux.add (7);

3 5 9 8

[0] [1] [2] [3]

7

[4] [5]

data

manyItems 45

11

Ştergerea

public boolean remove (int target) {// caută locaţia elementului în array; dacă nu este găsit, întoarce manyItemsindex = 0;while (index <= manyItems && target != data[index] )

index ++;

if (index != manyItems) {// s-a găsit elementul data[index]manyItems --;data[index] = data[manyItems];return true;

}// nu s-a găsit un element targetreturn false;

}3 5 9 8

[0] [1] [2] [3]

7

[4] [5]

data

manyItems 5

7

4

12

Numărarea duplicatelor

public int countOccurences (int target) {int answer;int index;

answer = 0;for (index = 0 ; index < manyItems ; index ++)

if (target == data[index])answer ++;

return answer;}

13

Fuzionarea cu altă colecţiepublic void addAll (IntArrayBag vec) {

// dacă vec este null, se aruncă o excepţie// de tip NullPointerExceptionensureCapacity (manyItems + vec.manyItems);

System.arraycopy (vec.data, 0, data, manyItems, vec.manyItems);

manyItems += vec.manyItems;}

de unde unde câte elemente

14

Un alt mod de fuzionare

public static IntArrayBag add (IntArrayBag b1, IntArrayBag b2){

// dacă b1 sau b2 sunt null, se aruncă o excepţieint t = b1.getCapacity () + b2.getCapacity ();IntArrayBag answer = new IntArrayBag (t);answer.manyItems = b1.manyItems + b2.manyItems;

System.arraycopy (b1.data, 0, answer.data, 0, b1.manyItems);System.arraycopy ( // destinaţie, sursă, număr

b2.data, 0, answer.data, b1.manyItems, b2.manyItems);

return answer;}

15

Clonarea

public Object clone () {IntArrayBag answer;

try { // clonăm obiectul bit cu bitanswer = (IntArrayBag) super.clone ();

} catch (CloneNotSupportedException e) {throw new RuntimeException (“forgot to implement Cloneable”);

}

// în noul obiect avem aceeaşi referinţă; trebuie să clonăm şi array-ul!// dacă nu o facem, vom avea array-ul comun în cele două obiecteanswer.data = (int []) data.clone ();

return answer;}

16

Efecte colaterale ale clonării

2 7 9 3

[0] [1] [2] [3] [4] [5]

manyItems 4

2 7 9 3

[0] [1] [2] [3] [4] [5]

manyItems 4

answer.data

data

data

● obiectul iniţial

● după clonare

answer.manyItems 4

`

17

Teste cu IntArrayBag// test 1: cum va arăta colecţia?IntArrayBag bag = new IntArrayBag (10);bag.add (1);bag.add (2);bag.add (3);bag.remove (1);

// test 2// ce se întâmplă dacă, adăugînd elemente,// depăşim cele 10 locaţii prealocate ?

// test 3// cum se scrie folosind System.arraycopy copierea// a 10 elemente de la începutul array-ului x în// array-ul y, începînd de pe poziţia a 5-a ?

18

Liste înlănţuite● Folosită la stocarea ordonată a elementelor● Fiecare element este conectat de elementul următor printr-o legătură (link)● Lista se poate parcurge doar mergînd din element în element● Fiecare nod este alcătuit dintr-o pereche (<valoare>, <legătura spre elementul următor>)

12 -414 10 •

19

Clasa IntNode

● Abstractizează lucrul cu noduri ale liste● Oferă suport pentru:

● crearea nodurilor● modificarea valorii unui nod● adăugarea sau ştergerea unui nod din listă● numărarea nodurilor din listă● căutarea unui nod după valoare● duplicarea listelor

20

Clasa IntNode

public class IntNode {private int data; // valoareprivate IntNode link; // legatura spre nodul următor

// ...}

// lista se păstrează prin memorarea referinţelor către// primul element, denumit head şi ultimul, denumit tailIntNode head;IntNode tail;

12 -414 10 •

head tail

referinţa null

21

Constructorul clasei

// se inţializează variabilele membrepublic IntNode (int val, IntNode lk) {

data = val;link = lk;

}

// de exemplu, aşa ar putea arăta crearea primului nod al listeiIntNode head = new IntNode (42, null);

42 •head

22

Metode acces şi modificare a stării

public int getData () {return data;

}

public IntNode getLink () {return link;

}

public void setData (int val) {data = val;

}

public void setLink (IntNode lk) {link = lk;

}

23

Adăugarea la începutul listei

head = new IntNode (5, head);

● Funcţionează şi dacă iniţial se porneşte cu lista vidă (head == null)

12 -414 10 •

head 5

24

Stergerea primului nodhead = head.getLink ();

● referinţa către (fostul) primul nod se nu se mai păstrează nicăieri● sistemul recunoaşte acest lucru şi va recupera spaţiul (garbage collector)

12 -414 10 •

head

25

Adăugarea unui nod dar nu la început

public void addNodeAfter (int val) {link = new IntNode (val, link);

}

12 -414 10 •

head

nod curent

3

26

Ştergerea unui nod care nu este la început

public void removeNodeAfter() {link = link.link;

} // ce se întâmplă dacă// link este null?

12 -414 10 •

head nod curent

27

Determinarea lungimii listei

public static int listLength (IntNode head) {IntNode cursor;int answer;

answer = 0;for (cursor = head ; cursor != null ; cursor = cursor.link )

answer ++;

return answer;}

28

Căutarea în listă a unui element de o valoare anume

public static IntNode listSearch (IntNode head, int target) {IntNode cursor;

for (cursor = head ; cursor != null ; cursor = cursor.link)if (target == cursor.data)

return cursor;

return null;}

29

Căutarea în listă a unui nod de pe o poziţie dată

public static IntNode listPosition (IntNode head, int position) {IntNode cursor;int i;if (position <= 0)

return null;

cursor = head;for (i = 1 ; i < position && cursor != null ; i ++)

cursor = cursor.link;

return cursor;}

30

Copierea unei liste

public static IntNode listCopy (IntNode source) {IntNode copyHead, copyTail;

// crearea primului nodcopyHead = new IntNode (source.data, null);copyTail = copyHead;

// copierea restului listeiwhile (source.link != null) {

source = source.link;copyTail.addNodeAfter (source.data);copyTail = copyTail.link;

} // se poate utiliza clonarea// pentru duplicarea listei?

return copyHead;}

31

Liste dublu înlănţuite

public class DoubleLinkedList {private int data;private DoubleLinkedNode back;private DoubleLinkedNode next;// ...

}

12 -4 10 •

head tail

32

Comparaţie a performanţelor

● dacă elementele sunt accesate la întâmplare, array-ul este mai rapid

● dacă elementele sunt accesate unul după altul, 'la rând', este mai avantajoasă o listă înlănţuită, mai ales pentru inserări la urmă

● redimensionarea este ineficientă pentru array; la o listă, se adaugă un element nou la coadă

● pentru deplasarea în ambele direcţii, folosim o listă dublu-înlănţuită