Documente Academic
Documente Profesional
Documente Cultură
ȘI STRUCTURI DE DATE
IE.2021
2
1. Stive
● Definiție/concepte:
○ Principiul LIFO
● Tipul abstract de date Stivă/Stack:
○ Interfața Stack
● Implementări:
○ bazate pe tablouri
○ bazate pe liste simplu înlănțuite
● Scurtă aplicație practică cu stive: HanoiTowerWithStack
3
Stiva: Concept
● O stivă (stack) reprezintă o structură de date de tip colecție în care
elementele sunt adăugate și îndepărtate conform principiului LIFO
○ Last-In-First-Out: obiectele pot fi oricând și în orice ordine adăugate, însă direct accesibile
sunt doar cele mai recente (cele din capătul superior - top - al stivei).
4
Stive: exemple
5
Tipul abstract de date Stivă (Stack)
public interface Stack<E> {
Operația Descriere
int size();
size() Returnează capacitatea stivei. boolean isEmpty();
void push(E e);
isEmpty() Returnează un boolean care
E top();
specifică dacă stiva este goală.
E pop();
push(e) Alimentează stiva cu un nou element }
adăugat la capătul superior
6
Exemplu
7
Implementare tip Stiva pe baza unui tablou
● Structura internă a clasei ArrayStack [extras (Goodrich14)]:
public class ArrayStack<E> implements Stack<E> {
/** Default array capacity. */
public static final int CAPACITY=1000; // default array capacity
/** Generic array used for storage of stack elements. */
private E[] data; // generic array used for storage
/** Index of the top element of the stack in the array. */
private int t = -1;
public ArrayStack() { this(CAPACITY); } // constructs stack with default capacity
public ArrayStack(int capacity) { // constructs stack with given capacity
data = (E[]) new Object[capacity]; // safe cast; compiler may give warning
}
...
}
8
Implementare TAD Stiva pe baza unui tablou
● Metode implementare operații în clasa ArrayStack:
public class ArrayStack<E> implements Stack<E> {
public int size() { return (t + 1); }
public boolean isEmpty() { return (t == -1); }
public void push(E e) throws IllegalStateException {
if (size() == data.length) throw new IllegalStateException("Stack is full");
data[++t] = e;
}
public E top() {
if (isEmpty()) return null; return data[t];
}
public E pop() {
if (isEmpty()) return null;
E answer = data[t]; data[t] = null; t--;
return answer;
}
}
9
Implementare TAD Stiva
pe baza unei liste simplu înlănțuite
● Metode Implementare operații în clasa LinkedStack [extras (Goodrich14)]:
public class LinkedStack<E> implements Stack<E> {
/** The primary storage for elements of the stack */
private SinglyLinkedList<E> list = new SinglyLinkedList<>(); // an empty list
10
Aplicație practică/Studiu de caz Stivă
Recursivitate: Turnul din Hanoi cu Stive
public static <E> void Hanoi(int n, Stack<E> src, Stack<E> dst, Stack<E> tmp) {
if (n > 0) {
// muta toate discurile in tmp cu exceptia celui mai mare
Hanoi(n - 1, src, tmp, dst);
// recursiv: muta toate discurile din tmp in destinatie (peste discul cel mai mare)
// folosing src ca si tmp de aceasta data
Hanoi(n - 1, tmp, dst, src);
}
}
11
Aplicație practică/Studiu de caz Stivă
Recursivitate: Turnul din Hanoi cu Stive
public static void main(String[] args) {
Stack<String> stack_A = new ArrayStack<String>();
Stack<String> stack_B = new ArrayStack<String>();
Stack<String> stack_C = new ArrayStack<String>();
stack_A.push("disc_1____");
stack_A.push("disc_2___");
stack_A.push("disc_3__");
stack_A.push("disc_4_");
System.out.println("Stack_A: " + stack_A);
System.out.println("Stack_B: " + stack_B);
System.out.println("Stack_C: " + stack_C);
13
Coada: concept
● O coadă (queue) reprezintă o structură de date de tip colecție în care
elementele sunt adăugate și îndepărtate conform principiului FIFO:
○ First-In-First-Out: obiectele pot fi adăugate oricând și în orice ordine, însă direct accesibile
sunt doar cele mai “vechi”.
14
Tipul abstract Coadă/Queue
public interface Queue<E> {
Operația Descriere
int size();
size() Returnează capacitatea cozii. boolean isEmpty();
void enqueue(E e);
isEmpty() Returnează un boolean care
E dequeue();
specifică dacă coada este goală.
E first();
enqueue(e) Alimentează coada cu un nou }
element adăugat la capătul superior
15
Implementare tip Coadă pe baza unui tablou
● Structura internă a clasei ArrayQueue [extras (Goodrich14)]:
public class ArrayQueue<E> implements Queue<E> {
/** Default array capacity. */
public static final int CAPACITY = 1000; // default array capacity
/** Generic array used for storage of queue elements. */
private E[] data; // generic array used for storage
/** Index of the top element of the queue in the array. */
private int f = 0; // index of the front element
/** Current number of elements in the queue. */
private int sz = 0; // current number of elements
16
Implementare tip Coadă pe baza unui tablou
● Metode Implementare operații în clasa ArrayQueue
public class ArrayQueue<E> implements Stack<E> {
public int size() { return sz; }
public boolean isEmpty() { return (sz == 0); }
public void enqueue(E e) throws IllegalStateException {
if (sz == data.length) throw new IllegalStateException("Queue is full");
int avail = (f + sz) % data.length; // use modular arithmetic
data[avail] = e; sz++;
}
public E first() {
if (isEmpty()) return null;
return data[f];
}
public E dequeue() {
if (isEmpty()) return null;
E answer = data[f]; data[f] = null;
f = (f + 1) % data.length; sz--;
return answer;
}
} 17
Implementare tip Coadă pe baza unui tablou
18
Implementare tip Coadă:
pe baza unei liste simplu înlănțuite
● Metode Implementare operații în clasa LinkedQueue [extras (Goodrich14)]:
19
Aplicație practică/Studiu de caz Coadă
Gestionare elemente în depozit
public class WarehouseQueue<E> {
private Double threshold = 0.0;
private Double fillingLevel = 0.0;
private Double warehouseMaxCapacity = 0.0;
private LinkedQueue<WarehouseEntry<E>> wQueue = new LinkedQueue<>();
//
public static class WarehouseEntry<E>{
private E entry;
private Double amount;
... ... // getters&setters&constructors
}
//
public WarehouseQueue(Double threshold, Double warehouseMaxCapacity) {
this.threshold = threshold;
this.warehouseMaxCapacity = warehouseMaxCapacity;
}
}
20
Aplicație practică/Studiu de caz Coadă
Gestionare elemente în depozit
public Stack<E> addIntoWarehouse(E entry, Double amount){
// check if there is enough room even after releasing some older items
if (this.fillingLevel + amount > this.warehouseMaxCapacity &&
this.threshold + amount > this.warehouseMaxCapacity)
throw new RuntimeException("Not enough space in warehouse!");
// firstly remove some items to make enough room for the new entry
Stack<E> releasedItems = releaseItemsFromWarehouse();
21
Aplicație practică/Studiu de caz Coadă
Gestionare elemente în depozit
private Stack<E> releaseItemsFromWarehouse() {
Stack<E> releasedItems = new ArrayStack<E>();
WarehouseEntry<E> releasedEntry;
// release item until warehouse filling level fall under warehouse threshold
while(this.fillingLevel > this.threshold) {
// release item under FIFO rule
releasedEntry = this.wQueue.dequeue();
// increase warehouse filling level
this.fillingLevel -= releasedEntry.getAmount();
releasedItems.push(releasedEntry.getEntry());
}
return releasedItems;
}
22
Aplicație practică/Studiu de caz Coadă
Gestionare elemente în depozit - Test
public static void main(String[] args) {
WarehousePQueue<String> warehouseQueue = new WarehousePQueue<String>(60.0, 100.0);
Stack<String> releasedItems;
//
releasedItems = warehouseQueue.addIntoWarehouse("Item_1", 20.0);
System.out.println(">>> Warehouse: " + warehouseQueue);
System.out.println(">>> >>> releasedItems: " + releasedItems);
System.out.println("-------------------------------------------");
23
Aplicație practică/Studiu de caz Coadă
Gestionare elemente în depozit - Test
public static void main(String[] args) {
... ...
releasedItems = warehouseQueue.addIntoWarehouse("Item_4", 20.0);
System.out.println(">>> Warehouse: " + warehouseQueue);
System.out.println(">>> >>> releasedItems: " + releasedItems);
System.out.println("-------------------------------------------");
25
Coadă cu priorități: concept
● O coadă cu priorități (priority queue) reprezintă o structură de date de tip
colecție în care elementele sunt adăugate arbitrar și sunt accesate și
îndepărtate (mai întâi) elementele cu prioritatea cea mai mare (primele în
ordinea priorității).
○ Prioritatea reprezintă o proprietate specifică elementelor desemnată printr-o cheie ale cărei
valori minimale desemnează prioritățile cele mai importante.
26
Tipul abstract CoadăCuPriorități PriorityQueue
public interface PriorityQueue<K,V> {
Operația Descriere
int size();
size() Returnează capacitatea cozii. boolean isEmpty();
Entry<K,V> insert(K key, V value)
isEmpty() Returnează un boolean care
Entry<K,V> min();
specifică dacă coada este goală.
Entry<K,V> removeMin();
insert(k, v) Alimentează coada cu o nouă intrare }
cu prioritatea k și valoarea v.
// Entry Composite
min() Returnează intrarea cu cheia (k) cea public interface Entry<K,V> {
mai mică din coadă (fără eliberare). K getKey();
removeMin() Returnează și eliberează intrarea cu V getValue();
cheia (k) cea mai mică din coadă. }
27
Comparabilitatea cheilor de prioritate
● Conceptul de cheie minimală este definit prin:
○ kmin <= k, pentru orice k din setul de chei.
● Conceptul de prioritate sau de cheie minimală este abstractizat prin
formalizarea conceptului de comparabilitate - definit în Java prin interfețele:
○ Comparable<T>, care impune pentru instanțele claselor conforme (care o implementează)
sintaxa
■ a.compareTo(b);
○ Comparator<T>, care permite compararea instanțelor unor clase arbitrare printr-un obiect
extern prin sintaxa:
■ comparator.compare(a, b);
28
Exemplu implementare comparabilitate
public class StringLengthComparator implements Comparator<String> {
/** Compares two strings according to their lengths. */
public int compare(String a, String b) {
if (a.length() < b.length()) return -1;
else if (a.length() == b.length()) return 0;
else return 1;
}
}
32
Aplicație practică/Studiu de caz Coadă
Gestionare elemente în depozit
public class WarehousePQueue<E> {
private Double threshold = 0.0;
private Double fillingLevel = 0.0;
private Double warehouseMaxCapacity = 0.0;
private PriorityQueue<Double, WarehouseEntry<E>> wQueue = new UnsortedPriorityQueue<>();
//
public static class WarehouseEntry<E>{
private E entry;
private Double amount;
... ...
}
//
public WarehouseQueue(Double threshold, Double warehouseMaxCapacity) {
this.threshold = threshold;
this.warehouseMaxCapacity = warehouseMaxCapacity;
}
}
33
Aplicație practică/Studiu de caz Coadă
Gestionare elemente în depozit
public Stack<E> addIntoWarehouse(E entry, Double amount){
System.out.println("... adding:" + entry + " with: " + amount);
// check if there is enough room even after releasing some older items
if (this.fillingLevel + amount > this.warehouseMaxCapacity &&
this.threshold + amount > this.warehouseMaxCapacity)
throw new RuntimeException("Not enough space in warehouse!");
// firstly remove some items to make enough room for the new entry
Stack<E> releasedItems = releaseItemsFromWarehouse();
35
Aplicație practică/Studiu de caz Coadă
Gestionare elemente în depozit
public class WarehousePQueue<E> {
private Double threshold = 0.0;
private Double fillingLevel = 0.0;
private Double warehouseMaxCapacity = 0.0;
// Folosim ComparatorWarehouseAmount pentru a elimina cu prioritate articolele cele mai mari
private PriorityQueue<Double, WarehouseEntry<E>> wQueue =
new UnsortedPriorityQueue<>(new ComparatorWarehouseAmount());
//
private static class ComparatorWarehouseAmount implements Comparator<Double>{
@Override
public int compare(Double o1, Double o2) {
return -o1.compareTo(o2);
}
}
... ...
}
36
}
3. Tabele asociative (mape). Sumar
● Definiție/concepte:
○ Conceptul de cheie de căutare
○ Tablouri asociative/Tabele de simboluri
● Tipul abstract de date Map :
○ Interfața Map
● Implementări
○ Structura MapEntry
○ Clasa abstractă AbstractMap
■ Structuri: KeyIterator și ValueIterator
○ Implementare AbstractMap (prin mecanismul ArrayList)
■ folosind o listă nesortată UnsortedTableMap
● Scurtă aplicație cu mape: WordCount
37
Tabela asociativă: concept
● O tabelă asociativă (mapă) reprezintă o structură de date pentru stocarea și
regăsirea eficientă a valorilor (elementelor) identificate în mod unic printr-o
cheie de căutare.
○ În mod specific, o tabelă asociativă gestioneză perechi cheie-valoare (k, v), numite intrări, ale
căror chei sunt unice în cadrul tabelei.
○ O strategie de implementare ar putea consta în transformarea cheilor în valori Integer care ar
putea fi folosite drept indecși pentru referențierea în cadrul unui tablou.
● Cazuri de utilizare pentru tabele asociative:
○ Sistemul informațional universitar - gestiune școlaritate
■ Matricol → ÎnregistrareStudent
○ Sistemul de gestiune a numelor de domeniu DNS
■ HostName → AddressURL
○ Site social media
■ Username → Profile
38
Tipul abstract Map
Operația Descriere
put(k,v) Dacă tabela nu are o intrare cu cheia k, atunci va fi adăugată intrarea (k,v) și
returnează null; altfel va înlocui cu v valoare existentă (din intrarea existentă cu cheia k)
și va returna vechea valoare.
values() Returnează o colecție iterabilă conținând toate valorile (intrărilor) din tabelă, eventual
duplicate dacă mai multe chei sunt asociate cu aceeași valoare.
entrySet() Returnează o colecție iterabilă conținând toate intrările cheie-valoare din tabelă.
39
Interfața Java pentru tipul abstract Map
public interface Map<K,V> {
int size();
boolean isEmpty();
V get(K key);
V put(K key, V value);
V remove(K key);
Iterable<V> values();
Iterable<Entry<K,V>> entrySet();
}
40
TAD Map
41
Implementare TAD Map:
Folosirea unei liste nesortate (ArrayList)
● Structura internă a clasei de bază UnsortedTableMap: size(), entrySet()
public class UnsortedTableMap<K,V> extends AbstractMap<K,V> {
private ArrayList<MapEntry<K,V>> table = new ArrayList<>();
public int size() { return table.size(); }
//---------------- nested EntryIterator class ----------------
private class EntryIterator implements Iterator<Entry<K,V>> {
private int j=0;
public boolean hasNext() { return j < table.size(); }
public Entry<K,V> next() {
if (j == table.size()) throw new NoSuchElementException("No further entries");
return table.get(j++);
} ...
}
//---------------- nested EntryIterable class ----------------
private class EntryIterable implements Iterable<Entry<K,V>> {
public Iterator<Entry<K,V>> iterator() { return new EntryIterator(); }
}
public Iterable<Entry<K,V>> entrySet() { return new EntryIterable(); }
...}
42
Implementare TAD Map:
Clasa de bază (abstractă)
● Structura clasei de bază AbstractMap - key iterator [extras (Goodrich14)]:
public class AbstractMap<K,V> implements Map<K,V> {
... ...
//---------------- nested KeyIterator class ----------------
private class KeyIterator implements Iterator<K> {
private Iterator<Entry<K,V>> entries = entrySet().iterator(); // reuse entrySet
public boolean hasNext() { return entries.hasNext(); }
public K next() { return entries.next().getKey(); } // return key!
public void remove() { throw new UnsupportedOperationException("remove not supported"); }
}
//---------------- nested KeyIterable class ----------------
private class KeyIterable implements Iterable<K> {
public Iterator<K> iterator() { return new KeyIterator(); }
}
public Iterable<K> keySet() { return new KeyIterable(); }
... ...
}
43
Implementare TAD Map:
Clasa de bază (abstractă)
● Structura clasei de bază AbstractMap - values iterator
public class AbstractMap<K,V> implements Map<K,V> {
... ...
//---------------- nested ValueIterator class ----------------
private class ValueIterator implements Iterator<V> {
private Iterator<Entry<K,V>> entries = entrySet().iterator(); // reuse entrySet
public boolean hasNext() { return entries.hasNext(); }
public V next() { return entries.next().getValue(); } // return value!
public void remove() { throw new UnsupportedOperationException("remove not supported"); }
}
//---------------- nested ValueIterable class ----------------
private class ValueIterable implements Iterable<V> {
public Iterator<V> iterator() { return new ValueIterator(); }
}
public Iterable<V> values() { return new ValueIterable(); }
... ...
}
44
Implementare TAD Map:
Folosirea unei liste nesortate (ArrayList)
● Structura internă a clasei de bază UnsortedTableMap: get()
public class UnsortedTableMap<K,V> extends AbstractMap<K,V> {
private int findIndex(K key) {
int n = table.size();
for (int j=0; j < n; j++)
if (table.get(j).getKey().equals(key))
return j;
return -1; // special value denotes that key was not found
}
public V get(K key) {
int j = findIndex(key);
if (j == -1) return null; // not found
return table.get(j).getValue();
}
public boolean isEmpty() { return size() == 0; }
... ...
}
45
Implementare TAD Map:
Folosirea unei liste nesortate (ArrayList)
● Structura internă a clasei de bază UnsortedTableMap: put(), remove()
public class UnsortedTableMap<K,V> extends AbstractMap<K,V> {
public V put(K key, V value) {
int j = findIndex(key);
if (j == -1) {
table.add(new MapEntry<>(key, value)); // add new entry
return null;
} else // key already exists
return table.get(j).setValue(value); // replaced value is returned
}
public V remove(K key) {
int j = findIndex(key); int n = size();
if (j == -1) return null; // not found
V answer = table.get(j).getValue();
if (j != n - 1)
table.set(j, table.get(n-1)); // relocate last entry to 'hole' created by removal
table.remove(n-1); // remove last entry of table
return answer;
}
} 46
Aplicație practică/Studiu de caz Tabelă asociativă
WordCount
public static Map<String, Integer> wordFrequences(String text){
String[] words = text.split("\\W+");
Map<String, Integer> wordFrequences = new UnsortedTableMap<>();
for(String word: words) {
if (wordFrequences.get(word) == null)
wordFrequences.put(word, 0);
wordFrequences.put(word, wordFrequences.get(word)+1);
}
return wordFrequences;
}
47
Aplicație practică/Studiu de caz Tabelă asociativă
WordCount
public static String maxWordCount(String text) {
Map<String, Integer> wordFrequences = wordFrequences(text);
int max = 0;
String mostFrequentWord = null;
for (String word: wordFrequences.keySet()) {
System.out.println("Word: " + word + ": " + wordFrequences.get(word));
if (wordFrequences.get(word) > max) {
max = wordFrequences.get(word);
mostFrequentWord = word;
}
}
return mostFrequentWord;
}
48
Aplicație practică/Studiu de caz Tabelă asociativă
WordCount - Test
public class WordCount {
public static String maxWordCount(String text) { ... }
public static String wordFrequences(String text) { ... }
}
}
49
Referințe Java
50
Bibliografie
● Michael T. Goodrich, Roberto Tamassia, Michael H. Goldwasser, Data
Structures and Algorithms in Java™, Sixth Edition, Wiley, 2014 [Goodrich14]
● Robert Sedgewick, Kevin Wayne, Algorithms, Fourth Edition,
Addison-Wesley, 2011 [Sedgewick11]
51