Programming concepts 1. Programming Concept 1.1. List and pointers 1.2. Abstract data type 1.3. Costruzione ed analisi di una classe Java per l'implementazione delle operazioni su una lista lineare realizzata mediante array 1.3.1. Inserimento in testa, in coda, in un punto intermedio della lista; cancellazione di un elemento 1.3.2. Confronto con java.util.ArrayList https://docs.oracle.com/javase/8/docs/api/java/util/ArrayList.html 1.3.3. Problema del dimensionamento dinamico dell'array sottostante alla lista 1.4. Costruzione ed analisi di una classe Java per l'implementazione delle operazioni su una lista concatenata realizzata mediante allocazione dinamica dei nodi LinkedListVsLinearListStudent.pdf 1.4.1. Inserimento in testa, in coda, in un punto intermedio della lista; cancellazione di un elemento 1.4.2. Confronto con java.util.LinkedList https://docs.oracle.com/javase/8/docs/api/java/util/LinkedList.html 1.4.3. Ripasso sull’uso di Javadoc (http://www.oracle.com/technetwork/java/javase/documentation/index-137868.html e http://stackoverflow.com/questions/8493352/how-to-make-documentation-withnetbeans-and-javadoc ) 1.4.4. Creazione di una libreria e uso di una libreria in un progetto NetBeans: https://netbeans.org/kb/docs/java/javase-intro.html 1.4.5. Deployment di applicazioni mediante file compressi jar: https://netbeans.org/kb/articles/javase-deploy.html Esercitazione 1: costruire il package it.cognome.ADT con le classi MyArrayList e MyLinkedList che implementano l’interfaccia MyList. In particolare la classe MyArrayList implementa anche i metodi privati squeeze() e enlarge() per la gestione della dimensione dell’array. Creare anche la documentazione in formato Javadoc e creare un file di libreria in formato jar. 1.4.6. Ripasso sull’uso delle eccezioni: http://www.tutorialspoint.com/java/java_exceptions.htm http://howtodoinjava.com/2013/04/04/java-exception-handling-best-practices/ https://docs.oracle.com/javase/tutorial/essential/exceptions/index.html 1.4.7. La classe Object (rivisitata) Object as Superclass.pdf https://docs.oracle.com/javase/tutorial/java/IandI/objectclass.html Clonazione di oggetti Uguaglianza tra oggetti Hashcode di oggetti Materiali: Object as Superclass.pdf Esercitazione 2: Scrivere la classe: public class Persona implements Cloneable { private String nome; private String cognome; private Date dataN; … Con i metodi @Override public String toString() {… @Override public int hashCode() {… @Override public boolean equals(Object o) {… @Override public Object clone() throws CloneNotSupportedException {… //clonazione profonda Scrivere anche la classe: public class Studente extends Persona { private static int contatore = 0; private final int matricola; …. Ridefinendo opportunamente i metodi toString, hashCode, equals, clone Esercitazione 3: estendere il package it.cognome.ADT aggiungendo i seguenti punti: 1. Nell’interfaccia MyList: a. Metodo equals() b. Metodo hashCode() 2. Nelle classi (entrambe) MyArrayList e MyLinkedList: Implementare equals(), hashCode(), toString(), clone(). Per l’implementazione riferirsi alla documentazione delle API di Java: equals(): https://docs.oracle.com/javase/8/docs/api/java/util/AbstractList.html#equalsjava.lang.Objectpublic boolean equals(Object o) Compares the specified object with this list for equality. Returns true if and only if the specified object is also a list, both lists have the same size, and all corresponding pairs of elements in the two lists are equal. (Two elements e1 and e2 are equal if (e1==null ? e2==null : e1.equals(e2)).) In other words, two lists are defined to be equal if they contain the same elements in the same order. This implementation first checks if the specified object is this list. If so, it returns true; if not, it checks if the specified object is a list. If not, it returns false; if so, it iterates over both lists, comparing corresponding pairs of elements. If any comparison returns false, this method returns false. If either iterator runs out of elements before the other it returns false (as the lists are of unequal length); otherwise it returns true when the iterations complete. hashCode(): https://docs.oracle.com/javase/8/docs/api/java/util/List.html#hashCode-int hashCode() Returns the hash code value for this list. The hash code of a list is defined to be the result of the following calculation: int hashCode = 1; for (E e : list) hashCode = 31*hashCode + (e==null ? 0 : e.hashCode()); This ensures that list1.equals(list2) implies that list1.hashCode()==list2.hashCode() for any two lists, list1 and list2, as required by the general contract of Object.hashCode(). clone(): https://docs.oracle.com/javase/8/docs/api/java/util/ArrayList.html#clone-public Object clone() Returns a shallow copy of this ArrayList instance. (The elements themselves are not copied.) Overrides: clone in class Object Returns: a clone of this ArrayList instance toString(): https://docs.oracle.com/javase/8/docs/api/java/util/AbstractCollection.html#toString-public String toString() Returns a string representation of this collection. The string representation consists of a list of the collection's elements in the order they are returned by its iterator, enclosed in square brackets ("[]"). Adjacent elements are separated by the characters ", " (comma and space). Elements are converted to strings as byString.valueOf(Object). Overrides: toString in class Object Returns: a string representation of this collection Nota: le classi MyArrayList e MyLinkedList definite nel package it.cognome.ATD hanno come tipo base oggetti di tipo String. Sostituire il tipo base con Studente (definito nell’esercitazione 2). Nelle prossime lezioni vedremo come realizzare classi generiche. 1.4.8. Autoboxing e classi wrapper. Materiali: Introduzione a OOP con Java parte 2 – par. 8.7 1.4.9. Confronto tra oggetti Materiali: Introduzione a OOP con Java parte 2 – par. da 11.7 a 11.10 Esercitazione 4: Data la classe Persona dell’esercitazione 2, definire un ordinamento naturale in base all’età (confrontare le date di nascita, sfruttando il compareTo() della classe java.util.Date). Per la classe Persona definire anche due ordinamenti aggiuntivi, mediante due nested inner classes di tipo Comparator. Il primo ordinamento è LexicographicalOrder che ordina le persone in base al cognome e, a parità di cognome, in base al nome. Il secondo ordinamento aggiuntivo è ShortestFullNameOrder che ordina le persone in base al numero complessivo di caratteri del cognome e del nome (è “minore” la persona che ha un numero minore complessivo di caratteri tra nome e cognome). La classe Studente eredita gli ordinamenti definiti per la classe Persona e in aggiunta introduce un ordinamento mediante un Comparator chiamato theYoungerTheBetter che ordina gli studenti in base all’età e a parità d’età li ordina in base al numero di matricola. Testare gli ordinamenti creando una lista di Persona e una lista di Studenti (usando le liste delle API di Java) ed effettuare gli ordinamenti utilizzando il metodo Collections.sort(List<T> list, Comparator<? super T> c). Dopo aver ridefinito il tipo base di MyLinkedList (e analogamente di MyArrayList) in Persona oppure in Studente, definire un metodo nella classe MyLinkedList (e analogamente in MyArrayList) chiamato sort che implementa l’ordinamento naturale della lista (richiamando il compareTo() degli oggetti di cui la lista è composta). Ad esempio: MyList lista = new MyLinkedList(); lista.add(new Persona("Maria", "De Zen", "31/02/1970")); lista.add(new Persona("Piero", "Angela", "23/02/1935")); //altri add… lista.sort();//ordina la lista in base all’ordinamento naturale – la lista di partenza è ordinata Definire un metodo nella classe MyLinkedList (e analogamente in MyArrayList) chiamato sort(Comparator<T> c) che accetta in input un oggetto di tipo Comparator<Persona> che permette di usare gli ordinamenti aggiuntivi LexicographicalOrder e ShortestFullNameOrder. Ad esempio: lista.sort(new Persona.LexicographicalOrder()); //ordina la lista usando l’ordinamento lessicografico Nota: per implementare l’algoritmo di ordinamento utilizzare uno degli algoritmi di ordinamento visti negli anni presedenti (ad esempio: insertion sort, bubble sort, etc.). Ad esempio, nei seguenti link si trovano esempi di utilizzo di compareTo() e di Comparator per implementare algoritmi di ordinamento: https://www.daniweb.com/programming/software-development/threads/347069/insertionsort-method-using-comparable-array http://www.cs.uofs.edu/~mccloske/courses/cmps144/java_comparator_sorting.html 1.5. Queues 1.5.1. FIFO concept: https://en.wikipedia.org/wiki/Queue_(abstract_data_type) 1.5.2. Interfaccia Coda (accesso FIFO) https://docs.oracle.com/javase/8/docs/api/java/util/Queue.html boolean offer(E e) Inserts the specified element into this queue if it is possible to do so immediately without violating capacity restrictions. When using a capacity-restricted queue, this method is generally preferable toadd(E), which can fail to insert an element only by throwing an exception. Parameters: e - the element to add Returns: true if the element was added to this queue, else false E poll() Retrieves and removes the head of this queue, or returns null if this queue is empty. Returns: the head of this queue, or null if this queue is empty E peek() Retrieves, but does not remove, the head of this queue, or returns null if this queue is empty. Returns: the head of this queue, or null if this queue is empty 1.5.3. Coda circolare: http://www.mathcs.emory.edu/~cheung/Courses/171/Syllabus/8List/array-queue2.html Altri riferimenti: http://www.java-tips.org/java-se-tips/java.lang/linked-list-based-queue-implementation.html http://www.java-tips.org/java-se-tips/java.lang/array-based-queue-implementation-injava.html 1.5.4. Confronto con java.util.LinkedList (che implementa java.util.Queue) 1.6. Stack 1.6.1. LIFO concept: https://en.wikipedia.org/wiki/Stack_(abstract_data_type) 1.6.2. Implementazione con array; operazioni di push e pop http://stackoverflow.com/questions/5552117/implementing-stack-using-linked-lists http://www.vogella.com/tutorials/JavaDatastructures/article.html#list 1.6.3. Confronto con java.util.Stack https://docs.oracle.com/javase/8/docs/api/java/util/Stack.html public E push(E item) Pushes an item onto the top of this stack. This has exactly the same effect as: addElement(item) Parameters: item - the item to be pushed onto this stack. Returns: the item argument. public E pop() Removes the object at the top of this stack and returns that object as the value of this function. Returns: The object at the top of this stack (the last item of the Vector object). Throws: EmptyStackException - if this stack is empty. public E peek() Looks at the object at the top of this stack without removing it from the stack. Returns: the object at the top of this stack (the last item of the Vector object). Throws: EmptyStackException - if this stack is empty. 1.7. Code particolari 1.7.1. Interfaccia java.util.Deque https://docs.oracle.com/javase/8/docs/api/java/util/Deque.html 1.7.2. Classe java.util.ArrayDeque https://docs.oracle.com/javase/8/docs/api/java/util/ArrayDeque.html 1.7.3. Coda di Priorità java.util.PiriorityQueue<> https://docs.oracle.com/javase/8/docs/api/java/util/PriorityQueue.html http://docs.oracle.com/javase/tutorial/collections/implementations/queue.html http://examples.javacodegeeks.com/core-java/util/priorityqueue/java-utilpriorityqueue-example/ Esercitazione 5: Progetto “Pronto soccorso”. Un esempio d'uso di code con priorità. Uso di java.util.PriorityQueue per la gestione di un pronto soccorso in base al codice d'urgenza. 1.1. Concetto di mappa e di set 1.1.1. Rivedere gli esempi sulle mappe dell'anno precedente (introduzione a OOP con Java parte 1 paragrafo 5.6) 1.1.2. Discussione dell’esempio tech-support-complete (dal libro Object First with Java) 1.1.3. http://www.mkyong.com/java/how-to-use-hashmap-tutorial-java/ 1.1.4. Concetto di Hash Table: documento HashTable.pdf 1.1.5. java.util.Map<K,V> 1.1.6. java.util.HashMap<K,V> 1.1.7. Esempi d'uso di HashMap 1.1.8. ADT Set: concetto e esempi d'uso 1.1.9. java.util.Set<E> 1.1.10. java.util.HashSet<E> 1.1.11. Esercitazione 6: Scrivere un programma java che permetta di gestire una rubrica telefonica. La lista dei contatti è realizzata mediante una HashMap in cui le chiavi sono i numeri di telefono e i valori sono oggetti di tipo Persona. Modificare la classe Persona in modo da inserire anche i campi telefono e email (entrambi di tipo String). Fase1: Realizzare i metodi per: 1. L’inserimento di una coppia <telefono, Persona> 2. La cancellazione di una coppia <telefono, Persona> 3. La ricerca di una Persona di cui si conosce il numero di telefono 4. La ricerca del numero di telefono di una Persona di cui si conosce il Nome e Cognome 5. La stampa di tutti i contatti ordinata in ordine lessicografico Fase 2: strutturare la rubrica nel seguente modo: 6. Creare la classe Contatto con i campi ID (intero ad auto-incremento), cognome (String), nome (String) , telefono (String) , email (String). Per la classe Contatto fare l’override di equals(), hashCode(), toString(), compareTo() [ordinamento naturale lessicografico prima sul cognome e poi, a parità di cognome, sul nome], clone() (deep copy o shallow copy?). Creare anche due Comparator come classi static nested nella classe Contatto: Contatto.OrderByPhoneNumber e Contatto.OrderByEmail. 7. Creare la classe Rubrica con al suo interno: Una LinkedList di tutti i contatti: contatti Una HashMap: indicePerNumero, Una HashMap: indicePerNome Una HashMap: indicePerCognome. Queste HashMap contengono le coppie <numero, Contatto>, <nome, Contatto > e <cognome, Contatto > rispettivamente e permettono di creare tre indici per la ricerca veloce per numero, per nome, per cognome. Ogni volta che si inserisce un nuovo contatto nella rubrica si crea un nuovo oggetto di tipo Contatto e si fanno gli inserimenti nella LinkedList contatti e nelle HashMap di indicizzazione: in una si inserisce la coppia <numero, riferimento al Contatto> e nelle altre la coppia <nome, riferimento allo stesso Contatto> e <cognome, riferimento allo stesso Contatto>. Attenzione: una HashMap non può contenere chiavi duplicate e dunque per gestire gli indici occorre tener presente che più contatti potrebbero avere lo stesso cognome, o lo stesso nome, o, addirittura, lo stesso numero di telefono. Per gestire mappe con chiavi duplicate si può ricorrere a una struttura come la seguente: http://stackoverflow.com/questions/1062960/map-implementation-with-duplicatekeys /* Adattato da http://stackoverflow.com/questions/18922165/how-to-includeduplicate-keys-in-hashmap */ package esempiohashmap; import java.util.LinkedList; import java.util.HashMap; import java.util.Iterator; /** * * @author Gennaro */ public class MultipleKeysMap { HashMap<String, LinkedList<String>> hashMap; public MultipleKeysMap() { hashMap = new HashMap<>(); } private void addValues(String key, String value) { //se key è presente nella mappa restituisco la lista di oggetti con la stessa key //altrimenti restituisco null LinkedList tempList = hashMap.get(key); if (tempList == null) {//devo creare la lista e inserirvi il valore tempList = new LinkedList(); tempList.add(value); } else {//la lista esiste, devo solo aggiungervi il valore tempList.add(value); } //inserisco la lista aggiornata in corrispondenza della chiave hashMap.put(key, tempList); } public static void main(String... arg) { // Add data with duplicate keys MultipleKeysMap testMap = new MultipleKeysMap(); testMap.addValues("A", "a1"); testMap.addValues("A", "a2"); testMap.addValues("B", "b"); // View data. Iterator it = testMap.hashMap.keySet().iterator(); LinkedList<String> tempList = null; while (it.hasNext()) { String key = it.next().toString(); tempList = testMap.hashMap.get(key); if (tempList != null) { for (String value : tempList) { System.out.println("Key : " + key + " , Value : " + value); } } } } } Nel nostro caso gli indici dovranno essere realizzati mediante mappe del tipo: Map<String, LinkedList<Contatto>> indicePerNome = new HashMap<>() 8. Gestire i casi di cancellazione di un Contatto, di modifica del nome (o cognome) e del numero di telefono. 9. Fornire anche il metodo che permette di fare la ricerca “globale” indifferentemente tramite numero o tramite nome. Questo metodo accetta anche stringhe parziali “parte del nome o del cognome” oppure “parte del numero” e nel caso di più corrispondenze fornisce la lista di Contatti… 1.2. Recursion 1.2.1. Scrittura di programmi ricorsivi: calcolo del fattoriale, stringhe palindrome; stampa cartelle del file system (esempi NetBeans: fileTreeDemo1 e fileTreeDemo2). Analisi delle prestazioni di un algoritmo ricorsivo Realizzazione di chiamate ricorsive (activation record sullo stack) Risorsa: http://home.deib.polimi.it/caglioti/lez5.pdf (funzioni_ricorsive.pdf) Esempi: torre di Hanoi http://en.wikipedia.org/wiki/Tower_of_Hanoi http://www.vogella.com/tutorials/JavaAlgorithmsTowersOfHanoi/article.html http://simpledeveloper.com/towers-of-hanoi/ http://www.mathcs.emory.edu/~cheung/Courses/170/Syllabus/13/hanoi.html Esercizi sulla Ricorsione: Emulazione del programma tree della cmd di windows sulla base della risorsa: “Esercizi sulla Ricorsione.pdf” 1.3. Grafi Studiare quanto riportato nella dispensa “Grafi e programmazione.pdf”