• Keine Ergebnisse gefunden

6.0 Arbeiten mit Objekten und Klassen

N/A
N/A
Protected

Academic year: 2022

Aktie "6.0 Arbeiten mit Objekten und Klassen"

Copied!
147
0
0

Wird geladen.... (Jetzt Volltext ansehen)

Volltext

(1)

252-0027

Einführung in die Programmierung

6.0 Arbeiten mit Objekten und Klassen

Thomas R. Gross

Department Informatik ETH Zürich

Copyright (c) Pearson 2013 and Thomas Gross 2020,2021

1

(2)

Übersicht

6.1 Stil und Konventionen

§ Hinweise (und Regeln) für verständliche Programme

§ Teil 1: Nicht vollständig – später erweitert

6.2 Datenstrukturen mit Verknüpfungen 6.3 Entwurf von (abgekapselten) Klassen 6.4 Programmbeispiel und –ausführung 6.5 (Mehr) Optionen für Sichtbarkeit

Copyright (c) Pearson 2013 and Thomas Gross 2016,2017,2019. 2

(3)

6.1 Stil und Konventionen

Hinweise für verständliche Programme

§ Einfache Regeln

§ Setzen Eclipse/IDE voraus

3

(4)

Hinweise und Regeln

§ Nicht strikt

§ Ausnahmen können sinnvoll sein.

§ Aber man sollte sich wirklich gut überlegen, ob eine Ausnahme gerechtfertigt ist.

§ Was ist das Ziel solcher (aller) Regeln?

4

(5)

§ Programme sollen gut lesbar sein.

§ Wichtige Leser sind

§ Development team / Maintenance team

§ Andere Programmierer (die mit der Problemstellung vertraut sind)

§ Der Compiler

§ Möglichst kompakt («Don’t repeat yourself»)

6

(6)

Programm Layout

§ Nicht mehr als 100 Zeichen pro Zeile

§ Neue Zeile für jede Anweisung

§ Keine unnötigen neuen Zeilen (neue Zeile wenn alte Zeile nicht ausreicht oder zur Trennung von (unabhängigen) Aktionen)

§ Manche Gruppen empfehlen < 80 Zeichen pro Zeile

§ Aufeinanderfolgende Anweisungen untereinander

int x = 10;

int y = x + 1;

§ Gleich weit eingerückt 7

(7)

Layout

§ Jeder neue Block wird eingerückt

§ 2, 4, 6 (selten 8) Leerzeichen

8

(8)

Beispiel

if (a == 1) {

System.out.println(a);

x = 3;

b = b + x;

} else if (a == 2) { System.out.println(a);

x = 6;

y = y + 10;

b = b + x;

} else { // a == 3

System.out.println(a);

x = 9;

b = b + x;

}

if (a == 1) {

System.out.println(a);

x = 3;

b = b + x;

} else if (a == 2) {

System.out.println(a);

x = 6;

y = y + 10;

b = b + x;

} else { // a == 3

System.out.println(a);

x = 9;

b = b + x;

}

(9)

«White Space»: Zwischenraum & Leerzeichen

§ Kosten wenig – können helfen

§ Einrücken von Blöcken

§ Trennen Keywords

§ for▢(int i = 1; …) oder while▢(true)

§ for(int i=1; …) oder while(true)

§ Aber

§ myMethod(params) oder myMethod()

§ myMethod▢(params) oder myMethod▢▢▢()

§ Methodenaufrufe sind so schnell zu erkennen

10

(10)

Leerzeichen

§ Zuweisungsoperator = mit Leerzeichen abgesetzt

§ Keine Leerzeichen nach ( oder vor )

§ Nicht (▢ oder ▢)

11

(11)

«NewLines»/Zeilenumbruch

§ Strukturieren ein Programm

§ Immer vor/nach Methodendeklaration

§ Gilt auch für Konstruktoren …

§ Eine Anweisung per Zeile

§ Anweisungen die eine Gruppe bilden werden durch NewLines abgegrenzt

12

(12)

«NewLines»

§ Schreiben Sie Code der durchsucht werden kann

§ new Operator mit Konstruktor auf eine Zeile, ein Leerzeichen

§ Also new▢Foo(parameter) und nicht new

Foo(parameter)

oder auch nicht new▢▢▢Foo(parameter)

§ Lange Ausdrücke: nach Operator trennen

§ und Rest einrücken

13

a+b+c+d

wenn kein Platz

a+b+

c+d

(13)

Layout

§ Eingeschlossene Blöcke oder Einheiten werden eingerückt

