Programmiertechnik II Klausur WS 2016/17 Angewandte Informatik Bachelor Name Matrikelnummer Aufgabe Punkte Aufgabe Punkte 1 4 6 18 2 12 7 18 3 12 8 12 4 12 9 12 5 20 Summe 120 Zwischensumme 60 Note Prof. Dr. O. Bittel, HTWG Konstanz WS 2016/17 1/12 Aufgabe 1 (4 Punkte) Beschreiben Sie mit einem Speicherbelegungsbild, was durch die folgende main-Funktion geleistet wird: class Point { private int x; private int y; public Point(int x, int y) { this.x = x; this.y = y; } public static void main(String[] a) { Point[] p = new Point[3]; p[0] = new Point(1,2); p[1] = p[0]; } } Prof. Dr. O. Bittel, HTWG Konstanz WS 2016/17 2/12 Aufgabe 2 (12 Punkte) Für die Knoten einer linear verketteten Liste ist folgende Klasse definiert: class Node { int data; Node next; // Referenz auf nächsten Knoten Node(int x, Node n) {data = x; next = n;} } Gegeben ist folgendes Speicherbelegungsbild. a ist ein Feld (grau unterlegter Speicherplatz) von linear verketteten Listen. a) Schreiben Sie genau eine Java-Anweisung, die den Typ von a definiert und den grau unterlegten Speicherplatz anlegt. Node[] a = new Node[3]; b) Schreiben Sie eine Folge von Java-Anweisungen (keine Schleife!), die die im Speicherbelegungsbild gezeigte Datenstruktur aufbaut. Die Java.Anweisung aus a) kann vorausgesetzt werden. a[0] a[0] a[0] a[2] = = = = new new new new Node(7, Node(3, Node(5, Node(1, null); a[0]); a[0]); null); c) Schreiben Sie mit Hilfe von Schleifen ein Programmstück, das alle Daten der abgebildeten Datenstruktur ausgibt. for (Node p : a) for (Node q = p; q != null; q = q.next) println(q.data); Prof. Dr. O. Bittel, HTWG Konstanz WS 2016/17 3/12 Aufgabe 3 (12 Punkte) java.util.Arrays bietet u.a. die Methode static boolean equals(Object[] a, Object[] b) mit folgender Spezifikation an: This method returns true if the two specified arrays of Objects are equal to one another. The two arrays are considered equal if both arrays contain the same number of elements, and all corresponding pairs of elements in the two arrays are equal. Two objects e1 and e2 are considered equal if (e1==null ? e2==null : e1.equals(e2)). In other words, the two arrays are equal if they contain the same elements in the same order. Also, two array references are considered equal if both are null. a) Was bedeutet Kovarianz von Feldern? Falls A <: B, dann ist A[ ] <: B[ ]. b) Welche Parameter dürfen beim Aufruf von equals übergeben werden? a und b dürfen beliebige Felder sein. c) Was gibt folgendes Programm auf die Konsole aus? Integer[] a = new Integer[]{1, 2}; Double[] b = new Double[]{1.0, 2.0}; Object[] c = new Integer[]{1, 2}; System.out.println(a.equals(c)); System.out.println(Arrays.equals(a,b)); System.out.println(a == c); System.out.println(Arrays.equals(a,c)); Prof. Dr. O. Bittel, HTWG Konstanz WS 2016/17 // // // // false false false true 4/12 Aufgabe 4 QuickSort mit 3-Median-Strategie (12 Punkte) Das 11-elementige Feld a = {5, 15, 2, 17, 2, 1, 3, 7, 4, 6, 10} wird mit Quicksort mit 3-MedianStrategie sortiert. Außerdem ist Quicksort so modifiziert, dass Teilfelder mit genau 2 Elementen mit einem einfachen Vertauschungsschritt sortiert werden. Beschreiben Sie, wie sich das Feld a beim Sortieren ändert. Benutzen Sie eine tabellenartige Darstellung wie in der Vorlesung. Geben Sie außerdem die Aufrufstruktur von Quicksort an. 5 15 2 10 4 3 17 2 3 2 1 1 2 3 2 2 1 2 2 4 3 3 3 4 17 5 5 15 7 17 6 6 6 Prof. Dr. O. Bittel, HTWG Konstanz 7 4 6 10 5 15 4 2 3 10 1 4 1 10 6 17 17 15 17 15 17 7 10 15 17 10 7 7 10 7 10 WS 2016/17 5/12 Aufgabe 5 Linear verkettete Liste (20 Punkte) Eine soll eine Klasse für linear verkette Listen realisiert werden, wobei eine Referenz auf den Anfang begin und eine Referenz auf das Ende end der Liste gespeichert wird. Die Knoten sollen Strings als Daten enthalten. Lösen Sie folgende Aufgaben. Die geforderten Methoden können direkt in die Klassendefinition auf der nächsten Seite geschrieben werden. Achten Sie dabei auf Sonderfälle. a) addFront(s) fügt den String s am vorderen Ende der Liste ein. b) removeFront() löscht das Element am vorderen Ende der Liste und liefert true bei Erfolg zurück. c) add(s) fügt den String s am hinteren Ende der Liste ein. Die Methode muß eine Laufzeit von O(1) haben. d) remove() löscht das Element am hinteren Ende der Liste und liefert true bei Erfolg zurück. e) addAll(l) fügt die Liste l am hinteren Ende der Liste ein. f) Wie muß die Methode add verändert werden, so dass verkettete Aufrufe möglich sind? l.add("dies").add("ist").add("ein").add("Test"); public List add(String w) { // Code wie bei alter Methode add: // ... return this; } Prof. Dr. O. Bittel, HTWG Konstanz WS 2016/17 6/12 public class List { static private class Node { private String str; private Node next; private Node(Node p, String s) {this.str = s; this.next = p;} } private Node begin, end; public List() { begin = end = null; } public void addFront(String s) { if (begin == null) begin = end = new Node(null, s); else begin = new Node(begin, s); } public boolean removeFront() { if (begin == null) return false; begin = begin.next; if (begin == null) end = null; return true; } public void add(String s) { if (begin == null) begin = end = new Node(null, s); else { end.next = new Node(null, s); end = end.next; } } public boolean remove() { if (begin == null) return false; if (begin == end) { begin = end = null; return true; } Node p = begin; while (p.next != end) p = p.next; p.next = null; end = p; return true; } public void addAll(List l) { for (Node p = l. begin; p!= null; p = p.next) add(p.str); } Prof. Dr. O. Bittel, HTWG Konstanz WS 2016/17 7/12 Aufgabe 6 Bäume (18 Punkte) Die Klasse Tree auf der folgenden Seite realisiert Bäume mit int-Daten in jedem Knoten und einer beliebigen Anzahl von Kindern. root ist die Wurzel des Baums. In der Abbildung (a) und (b) sind zwei Beispielbäume gezeigt. Ergänzen Sie die Klassendefinition um folgende Methoden: a) Schreiben Sie eine Methode build, die den in (b) gezeigten Baum aufbaut. b) Die Methode sum gibt die Summe aller Integerzahlen im Baum zurück. Beim in (a) abgebildeten Baum ist die Summe 31. sum ruft die private Methode sumR auf, die den Baum rekursiv durchläuft. Schreiben Sie die Methode sumR. c) Die Methode collect gibt die Liste aller Integerzahlen im Baum zurück. collect ruft die private Methode collectR auf, die den Baum rekursiv durchläuft und alle Zahlen aufsammelt. Schreiben Sie die Methode collectR. d) Welche Liste gibt Ihre Methode collect für den in (a) gezeigten Baum zurück? 1, 6, 2, 3, 1, 3, 4, 1, 2, 2, 1, 5 Prof. Dr. O. Bittel, HTWG Konstanz WS 2016/17 8/12 class Tree { private static class Node { int data; List<Node> children; Node(int d) { data = d; children = new LinkedList<>(); } } private Node root; public void build() { root = new Node(5); root.children.add(new Node(1)); root.children.add(new Node(2)); } public int sum() { if (root == null) return 0; else return sumR(root); } private int sumR(Node p) { int s = p.data; for (Node q : p.children) { s += sumR(q); } return s; } public List<Integer> collect() { List<Integer> l = new LinkedList<>(); collectR(root, l); return l; } private void collectR(Node p, List<Integer> l) { for (Node q : p.children) { collectR(q, l); } l.add(p.data); } } Prof. Dr. O. Bittel, HTWG Konstanz WS 2016/17 9/12 Aufgabe 7 Java-Collections (18 Punkte) Die Klasse RaumVerwaltung verwaltet Räume und die darin stattfindenden Lehrveranstaltungen. Die Klasse verwendet dazu eine Map, die jedem Raum eine Menge der darin stattfindenden Lehrveranstaltungen zuordnet. Räume und Lehrveranstaltungen werden über ihren Namen vom Typ String identifiziert. a) Schreiben Sie eine Methode insert(r,lv), die in der Raumverwaltung speichert, dass die Lehrveranstaltung lv im Raum r stattfindet. Falls der Raum noch nicht existiert, dann muss er neu angelegt werden. b) Schreiben Sie eine Methode getLVen(r), die für den Raum r alle in ihm stattfindenden Lehrveranstaltungen zurückliefert. Achten Sie darauf, dass Ihre Methode die gewünschten Daten „direkt“ (d.h. ohne Schleife) aus der Map abliest. c) Schreiben Sie eine Methode getRaeume(lv), die für die Lehrveranstaltung lv alle Räume zurückliefert, in der lv stattfindet. Hinweis: hierfür ist eine Schleife notwendig. d) Schätzen Sie die Laufzeiten der Methoden getLVen und getRaueme mit Hilfe der O-Notation ab. Gehen Sie davon aus, dass die Raumverwaltung n Räume und m Lehrveranstaltungen enthält und führen Sie eine Worst-Case-Betrachtung durch. getLVen: T(n,m) = O(log(n)). getRaueme: T(n,m) = O(n (log(n) + log(m))). class RaumVerwaltung { private Map<String, Set<String>> meineLVen = new TreeMap<>(); public void insert(String raum, String lv) { if (!meineLVen.containsKey(raum)) meineLVen.put(raum, new TreeSet<>()); meineLVen.get(raum).add(lv); } public Set<String> getLVen(String raum) { return meineLVen.get(raum); } public Set<String> getRaeume(String lv) { Set<String> meineRaeume = new TreeSet<>(); for (Map.Entry<String, Set<String>> entry : meineLVen.entrySet()) { if (entry.getValue().contains(lv)) meineRaeume.add(entry.getKey()); } return meineRaeume; } } Prof. Dr. O. Bittel, HTWG Konstanz WS 2016/17 10/12 Aufgabe 8 Subtyping (12 Punkte) Es werden folgende Variablen definiert, wobei die Initialisierungen weggelassen sind. Collection<Double> colDb; Collection<Number> colNb; Collection<Integer> colInt; Collection<Object> colObj; List<String> listStr; Set<Integer> setInt; List<Object> listObj; a) Geben Sie in folgender Tabelle für jeden Aufruf an, ob er korrekt ist („+“) oder ob er nicht korrekt ist („-“). Falsche Antworten geben Abzüge! listStr.containsAll(colNb); colInt.addAll(colNb); listStr.removeAll(colObj); colNb.addAll(setInt); listObj.add(colInt); setInt.addAll(colInt); colDb.containsAll(setInt); listObj.addAll(colDb); colDb.addAll(setInt); + + + + + + + - b) Die statische Methode copy kopiert die Liste src in die Liste dest. static <T> void copy(List<? super T> dest, List<? extends T> src) Geben Sie in folgender Tabelle für jeden Aufruf an, ob er korrekt ist („+“) oder ob er nicht korrekt ist („-“). Falsche Antworten geben Abzüge! Collections.copy(listStr, listObj); Collections.copy(colObj, listObj); Collections.copy(listObj, listStr); Prof. Dr. O. Bittel, HTWG Konstanz + WS 2016/17 11/12 Aufgabe 9 Java 8 (12 Punkte) Gegeben sind folgende Interfaces aus der Java-API (Schnittstellen sind leicht vereinfacht): Funktionales Interface Abstrakte bzw. default-Methode Beschreibung Predicate<T> boolean test(T t) Predicate<T> and( Predicate<T> p) Predicate<T> or( Predicate<T> p) Predicate<T> p negate() 1-stelliges Prädikat logisches Und logisches Oder logische Negation BiPredicate<T, U> boolean test(T t, U u) 2-stelliges Prädikat UnaryOperator<T> T apply(T t) 1-stelliger Operator vom Typ T → T BinaryOperator<T> T apply(T t, T u) 2-stelliger Operator vom Typ T × T → T Interface Default-Methode Beschreibung Collection<T> boolean removeIf( Predicate<T> p ) Entfernt aus der Collection jedes Element x, für das p(x) zutrifft. List<T> void replaceAll(UnaryOperator<E> f) Ersetzt in der Liste jedes Element x durch f(x). a) Gegeben ist eine Lambda-Funktion ggT, die den größten gemeinsamen Teiler zweier ganzer Zahlen bestimmt. Definieren Sie mit Hilfe von ggT ein zweistelliges Prädikat istTeilerFremd, das prüft, ob zwei ganze Zahlen teilerfremd sind. Zwei Zahlen sind teilerfremd, wenn sie außer 1 keinen gemeinsamen Teiler haben. BinaryOperator<Integer> ggT = ...; BiPredicate<Integer, Integer> istTeilerFremd = (n, m) -> ggT.apply(n,m) == 1; b) Schreiben Sie einen replaceAll-Aufruf, der jede gerade Zahl in der Liste intList quadriert. List<Integer> intList = Arrays.asList(5, 4, 3, 8, 6, 9); intList.replaceAll(n -> n%2 == 0 ? n*n : n); c) Schreiben Sie einen removeIf-Aufruf, der in einer String-Liste strList alle Strings mit kleinem Anfangsbuchstaben löscht. Hinweis: charAt(int i) liefert das i-te Zeichen in einem String. List<String> strList = new LinkedList<>(Arrays.asList("auch", "ein", "Test")); strList.removeIf(s -> 'a' <= s.charAt(0) && s.charAt(0) <= 'z'); d) Gegeben ist ein einstelliges Prädikat isNotPrime, das prüft ob eine Zahl keine Primzahl ist. Definieren Sie mit Hilfe der logisches Operationen aus Predicate ein 1-stelliges Prädikat myPred, das prüft, ob eine Zahl eine Primzahl und größer oder gleich 100 ist. Predicate<Integer> isNotPrime = ...; Predicate<Integer> myPred = isNotPrime.negate().and(n -> n>= 100); Prof. Dr. O. Bittel, HTWG Konstanz WS 2016/17 12/12