Corso di Algoritmi e Strutture Dati Prima Esercitazione in Laboratorio 26/04/2005 In questa esercitazione consideremo due algoritmi, di cui è riportato il listato Java in calce al presente documento. L’esercitazione è suddivisa in 2 fasi. Fase 1 Per ciascun algoritmo si richiede di eseguire una analisi sperimentale dei tempi di elaborazione, invocando ripetutamente l’algoritmo su input di varia dimensione e misurando i tempi di elaborazione, riportando i risultati in opportune tabelle,1 ciascuna composta da numerose righe e due colonne, come nell’esempio schematizzato. Algoritmo A input size tempo (msec o sec) di esecuzione 10 t1 20 t2 30 t3 40 t4 … … Il passo con cui cresce la dimensione dell’input è puramente indicativo e può essere modificato a seconda delle esigenze.2 Quanto specificato, deve essere eseguito sui due algoritmi insertionSort ed ennesimoPrimo, dei quali è fornita l’implementazione Java come metodi static. Il primo metodo ha signature public static void insertionSort(int[] a) e, dato un array di int, ne esegue l’ordinamento (in senso crescente) attraverso un algoritmo di ordinamento denominato appunto Insertion Sort. Il secondo metodo ha signature public static long ennesimoPrimo(long n) e, dato un long n, calcola e restituisce l’n-esimo numero primo (per convenzione, ennesimoPrimo(1) restituisce 2). L’algoritmo è piuttosto semplice ed inefficiente. A tal scopo può essere utile il re-indirizzamento dell’output su file, disponibile al prompt del DOS. Ad esempio, il comando java Pippo > miofile.txt crea un file di nome miofile.txt contenente tutto l’output della invocazione java Pippo. 1 2 In alcuni casi, a passi troppo piccoli corrispondono aumenti dei tempi scarsamente percepibili. In questi casi, conviene utilizzare passi più ampi. Risorse JFC utili per la sperimentazione (evidenziate in giallo) java.lang Class System java.lang.Object java.lang.System public final class System extends Object The System class contains several useful class fields and methods. It cannot be instantiated. Among the facilities provided by the System class are standard input, standard output, and error output streams; access to externally defined "properties"; a means of loading files and libraries; and a utility method for quickly copying a portion of an array. Since: JDK1.0 Field Summary static PrintStream err The "standard" error output stream. static InputStream in The "standard" input stream. static PrintStream out The "standard" output stream. Method Summary static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length) Copies an array from the specified source array, beginning at the specified position, to the specified position of the destination array. static long currentTimeMillis() Returns the current time in milliseconds. static void exit(int status) Terminates the currently running Java Virtual Machine. static void gc() Runs the garbage collector. static String getenv(String name) Deprecated. The preferred way to extract system-dependent information is the system properties of the java.lang.System.getProperty methods and the corresponding getTypeName methods of the Boolean, Integer, and Long primitive types. For example: String classPath = System.getProperty("java.class.path","."); if (Boolean.getBoolean("myapp.exper.mode")) enableExpertCommands(); static Properties getProperties() Determines the current system properties. static String getProperty(String key) Gets the system property indicated by the specified key. static String getProperty(String key, String def) Gets the system property indicated by the specified key. static SecurityManager getSecurityManager() Gets the system security interface. static int identityHashCode(Object x) Returns the same hash code for the given object as would be returned by the default method hashCode(), whether or not the given object's class overrides hashCode(). static void load(String filename) Loads a code file with the specified filename from the local file system as a dynamic library. static void loadLibrary(String libname) Loads the system library specified by the libname argument. static String mapLibraryName(String libname) Maps a library name into a platform-specific string representing a native library. static void runFinalization() Runs the finalization methods of any objects pending finalization. static void runFinalizersOnExit(boolean value) Deprecated. This method is inherently unsafe. It may result in finalizers being called on live objects while other threads are concurrently manipulating those objects, resulting in erratic behavior or deadlock. static void setErr(PrintStream err) Reassigns the "standard" error output stream. static void setIn(InputStream in) Reassigns the "standard" input stream. static void setOut(PrintStream out) Reassigns the "standard" output stream. static void setProperties(Properties props) Sets the system properties to the Properties argument. static String setProperty(String key, String value) Sets the system property indicated by the specified key. static void setSecurityManager(SecurityManager s) Sets the System security. Methods inherited from class java.lang.Object clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait java.util Class Random java.lang.Object java.util.Random All Implemented Interfaces: Serializable Direct Known Subclasses: SecureRandom public class Random extends Object implements Serializable An instance of this class is used to generate a stream of pseudorandom numbers. The class uses a 48-bit seed, which is modified using a linear congruential formula. (See Donald Knuth, The Art of Computer Programming, Volume 2, Section 3.2.1.) If two instances of Random are created with the same seed, and the same sequence of method calls is made for each, they will generate and return identical sequences of numbers. In order to guarantee this property, particular algorithms are specified for the class Random. Java implementations must use all the algorithms shown here for the class Random, for the sake of absolute portability of Java code. However, subclasses of class Random are permitted to use other algorithms, so long as they adhere to the general contracts for all the methods. The algorithms implemented by class Random use a protected utility method that on each invocation can supply up to 32 pseudorandomly generated bits. Many applications will find the random method in class Math simpler to use. Since: JDK1.0 See Also: Math.random(), Serialized Form Constructor Summary Random() Creates a new random number generator. Random(long seed) Creates a new random number generator using a single long seed: Method Summary protected int next(int bits) Generates the next pseudorandom number. boolean nextBoolean() Returns the next pseudorandom, uniformly distributed boolean value from this random number generator's sequence. void nextBytes(byte[] bytes) Generates random bytes and places them into a user-supplied byte array. double nextDouble() Returns the next pseudorandom, uniformly distributed double value between 0.0 and 1.0 from this random number generator's sequence. float nextFloat() Returns the next pseudorandom, uniformly distributed float value between 0.0 and 1.0 from this random number generator's sequence. double nextGaussian() Returns the next pseudorandom, Gaussian ("normally") distributed double value with mean 0.0 and standard deviation 1.0 from this random number generator's sequence. int nextInt() Returns the next pseudorandom, uniformly distributed int value from this random number generator's sequence. int nextInt(int n) Returns a pseudorandom, uniformly distributed int value between 0 (inclusive) and the specified value (exclusive), drawn from this random number generator's sequence. long nextLong() Returns the next pseudorandom, uniformly distributed long value from this random number generator's sequence. void setSeed(long seed) Sets the seed of this random number generator using a single long seed. Methods inherited from class java.lang.Object clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait Fase 2 Consiste nel calcolo analitico degli upper bound degli algoritmi (asintotici, a costi uniformi, in funzione della dimensione dell’input, worst case). Un volta invidivuata una funzione di costo f(n) per un algoritmo, effettuare la verifica incrociata con la corrispondente tabella di costi T(n), calcolata nella Fase 1. In particolare è interessante verificare se il rapporto f(n)/T(n), al crescere di n, converge verso una costante. Sebbene sia possibile svolgere tale verifica in molti modi, è consigliabile modificare il codice Java sviluppato nella Fase 1, per includere anche la stampa dei rapporti f(n)/T(n). // Classe java di riferimento per l’Esercitazione in laboratorio del 26-4-2005 public class Esercitaz1 { /* * ordina l'array a con l'algoritmo di Insertion Sort */ public static void insertionSort(int[] a) { for(int i = 0; i < a.length; i++) { int tmp = a[i]; int j; for(j = i; (j > 0) && (tmp < a[j-1]); j--) a[j] = a[j - 1]; a[j] = tmp; } } /* * metodo che restituisce, dato un intero n, * il più grande intero < n che è divisore di n * * se tale intero è 1 allora n è numero primo */ public static long maxDivisore(long n) { if(n % 2 == 0) return 2; long r = (long)Math.sqrt(n); long d = 3; while(d <= r) { if(n % d == 0) return d; d += 2; } return 1; } /* * restituisce l'n-esimo numero primo * * ennesimoPrimo(1) restituisce 2, per * convenzione */ public static long ennesimoPrimo(long n) { if(n == 1) return 2; // convenzione if(n == 2) return 3; long i = 3; long contaPrimi = 2; while(contaPrimi < n) { i += 2; if(maxDivisore(i) == 1) contaPrimi++; } return i; } }