§ 2 oder 4 Leerzeichen (1 vielleicht ok, 8 vielleicht zuviel) if (foo()) {

▢▢x = 1; // ▢ zur Illustration }

§ oder

if (foo()) {

▢▢▢▢x = 1; // ▢ zur Illustration }

§ Zeigen Sie die Struktur des Programms 14

(14)

Verwenden Sie { und }

// Good

if (x < 0) {

computeHead(x);

} else {

colorHead(x);

}

// Not good

if (x < 0) computeHead(x);

15

(15)

Position von { und }

§ Die sich öffnende Klammer { steht in der Zeile, die den neuen Block beginnt

if (foo()) {

nicht

if (foo() { …

§ Die sich schliessende Klammer wird soweit eingrückt wie die Anweisung, die den Block beginnt

16

(16)

§ Dazu gibt es natürlich auch andere Meinungen

§ Vielleicht OK für den Bildschirm, nicht aber für Folien

// Also good

for (int i=0; i<limit; i++) {

// first statement // next statement // last statement }

§ Wählen Sie eine Variante

17

(17)

§ Gleichmässig ist wichtiger als genaue Tab Position

// Also good

for (int i=0; i<limit; i++) { // first statement

// next statement // last statement }

// Not good

for (int i=0; i<limit; i++) {// first statement // next statement

// last statement }

19

(18)

// Not good at all

for (int i=0; i<limit; i++) { // first statement

// next statement

// another statement // last statement }

20

(19)

Verwenden Sie { und } und Einrücken

// Not good

if (x < 0) computeHead(x);

// Really bad if (x < 0)

computeHead(x);

// Good

if (x < 0) {

computeHead(x);

}

21

(20)

Führen Sie den Leser nicht in die Irre!

§ Sie könnten der Leser sein …

if (x < 0)

System.out.println("Less than 0");

foundSmall++;

§ Einige Editoren/IDEs warnen vor obigem Code

// Besser … aber am besten mit { } if (x < 0)

System.out.println("Less than 0");

foundSmall++;

22

(21)

§ Verwenden Sie { und } … aber nicht mehr als nötig

double eps = 0;

while (eps > bound) { n++

eps = findPoint(n);

} {

double approx = 0.0;

double sum = 0.0;

for (int i = 0; i <= 25; i++) { approx += 1.0/Math.pow(n, 2); }

} 23

(22)

Verwenden Sie ( und ) um Klarheit zu verschaffen

// Bad

return a << 8 * n + 1 | 0xFF;

if (jahr % 4 == 0 && jahr % 100 != 0 || jahr % 400 == 0 ){

// Good

return (a << (8 * n) + 1) | 0xFF;

if (((jahr % 4 == 0) && (jahr % 100 != 0)) ||

(jahr % 400 == 0)) { …

24

(23)

Datei Layout

§ Reihenfolge in Datei Name.java

§ Import

§ (Haupt) Klasse (public class Name …)

§ main Methode (wenn vorhanden)

§ andere Methoden

§ ggf. andere Klassen (später mehr)

25

(24)

Klassen

§ Attribute die verändert werden können sind private

§ Zugriff via «getter» und «setter» Methoden

§ Flexibel – kann Darstellung (des Attributes) später ändern

§ Methoden sind zuerst private und bleiben private – es sei denn ein Klient ruft sie auf

§ Dann sind sie public (bis wir weitere Optionen kennen lernen)

§ Klassen sind public wenn es Klienten gibt

26

(25)

Regeln für Namen

27

(26)

§ Nur Buchstaben und Ziffern

§ Keine _, $, etc.

§ Keine Umlaute

§ Klassennamen: MitGrossBuchstaben

§ Methodennamen

§ Wenn möglich mit Verb

§ erster Buchstabe klein insert, remove, drawLine

§ Namen für Variable: beschreibend

§ Kurze Namen für Loopcounter for (int i; …)

28

(27)

Variablennamen

§ Kurze Variablennamen reserviert für Loopcounter

§ D.h. i, j, k usw sollten immer Loopcounter sein

§ Idealerweise im for Statement deklariert

§ for (int i = 0; …; i++) { … }

§ for (double d : measuredTemp) { … }

§ Standard Konvention

§ MyClass für Typen: Klassen und Interfaces

§ MyClass() ist dann der Konstruktor der Klasse

§ myVariable für Attribute, Parameter und Variable (static und local)

§ myMethod() für Methoden

§ MY_CONSTANT für Konstanten (sind final) 29

(28)

Variablennamen

§ Keine Typ/Metainformation im Namen

// Good int i;

int responses;

// Not good

int[] scoreArray;

double doubleNote;

§ Masseinheit soll (wenn relevant) Teil des Names sein

// Good

int refreshIntervalMs;

30

(29)

Variable

§ Deklaration in dem Block in dem Variable gebraucht wird

// Not good int i;

....

for (i = 0; i < weight.length; i++) { ....

}

// Good

for (int i = 0; i < weight.length; i++) { ....

}

32

(30)

Variablen

§ Eine Variable pro Deklaration. Initalisierung nicht vergessen.

// Not good int k, m;

k = ...;

// Good

int k = 100;

int m = 0;

// Also i.O.

int k;

k = ...;

33

(31)

§ Für Parameter gelten die selben Regeln wie für (Methoden- lokale) Variablen

34

(32)

Arrays

§ Obwohl die Java Syntax flexibel ist, verbinden wir die [] mit dem Typ der Arrayelemente

// Good

String[] args;

// Not good

String args[]; // Java akzeptiert das … String▢[] args; // Java akzeptiert das …

§ Der Typ ist "StringArray" – daher die Position für []

35

(33)

Code

36

(34)

Faktorisierung

§ Sie erinnern sich an die Zerlegung einer Zahl in Primzahlen

§ Klasse Factors – Modul für andere Klassen (Programme)

§ Oder die Zerlegung von Polynomen (in der Mathematik)

§ «Faktorisierung» -- Zerlegung in Terme/Teile

§ Idee: keine Überlappung

§ Faktorisierung («factoring») von Code : Herausarbeiten von gemeinsamen/redundanten Anweisungen

§ In der Praxis of Refaktorisierung («refactoring»)

(35)

Faktorisierung für if/else Anweisungen

§ Example:

if (a == 1) {

System.out.println(a);

x = 3;

b = b + x;

} else if (a == 2) {

System.out.println(a);

x = 6;

y = y + 10;

b = b + x;

} else { // a == 3

System.out.println(a);

x = 9;

b = b + x;

System.out.println(a);

b = b + x;

(36)

Faktorisierung für if/else Anweisungen

§ Example:

if (a == 1) {

System.out.println(a);

x = 3;

b = b + x;

} else if (a == 2) {

System.out.println(a);

x = 6;

y = y + 10;

b = b + x;

} else { // a == 3

System.out.println(a);

x = 9;

b = b + x;

System.out.println(a);

x = 3 * a;

b = b + x;

(37)

Faktorisierung für if/else Anweisungen

§ Example:

if (a == 1) {

System.out.println(a);

x = 3;

b = b + x;

} else if (a == 2) {

System.out.println(a);

x = 6;

y = y + 10;

b = b + x;

} else { // a == 3

System.out.println(a);

x = 9;

b = b + x;

System.out.println(a);

x = 3 * a;

if (a == 2) { y = y + 10;

}

b = b + x;

(38)

Boolesche Ausdrücke

if (((x>0) && (y>0)) && (z > 0)) { // block 1

}

// more code

if (((x>0) && (y>0)) && (z >= 0)) { // block 2

}

§ Was ist an diesem Code Beispiel schlecht?

41

(39)

Boolesche Ausdrücke

if (((x>0) && (y>0)) && (z > 0)) { // block 1

}

// more code

if (((x>0) && (y>0)) && (z >= 0)) { // block 2

}

§ Was ist an diesem Code Beispiel schlecht?

§ (x>0) && (y>0) mehrfach berechnet und unübersichtlich 42

(40)

Boolesche Ausdrücke

if (((x>0) && (y>0)) && (z > 0)) { // block 1

} else if (((x>0) && (y>0)) && (z < 0)) { // block 2

} else if (((x>0) && (y>0)) && (z == 0)) { // block 3

}

§ Was ist an diesem Code Beispiel schlecht?

43

(41)

Beispiel -- Faktorisierung

if (((x>0) && (y>0))) { if (z > 0) {

// block 1

} else if (z < 0) { // block 2

} else if (z == 0) { // block 3

} }

44

(42)

Methoden

§ Kurze Methoden sind schneller zu lesen

§ Keine Code Duplikation!

§ Methoden erlauben Wiederverwendung

§ In der Regel nicht mehr als 20-40 Anweisungen pro Methode

§ Es gibt manchmal gute Gründe für Ausnahmen

§ (z.B. switch Statement, geschachtelte if-Statements)

§ Wenn es mehr Anweisungen gibt: separate Methode!

47

(43)

Methoden

§ Kurze Parameterlisten

§ If you have a procedure with ten parameters, you probably missed some. (Alan Perlis Epigrams in Programming)

§ Eine Methode sollte ein Problem/eine Aufgabe lösen

49

§ Kurze Methoden sind schneller zu verstehen

(44)

Methoden

§ Basistyp Parameter sollten nicht (in der Methode) modifiziert werden

§ Jede Methode kann auf jedes Attribut zugreifen: Gefahr die Übersicht zu verlieren

50

(45)

Entwurf von/Aufteilung in Methoden

51

Attribute eines Exemplars

Methode

(46)

Methoden helfen nicht unbedingt

52

Attribute eines Exemplars

Methoden

(47)

Methoden helfen vielleicht

53

Attribute eines Exemplars

Methoden

(48)

Statt

54

(49)

Struktur mit Mehrfachverwendung

55

(50)

Bessere Struktur

§ Andere Methoden

§ Parameter (statt direkter Zugriff auf Attribut)

56

(51)

Manchmal ruft sich eine Methode auf …

57

(52)

Rekursive Methoden

§ Eine Methode f() ist rekursiv, wenn ein Aufruf von f() wieder zu einem Aufruf von f() führen kann

§ f() ist direkt rekursiv wenn der Aufruf von f() im Rumpf von f() auftritt

§ Eine Methode g() ist indirekt rekursiv, wenn der Aufruf von g() zum Aufruf von h() (und dieser zum Aufruf von …) führt, in dem dann g() wieder aufgerufen wird

§ g() à h() à m() à …. à g()

58

(53)

Rekursive Methoden

§ … sind manchmal der beste Weg ein Problem zu lösen

§ … sind Iteration (Schleifen) überlegen

§ ... sind oft kürzer als Schleifen

§ … haben eine einfachere Kontrollstruktur (weniger if-Fälle, z.B.)

§ … kommen mit weniger Variablen aus

§ … haben oft einen einfachen Korrektheitsbeweis

§ Später mehr dazu

§ … und sind in manchen Programmiersprachen der einzige Weg, Wiederholungen auszudrücken

59

(54)

Rekursive Methoden

§ Wir erinnern uns: EBNF erlaubte Rekursion und Iteration

§ Genauso viele Programmiersprachen

§ z.B. Java

60

(55)

Iteration vs. Rekursion

§ Grundidee: Ein Problem verkleinern – bis es einfach zu lösen ist (oder keine weitere Zerlegung möglich ist)

§ Beispiel:

§ Annahme: Wir leben in einer altruistischen Gesellschaft. Wenn jemand uns fragt, so spenden wir 1 Rappen

§ Aufgabe: Wir wollen sFr 1'000.00 für einen guten Zweck sammeln

Quelle: https://upload.wikimedia.org/wikipedia/de/0/00/Einrappen.png 61

(56)

Iteration vs. Rekursion

§ Iterative Lösung:

§ Wir fragen 100'000 Personen und sammeln vom jeder 1 Rappen ein

§ Rekursive Lösung:

§ Wenn uns eine Person um 1 Rappen fragt, so geben wir der Person 1 Rappen, sonst

(d.h. es will jemand mehr als 1 Rappen)

§ Kontaktiere 10 Personen und beauftrage jede, 1/10 des Betrages zu sammeln, der von uns verlangt wird

§ Lege das von diesen Personen gesammelte Geld in eine Schachtel

§ Gebe die Schachtel der Person, die uns gefragt hat

62

(57)

§ Iteration: Das Problem ist in 100'000 Teil-Probleme zerlegt

§ Jedes Teil-Problem ist gleich gross

§ Rekursion: Die Teil-Probleme werden kleiner und kleiner

§ … bis nur noch 1 Rappen gesammelt werden muss

§ (ein kleineres Problem gibt es nicht, 1 Rappen ist die kleinste Münze)

63

(58)

solve(): Eine rekursive Methode (Muster)

Wenn das Problem nicht weiter zerlegt werden kann (minimal ist, Basisfall):

löse Problem direkt (ohne Rekursion) und liefere die Lösung sonst

1. Zerlege Problem in ein oder mehr ähnliche, aber kleinere Teil-Probleme TP1, TP2, …, TPn

2. Rufe rekursiv solve() auf, um die kleineren Teil-Probleme zu lösen (denn diese sind ähnlich): solve(TP1), solve(TP2), … , solve(TPn)

3. Füge die Lösungen der Teil-Probleme (von solve(TPi) geliefert) zusammen um das ursprüngliche Problem zu lösen

4. Liefere die Lösung zum ursprünglichen Problem (an den Aufrufer)

64

(59)

Übung

§ Wir sagen eine ganze positive Zahl N hat die Eigenschaft AZT (alle Ziffern sind Teiler) wenn jede Ziffer von N die Zahl N ohne Rest teilt.

§ Beispiel

§ 124, 128 haben die AZT Eigenschaft

§ 127, 104 haben sie nicht

§ Beobachtung: eine Zahl mit Ziffer 0 hat nie die AZT Eigenschaft

65

(60)

Übung

§ Schreiben Sie ein Programm (eine Methode) die für eine positive ganze Zahl N true zurückgibt, wenn N die AZT Eigenschaft hat.

§ Zur Erinnerung: ob eine Zahl ohne Rest teilt können wir mit dem modulo-Operator % feststellen

§ Die k-te Ziffer erhalten wir durch / 10k (von rechts nach links)

66

(61)

Lösung

public class AZT {

public static void main(String[] args) { System.out.println("124 : " + azt(124));

}

public static boolean azt(int x) {

}

} 67

(62)

68

1 2 4 124 % 1 == 0 ?

124 % 2 == 0 ?

124 % 4 == 0 ?

AZT

(63)

69

1 2 4

124 % 4 == 0 ?

124 % 2 == 0 ?

124 % 1 == 0 ?

AZT

(64)

70

4 3 1

431 % 1 == 0 ?

431 % 3 == 0 ?

431 % 4 == 0 ?

AZT ✘

(65)

Lösung

§ % 10 liefert letzte Ziffer Z

§ Müssen Eingabe Zahl N bereithalten

§ Um zu prüfen ob Z die Zahl N ohne Rest teilt

71

(66)

Lösung

§ % 10 liefert letzte Ziffer Z

§ Müssen Eingabe Zahl N bereithalten

§ Um zu prüfen ob Z die Zahl N ohne Rest teilt

§ Idee: eine Helfer-Methode mit zwei Parametern: die Zahl N und das Residuum (Ziffern die noch nicht untersucht wurden)

§ N wird «weiterreicht» , Residuum wird immer kleiner

§ Helfer-Methode prüft, ob N durch Z ohne Rest teilbar ist

§ Wenn ja: Aufruf von Helfer-Methode mit Residuum \ { Z } 72

(67)

73

(68)

Lösung -- Residuum

§ Residuum: Ziffern die noch nicht untersucht wurden

§ Könnten eine Menge nehmen (alle Ziffern von N)

§ Könnten einen Array nehmen (alle Ziffern von N)

§ Einfach: Division durch 10 «entfernt» letzte Ziffer

§ Residuum: Zahl

§ Müssen Helfer-Methode am Anfang mit Residuum N aufrufen

74

(69)

Lösung

public class AZT {

public static void main(String[] args) { System.out.println("124 : " + azt(124));

}

public static boolean azt(int x) { return azt_helper(x, x);

}

} 75

(70)

azt_helper(int origin, int residuum)

§ Wann sind wir fertig?

§ Wenn alle Ziffern untersucht wurden und Teiler sind

§ Dann hat die Zahl die AZT Eigenschaft

§ Wenn alle Zifferen untersucht wurden: es gibt keine weiteren Ziffern

§ D.h. residuum ist 0

§ (Es wurde immer die letzte Ziffer untersucht)

76

(71)

azt_helper: Eine rekursive Methode

Wenn das Problem nicht weiter zerlegt werden kann (minimal ist, Basisfall):

löse Problem direkt (ohne Rekursion) und liefere die Lösung

public static boolean azt_helper(int origin, int residuum) { if (residuum == 0) {

return true;

}

77

(72)

azt_helper: Eine rekursive Methode

sonst

1. Zerlege Problem in ein oder mehr ähnliche, aber kleinere Teil-Probleme TP1, TP2, …, TPn

2. TP1 : Letzte Ziffer von residuum: Nicht 0 und teilt die Zahl N ohne Rest?

3. TP2 : Übrige Ziffern von residuum

2. Rufe rekursiv azt-helper(...) auf, um das kleinere Teil-Problem TP2 zu lösen (denn dieses ist ähnlich)

3. Füge die Lösungen der Teil-Probleme zusammen um das ursprüngliche Problem zu lösen

4. Liefere die Lösung zum ursprünglichen Problem (an den Aufrufer)

78

(73)

azt_helper(int origin, int residuum)

Ist origin durch letzte Ziffer von residuum teilbar?

§ Wenn die letzte Ziffer eine 0 ist, dann macht diese Frage keinen Sinn (und die Zahl hat nicht die AZT Eigenschaft)

§ Dies müssen wir prüfen bevor obige Bedingung geprüft werden kann

79

(74)

Lösung

public static boolean azt_helper(int origin, int residuum) { if (residuum == 0) {

return true;

} else {

// Letzte Ziffer von residuum: ≠ 0 und teilt die Zahl N ohne Rest?

boolean resultTP1;

resultTP1 = (residuum%10!=0) && (origin%(residuum%10)==0);

// Rufe rekursiv azt-helper(...) fuer TP2 auf

boolean resultTP2 = azt_helper(origin, residuum/10);

return resultTP1 && resultTP2;

}

} 80

(75)

azt_helper: Eine rekursive Methode

sonst

1. Zerlege Problem in ein oder mehr ähnliche, aber kleinere Teil-Probleme TP1, TP2, …, TPn

2. TP1 : Letzte Ziffer von residuum: Nicht 0 und teilt die Zahl N ohne Rest?

3. TP2 : Übrige Ziffern von residuum.

2. Rufe rekursiv azt-helper(...) auf, um das kleinere Teil-Problem TP2 zu lösen (denn dieses ist ähnlich)

3. Füge die Lösungen der Teil-Probleme zusammen um das ursprüngliche Problem zu lösen

4. Liefere die Lösung zum ursprünglichen Problem (an den Aufrufer)

81

(76)

Lösung

public static boolean azt_helper(int origin, int residuum) { if (residuum == 0) {

return true;

} else {

// Letzte Ziffer von residuum: ≠ 0 und teilt die Zahl N ohne Rest?

boolean resultTP1;

resultTP1 = (residuum%10!=0) && (origin%(residuum%10)==0);

// Rufe rekursiv azt-helper(...) fuer TP2 auf

boolean resultTP2 = azt_helper(origin, residuum/10);

return resultTP1 && resultTP2;

}

} 82

(77)

azt_helper: Eine rekursive Methode

sonst

1. Zerlege Problem in ein oder mehr ähnliche, aber kleinere Teil-Probleme TP1, TP2, …, TPn

2. TP1 : Letzte Ziffer von residuum: Nicht 0 und teilt die Zahl N ohne Rest?

3. TP2 : Übrige Ziffern von residuum.

2. Rufe rekursiv azt-helper(...) auf, um das kleinere Teil-Problem TP2 zu lösen (denn dieses ist ähnlich)

3. Füge die Lösungen der Teil-Probleme zusammen um das ursprüngliche Problem zu lösen

4. Liefere die Lösung zum ursprünglichen Problem (an den Aufrufer)

83

(78)

Lösung

public static boolean azt_helper(int origin, int residuum) { if (residuum == 0) {

return true;

} else {

// Letzte Ziffer von residuum: ≠ 0 und teilt die Zahl N ohne Rest?

boolean resultTP1;

resultTP1 = (residuum%10!=0) && (origin%(residuum%10)==0);

// Rufe rekursiv azt-helper(...) fuer TP2 auf

boolean resultTP2 = azt_helper(origin, residuum/10);

return resultTP1 && resultTP2;

}

} 84

(79)

Vereinfacht … mit «short-circuit» Auswertung

85

public static boolean azt_helper(int origin, int residuum) { if (residuum == 0) {

return true;

} else { return

// Letzte Ziffer von residuum: ≠ 0 und teilt die Zahl N ohne Rest?

( (residuum%10!=0) && (origin%(residuum%10)==0) &&

// Rufe rekursiv azt-helper(...) fuer TP2 auf

azt_helper(origin, residuum/10) );

} }

(80)

6.2 Datenstrukturen mit Verküpfungen

87

(81)

Datenstrukturen mit Verküpfungen

§ Bisher hatten wir Arrays als Datenstruktur kennen gelernt

§ Ein Array besteht aus Elementen eines Typs int[] ia = {42, -3, 17, 9};

§ Grösse muss im Voraus bekannt sein

§ Entweder für new int[length] oder für Initialisierung

§ Oft wollen wir mit einer unbestimmten Anzahl von Elementen arbeiten.

88

Index 0 1 2 3 Wert 42 -3 17 9

(82)

Datenstrukturen mit Verküpfungen

§ Wir wollen mit einer unbestimmten

§ Anzahl von Elementen arbeiten

§ Können nicht berechnen wieviele

§ Elemente wir brauchen werden

§ Diese können wir als verknüpfte Objekte («linked objects») organisieren. Jedes Objekt (Knoten) speichert ein Element und einen Verweis auf einen anderen Knoten.

list 42 -3 17 9

?

90

Index 0 1 2 3 Wert 42 -3 17 9

(83)

Datenstrukturen mit Verküpfungen

§ Wir wollen mit einer unbestimmten

§ Anzahl von Elementen arbeiten

§ Können nicht berechnen wieviele

§ Elemente wir brauchen werden

§ Diese können wir als verknüpfte Objekte («linked objects») organisieren. Jedes Objekt (Knoten) speichert ein Element und einen Verweis auf einen anderen Knoten.

list 42 -3 17 9

91

Index 0 1 2 3 Wert 42 -3 17 9

null

(84)

Datenstrukturen mit Verküpfungen

§ Wir wollen mit einer unbestimmten

§ Anzahl von Elementen arbeiten

§ Können nicht berechnen wieviele

§ Elemente wir brauchen werden

§ Diese können wir als verknüpfte Objekte («linked objects») organisieren. Jedes Objekt (Knoten) speichert ein Element und einen Verweis auf einen anderen Knoten.

list 42 -3 17 9

92

Index 0 1 2 3 Wert 42 -3 17 9

(85)

Eine Klasse für Knoten einer Liste

public class ListNode { int data;

??? next;

}

§ Jeder Knoten der Liste speichert:

§ Den Wert einer ganzen (int) Zahl

§ Einen Verweis auf einen anderen Listenknoten

§ ListNodes können zu einer Kette verbunden («linked») wer- den um eine Menge oder Liste von Werten zu speichern.

data next 42

data next -3

data next 17

data next 9

93

(86)

Eine Klasse für Knoten einer Liste

public class ListNode { int data;

ListNode next;

}

§ Jeder Knoten der Liste speichert:

§ Den Wert einer ganzen (int) Zahl

§ Einen Verweis auf einen anderen Listenknoten

§ ListNodes können zu einer Kette verbunden («linked») wer- den um eine Menge oder Liste von Werten zu speichern.

data next 42

data next -3

data next 17

data next 9

94

(87)

ListNode Klient - Beispiel

public class ConstructList1 {

public static void main(String[] args) { ListNode list = new ListNode();

list.data = 42;

list.next = new ListNode();

list.next.data = -3;

list.next.next = new ListNode();

list.next.next.data = 17;

list.next.next.next = null;

System.out.println(list.data + " " + list.next.data + " " + list.next.next.data);

// 42 -3 17 }

}

data next 42

data next -3

data next

list 17

95

(88)

Konstruktor für Knoten einer Liste

public class ListNode { int data;

ListNode next;

public ListNode(int data) { this.data = data;

this.next = null;

}

public ListNode(int data, ListNode next) { this.data = data;

this.next = next;

}

} 96

(89)

Übung

§ Modifizieren Sie das letzte Klientenprogramm so dass es diese Konstruktoren verwendet.

97

(90)

ListNode Klient – mit Konstruktor

public class ConstructList1 {

public static void main(String[] args) {

ListNode list = new ListNode(42,

new ListNode(-3,

new ListNode(17)));

System.out.println(list.data + " " + list.next.data + " " + list.next.next.data);

// 42 -3 17 }

} data next

42

data next -3

data next list 17

98

(91)

ListNode Klient – mit Konstruktor

public class ConstructList1 {

public static void main(String[] args) { ListNode list = new ListNode(42,

new ListNode(-3,

new ListNode(17)));

System.out.println(list.data + " " + list.next.data + " " + list.next.next.data);

// 42 -3 17 }

} data next

42

data next -3

data next list 17

99

(92)

ListNode Klient – mit Konstruktor

public class ConstructList1 {

public static void main(String[] args) { ListNode list = new ListNode(42,

new ListNode(-3,

new ListNode(17)));

System.out.println(list.data + " " + list.next.data + " " + list.next.next.data);

// 42 -3 17 }

} data next

42

data next -3

data next list 17

100

(93)

Verknüpfte Knoten -- Übungsproblem 1

Welche Folge von Anweisungen verändert dieses Bild:

in dieses?

data next 10

data next

list 20

data next 10

data next

list 20 data next

30

101

(94)

Verknüpfte Knoten -- Übungsproblem 1

Welche Folge von Anweisungen verändert dieses Bild:

in dieses?

list.next.next = new ListNode(30);

data next 10

data next

list 20

data next 10

data next

list 20 data next

30

103

(95)

Verknüpfte Knoten -- Übungsproblem 2

Welche Folge von Anweisungen verändert dieses Bild:

in dieses?

data next 10

data next

list 20

data next 30

data next

list 10 data next

20

104

(96)

Verknüpfte Knoten -- Übungsproblem 2

Welche Folge von Anweisungen verändert dieses Bild:

in dieses?

data next 10

data next

list 20

data next 30

data next

list 10 data next

20

106

list = new ListNode(30, list);

(97)

Verknüpfte Knoten -- Übungsproblem 3

Welche Folge von Anweisungen verändert dieses Bild:

in dieses?

data next 10

data next

list1 20

data next 30

data next

list2 40

data next 10

data next

list1 30

data next

list2 40

data next 20

107

(98)

Verknüpfte Knoten -- Übungsproblem 3

Welche Folge von Anweisungen verändert dieses Bild:

data next 10

data next

list1 20

data next 30

data next

list2 40

rest

108

rest = list2.next;

list2.next = list1.next;

list1.next = list2;

list2 = rest;

(99)

ListNode rest, list1, list2;

rest = list2.next;

list2.next = list1.next;

list1.next = list2;

list2 = rest;

110

(100)

Zuweisungen mit Referenzvariablen

Variable = Wert;

§ Die Variable (links von = ) ist Referenzvariable

§ Entweder Attribut (z.B., next) eines durch eine andere Referenzvariable (z.B., a) bestimmten Objekts oder Variable/Parameter einer Methode

§ Referenzvariable (z.B. ListNode next) speichern Verweis auf Objekt (z.B.

a.next verweist auf nächstes Element einer Liste)

§ Der Wert (rechts von = ) ist ein Verweis auf ein Exemplar (ein Rechteck, ein Window, ein Element einer Liste, usw.)

§ Typ des Exemplars muss mit Referenzvariable übereinstimmen

§ Java erlaubt keine arithmetischen Ausdrücke mit Referenzvariablen, daher muss Wert auch eine Referenzvariable sein oder einen Verweis erstellen (mittels new o.ä.)

111

(101)

Referenzen vs. Objekte

Variable = Wert;

Für die Liste rechts:

§ a.next = Wert;

heisst anpassen worauf zeigt

§ Variable = a.next;

heisst die Variable setzen so dass sie auf zeigt

data next

a 10 data next

1 20

2

1

2

112

(102)

Referenzen verändern

§ Wenn das Programm sagt:

a.next = b.next;

§ dann heisst das:

§ «Lasse die Variable a.next auf den selben Wert (Objekt) zeigen wie b.next»

§ Oder: «Lasse a.next auf den selben Ort wie b.next verweisen.»

data next

a 10 data next

20

data next

b 30 data next

40

113

(103)

§ Nehmen wir an wir haben eine lange Kette von Knoten:

§ Wir wissen nicht wie lang die Kette ist.

§ Wie könnten wir die Werte in allen Knoten ausgeben?

data next 10

data next

list 990

...

data next 20

114

Verknüpfte Knoten -- Übungsproblem 4

(104)

Algorithmus Pseudocode

§ Fangen wir am Anfang der Liste an

§ list verweist auf 1. Knoten

§ while (es gibt noch Knoten auszugeben):

§ Gebe den data Wert des Knotens aus

§ Gehe weiter zum nächsten Knoten via das next Attribut.

§ Wie wissen wir ob noch Knoten auszugeben sind?

§ Wir haben einen Verweis auf einen Knoten

§ Nach der Ausgabe des letzten Knotens ist sein next Attribute null.

data next 10

data next

list 990

...

data next 20

116

(105)

Algorithmus Pseudocode

§ Fangen wir am Anfang der Liste an

§ list verweist auf 1. Knoten

§ while (es gibt noch Knoten auszugeben):

§ Gebe den data Wert des Knotens aus

§ Gehe weiter zum nächsten Knoten via das next Attribut.

§ Wie können wir uns durch die Liste arbeiten ?

§ list = list.next; // is this a good idea?

data next 10

data next

list 990

...

data next 20

117

(106)

Abarbeiten einer Liste?

§ Ein (schlechter) Weg jeden Wert in der Liste auszugeben :

while (list != null) {

System.out.println(list.data);

list = list.next; // move to next node }

§ Was ist das Problem?

118

(107)

Abarbeiten einer Liste?

§ Ein (schlechter) Weg jeden Wert in der Liste auszugeben :

while (list != null) {

System.out.println(list.data);

list = list.next; // move to next node }

§ Was ist das Problem?

§ Wir verlieren die Liste während wir sie ausgeben

data next 10

data next

list 990

...

data next

20 119

(108)

Eine weitere Referenz: current

§ Wir wollen list nicht verändern. Wir deklarieren eine andere Variable und ändern diese.

§ Eine ListNode (Referenz)Variable ist nicht ein ListNode Objekt

§ … sondern eine Referenz (Verweis) auf ein Objekt

ListNode current = list;

data next 10

data next

list 990

...

data next 20

current

120

(109)

Eine weitere Referenz: current

ListNode current = list;

§ Was passiert wenn wir jetzt diese Anweisung ausführen:

current = current.next;

data next 10

data next

list 990

...

data next 20

current

121

(110)

Eine weitere Referenz: current

ListNode current = list;

§ Was passiert wenn wir jetzt diese Anweisung ausführen:

current = current.next;

data next 10

data next

list 990

...

data next 20

current

122

(111)

Korrektes Durchlaufen einer Liste

§ Der korrekte Weg jeden Wert der Liste auszugeben:

ListNode current = list;

while (current != null) {

System.out.println(current.data);

current = current.next; // move to next node }

§ Das Verändern von current hat keinen Einfluss auf die Liste.

data next 10

data next

list 990

...

data next 20

123

(112)

Verknüpfte Knoten -- Übungsproblem 5

Welche Folge von Anweisungen verändert dieses Bild:

in dieses?

data next 10

data next

list 990

...

data next 10

data next

list 990

...

data next 1000

124

(113)

6.3 Entwurf von (abgekapselten) Klassen

125

(114)

Eine Klasse LinkedIntList

§ ListNodes sollen nicht von Klienten direkt verändert werden.

§ Also entwickeln wir eine Klasse die die Knoten versteckt:

LinkedIntList.

front LinkedIntList

ListNode ListNode ListNode

data next 42

data next -3

data next 17

126

(115)

Eine Klasse LinkedIntList

§ Klienten arbeiten mit LinkedIntList, nicht mit ListNode Objekten.

§ Wir können die Elemente numerieren (von 0 an)

front LinkedIntList

ListNode ListNode ListNode

data next 42

data next -3

data next 17

element 0 element 1 element 2

127

(116)

§ Hat die Methoden

§ add(value) - füge neues Element am Ende hinzu

§ remove() - entferne erstes Element

§ Die Liste ist als Kette von Knoten intern implementiert

§ Das LinkedIntList Objekt enthält eine Referenz auf das erste Element in front

front LinkedIntList

ListNode ListNode ListNode

data next 42

data next -3

data next 17

element 0 element 1 element 2

128

(117)

§ Hat weitere Methoden

§ add(value,index) - füge Element in Position k hinzu

§ remove(index) - entferne k-tes Element

§ Das LinkedIntList Objekt enthält eine Referenz auf das erste Element in front

§ null im next Attribut signalisiert Ende der Liste

§ Hat front den Wert null so ist die Liste leer

front add(value)

add(index, value) indexOf(value) remove(index) size()

toString() LinkedIntList

ListNode ListNode ListNode

data next 42

data next -3

data next 17

element 0 element 1 element 2

129

(118)

Namen von Methoden

§ In einer Klasse können verschiedene Methoden den selben Namen haben

public void add (int value) { … }

public void add (int value, int index) { … }

§ Die Typen der Parameter müssen unterschiedlich sein

public void add (int value) { … }

public void add (int index) { … } // not OK

130

(119)

LinkedIntList Klasse v1

public class LinkedIntList { private ListNode front;

public LinkedIntList() { front = null;

}

// methods }

front = LinkedIntList

131

(120)

Die add Methode

// Adds the given value to the end of the list.

public void add(int value) { ...

}

§ Wie wollen wir einen neuen Knoten am Ende hinzufügen?

§ Sind die Werte in der Liste vor diesem Schritt wichtig?

front =

data next 42

data next -3

data next 17

element 0 element 1 element 2

132

(121)

Ein Element in eine leere Liste hinzufügen

§ Bevor 20 hinzugefügt wird: Danach:

front = front =

data next 20

element 0

133

(122)

Ein Element in eine leere Liste hinzufügen

§ Bevor 20 hinzugefügt wird: Danach:

§ Wir müssen einen Knoten erstellen und an die Liste anhängen.

front = front =

data next 20

element 0

134

Referenzen

ÄHNLICHE DOKUMENTE

Ein Java-Objekt kann genau auf die Nachrichten reagieren, für die Methoden in seiner Klasse deklariert sind oder für die es Methoden geerbt hat (vgl... Poetzsch-Heffter,

Dann läßt man das Element im Heap absinken , indem man es solange immer wieder mit dem größeren der beiden Söhne vertauscht, bis beide Söhne kleiner sind oder das Element

§ Um ein Element zur Liste hinzuzufügen müssen wir das next Attribut des vorherigen Knotens modifizieren?.

§ Wenn eine Methode aufgerufen wird, dann muss das neue Stack Frame genug Platz für alle (lokalen) Variablen haben. § Wenn eine Methode fertig ist, dann kann ihr Stack Frame

§ Um ein Element zur Liste hinzuzufügen müssen wir das next Attribut des vorherigen Knotens modifizieren..

§ Variable, die in einer Methode deklariert sind, müssen einen Wert haben, bevor sie als Operand oder Parameter.. verwendet

§ ListNode s können zu einer Kette verbunden (“linked”) wer- den um eine Menge oder Liste von Werten zu

In Berlin war das Licht von Colberg schlecht zu sehen; es kam immer erst kurz vor Sonnenuntergang hinter dem Walde hervor, war dann breit und flackernd und überhaupt schwer