This repository has been archived by the owner on Nov 19, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Esercizio1.java
336 lines (289 loc) · 9.87 KB
/
Esercizio1.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
import java.util.Locale;
import java.util.Random;
import java.util.Scanner;
/**
* Enjun Hu
* 0000944041
*/
/**
* Soluzione 2 tramite l'uso di un MinHeap:
* Tra le varie soluzioni, questa risulta quella più efficiente, dove si ha un
* C.C. pari a O(log n) per le Operazioni b) e c) garantendo al contempo le
* condizioni 1) e 2) richieste. Mentre per l'operazione a) si ha un Costo O(1).
*
* A differenza di un MinHeap per le code di priorità, non si avrà l'array pos[]
* e quindi non si avrà un Overhead di O(K) in quanto non è necessario il metodo
* DecreseKey().
*
* Questa è la soluzione più efficiente dato il problema ma bisogna notare come
* esso sia efficiente perchè sappiamo che avremo sempre K o K-1 elementi nella
* nostra struttura. Quindi se l'ordine delle operazioni fossero cambiate,
* questa soluzione dovrebbe essere rivista, in quanto potrebbe capitare che
* si riempia lo spazio disponibile nella struttura, visto che il MinHeap si
* basa su un vettore statico di K elementi.
* Bisogna tenere in considerazione anche il fatto che il costo ammortizzato
* dell'Inserimento e della Cancellazione (dovuto al Raddoppio e Dimezzamento) è
* pari a O(1), quindi in "teoria" non violerebbe la condizione 1) e 2).
*
* Tempo: O(log K)
* Spazio: O(K)
*/
public class Esercizio1 {
MinHeap S;
public static void main(String[] args) {
Locale.setDefault(Locale.US);
Esercizio1 es1 = new Esercizio1();
}
/**
* Chiede in input i valori di K, TSI(1) e TSE(1)
* per poi popolare la struttura partendo da questi valori.
* Inoltre esegue per 2K volte le operazioni a), b), c).
*
* Viene stampato i dati nella struttura prima e dopo il ciclo di operazioni.
*/
public Esercizio1() {
Scanner sc = new Scanner(System.in);
final int K = sc.nextInt();
int TSI = sc.nextInt();
int TSE = sc.nextInt();
sc.close();
assert (K > 15 && K < 27);
assert (TSE > TSI);
this.S = new MinHeap(K);
int i = 1;
S.insert(i, TSI, TSE);
Random Z = new Random(944041);
Random T = new Random(944041);
for (i = 2; i <= K; i++) {
TSI = TSI + Z.nextInt(7) + 4;
TSE = TSI + T.nextInt(6) + 2;
assert (TSE > TSI);
S.insert(i, TSI, TSE);
}
System.out.println("Lista Prima le 2K operazioni\n");
printList(S);
// Eseguire il ciclo di operazioni a), b) e c) 2*K volte.
for (int j = 0; j < 2 * K; j++) {
Tripla t = S.min();
S.deleteMin();
TSI = TSI + Z.nextInt(7) + 4;
TSE = TSI + T.nextInt(6) + 2;
S.insert(i, TSI, TSE);
i++;
}
System.out.println("Lista Dopo le 2K operazioni\n");
printList(S);
}
/**
* Stampa la lista delle Triple contenute nella struttura S.
* Nel formato: [i TSI TSE]
*
* @param S
*/
protected static void printList(MinHeap S) {
for (Tripla tripla : S.heap) {
System.out.println(tripla);
}
}
private class Tripla {
public final int i;
public final int TSI;
public final int TSE;
public Tripla(int i, int TSI, int TSE) {
this.i = i;
this.TSI = TSI;
this.TSE = TSE;
}
@Override
public String toString() {
return this.i + "\t" + this.TSI + "\t" + this.TSE;
}
}
/**
* Struttura MinHeap (vista a lezione), modificata e riadattata per soddisfare
* le operazioni e le condizioni 1) e 2) richieste.
*/
private class MinHeap {
Tripla heap[];
int size, maxSize;
public MinHeap(int maxSize) {
this.heap = new Tripla[maxSize];
this.maxSize = maxSize;
this.size = 0;
}
/**
* Controlla la validità dell'indice
*/
private boolean valid(int i) {
return ((i >= 0) && (i < size));
}
/**
* Inverte l'heap[i] con l'heap[j]
*/
private void swap(int i, int j) {
Tripla elemTmp = heap[i];
heap[i] = heap[j];
heap[j] = elemTmp;
}
/**
* Ritorna il nodo padre di heap[i]
*/
private int parent(int i) {
assert (valid(i));
return (i + 1) / 2 - 1;
}
/**
* Ritorna l'indice del figlio sinistro dell'heap[i]
*/
private int lchild(int i) {
assert (valid(i));
return (i + 1) * 2 - 1;
}
/**
* Ritorna l'indice del figlio destro dell'heap[i]
*/
private int rchild(int i) {
assert (valid(i));
return lchild(i) + 1;
}
/**
* Controlla se l'Heap è vuoto.
*/
public boolean isEmpty() {
return (size == 0);
}
/**
* Controlla se l'Heap è pieno.
*/
public boolean isFull() {
return (size > maxSize);
}
/**
* Operazione A.
* Costo O(1).
*
* @return La Tripla caratterizzata dal
* valore minimo della differenza tra TSE(i) – TSI(i).
*
*/
public Tripla min() {
assert (!isEmpty());
return heap[0];
}
/**
*
* Scambia la tripla i-esima con il suo padre finchè non arriva alla posizione
* corretta nell'Heap.
*
* Ha un Costo pari a O(log n).
*/
private void moveUp(int i) {
assert (valid(i));
int p = parent(i);
while ((p >= 0) && ((heap[i].TSE - heap[i].TSI < heap[p].TSE - heap[p].TSI)
|| ((heap[i].TSE - heap[i].TSI == heap[p].TSE - heap[p].TSI) && heap[i].i < heap[p].i))) {
swap(i, p);
i = p;
p = parent(i);
}
}
/**
*
* Ritorna la posizione del figlio con la priorità minore.
* In caso di due figli con stessa priorità, ritorna quello con l'identificativo
* "i" minore.
*
* Se non ha figli, ritorna -1.
*/
private int minChild(int i) {
assert (valid(i));
final int l = lchild(i);
final int r = rchild(i);
int result = -1;
if (valid(l)) {
result = l;
if (valid(r)) {
if (heap[r].TSE - heap[r].TSI < heap[l].TSE - heap[l].TSI) {
result = r;
}
// Si controlla inoltre, nel caso fossero uguali la differenza tra TSE e TSI,
// l'indice i, che come richiesto, bisogna dare "priorità a quello minore".
else if ((heap[r].TSE - heap[r].TSI == heap[l].TSE - heap[l].TSI) && (heap[r].i < heap[l].i)) {
result = r;
}
}
}
return result;
}
/**
* Inverte la tripla i-esima con il figlio con "priorità" inferiore, se esiste,
* finchè non raggiunge la corretta posizione nell'heap.
* Costo O(log n).
*
* Tiene in considerazione anche l'identificativo "i" nella Tripla, in caso di
* Priorità uguale.
* In caso di priorità uguale, ci sarà sempre quello con il valore di "i" minore
* in cima, grazie al while() che si ferma solo quando la Priorità della Tripla
* in cima è minore o uguale a quelle dei figli ().
*
* Non ci potrà mai essere una Tripla con identificativo "i" maggiore sopra ad
* una Tripla con stessa priorità ma uno con identificiativo "i" minore.
* Esso è dimostrabile per Assurdo, in quanto affinchè venga messo una Tripla X
* più in alto rispetto ad una Tripla Z, con stessa priorità ma quest'ultima con
* "i" minore, occorrerebbe che tra le due triple ci sia almeno un'altra Tripla
* Y in mezzo, quest'ultima con priorità maggiore rispetto alla priorità di X.
* Il che è assurdo visto che X e Z hanno la stessa priorità (X <= Y <= Z).
*
* Gli "if statement" possono essere compattati, ma si lascia diviso per
* questioni di leggibilità del codice.
*
* Costo O(log n)
*/
private void moveDown(int i) {
assert (valid(i));
boolean done = false;
do {
int dst = minChild(i);
if (valid(dst)) {
if ((heap[dst].TSE - heap[dst].TSI < heap[i].TSE - heap[i].TSI)) {
swap(i, dst);
i = dst;
} else if ((heap[dst].TSE - heap[dst].TSI == heap[i].TSE - heap[i].TSI)
&& (heap[dst].i < heap[i].i)) {
swap(i, dst);
i = dst;
} else {
done = true;
}
} else {
done = true;
}
} while (!done);
}
/**
* Inserisce una nuova Tripla (i, TSE, TSI) nel MinHeap.
* Costo O(log n).
*/
public void insert(int id, int TSI, int TSE) {
assert (!isFull());
final int i = size++;
heap[i] = new Tripla(id, TSI, TSE);
moveUp(i);
}
/**
*
* Elimina l'elemento con priorità minore.
* Riordina l'heap dopo l'eliminazione.
*
* Tempo O(log n).
*/
public void deleteMin() {
assert (!isEmpty());
swap(0, size - 1);
size--;
if (size > 0)
moveDown(0);
}
}
}