• Keine Ergebnisse gefunden

faik 1 Wieeee2011/2012

N/A
N/A
Protected

Academic year: 2022

Aktie "faik 1 Wieeee2011/2012 "

Copied!
443
0
0

Wird geladen.... (Jetzt Volltext ansehen)

Volltext

(1)

Wintersemester 2011/2012

Helmut Seidl

Institut für Informatik

TU Münhen

(2)

Inhalt dieser Vorlesung:

Einführung in Grundkonzepte der Informatik;

Einführung in Denkweisen der Informatik;

Programmieren in Java.

(3)

Ein Problem besteht darin, aus einer gegebenen Menge von

Informationen eine weitere (bisher unbekannte) Information zu

bestimmen.

Ein Algorithmus ist ein exaktes Verfahren zur Lösung eines

Problems, d.h. zur Bestimmung der gewünshten Resultate.

== ⇒

Ein Algorithmus beshreibt eine Funktion:

f : E → A

,

wobei

E =

zulässige Eingaben,

A =

möglihe Ausgaben.

(4)
(5)

Niht jede Abbildung lässt sih durh einen Algorithmus realisieren!

(

Berehenbarkeitstheorie)

Das Verfahren besteht i.a. darin, eine Abfolge von Einzelshritten der

Verarbeitung festzulegen.

Beispiel: Alltagsalgorithmen

Resultat Algorithmus Einzelshritte

Pullover Strikmuster eine links, eine rehts

eine fallen lassen

Kuhen Rezept nimm 3 Eier ...

Konzert Partitur Noten

(6)

Problem: Seien

a, b ∈ N , a, b 6= 0

. Bestimme

ggT (a, b)

.

Algorithmus:

1. Falls

a = b

, brih Berehnung ab, es gilt

ggT (a, b) = a

.

Ansonsten gehe zu Shritt 2.

2. Falls

a > b

, ersetze

a

durh

a − b

und

setze Berehnung in Shritt 1 fort.

Ansonsten gehe zu Shritt 3.

3. Es gilt

a < b

. Ersetze b durh

b − a

und

setze Berehnung in Shritt 1 fort.

(7)

Problem: Seien

a, b ∈ N , a, b 6= 0

. Bestimme

ggT (a, b)

.

Algorithmus:

1. Falls

a = b

, brih Berehnung ab, es gilt

ggT (a, b) = a

.

Ansonsten gehe zu Shritt 2.

2. Falls

a > b

, ersetze

a

durh

a − b

und

setze Berehnung in Shritt 1 fort.

Ansonsten gehe zu Shritt 3.

3. Es gilt

a < b

. Ersetze b durh

b − a

und

setze Berehnung in Shritt 1 fort.

(8)

Programmiersprahe.

Die Formulierung gestattet (hoentlih) eine mashinelle

Ausgeführung.

Beahte:

Es gibt viele Programmiersprahen: Java, C, Prolog, Fortran, Cobol ....

Eine Programmiersprahe ist dann gut, wenn

die Programmiererin in ihr ihre algorithmishen Ideen

natürlih beshreiben kann, insbesondere selbst später noh

versteht, was das Programm tut (oder niht tut);

ein Computer das Programm leiht verstehen und ezient

ausführen kann.

(9)

Eine Programmiersprahe soll

Datenstrukturen anbieten;

Operationen auf Daten erlauben;

Kontrollstrukturen zur Ablaufsteuerung bereit stellen.

Als Beispiel betrahten wir MiniJava.

(10)

Um Daten zu speihern und auf gespeiherte Daten zugreifen zu

können, stellt MiniJava Variablen zur Verfügung. Variablen müssen

erst einmal eingeführt, d.h. deklariert werden.

Beispiel:

int x, result;

Diese Deklaration führt die beiden Variablen mit den Namen x und

result ein.

(11)

Das Shlüsselwort int besagt, dass diese Variablen ganze Zahlen (Integers) speihern sollen.

int heiÿt auh Typ der Variablen x und result.

Variablen können dann benutzt werden, um anzugeben, auf

welhe Daten Operationen angewendet werden sollen.

Die Variablen in der Aufzählung sind durh Kommas ,

getrennt.

Am Ende steht ein Semikolon ;.

(12)

Die Operationen sollen es gestatten, die Werte von Variablen zu

modizieren. Die wihtigste Operation ist die Zuweisung.

Beispiele:

x = 7;

Die Variable x erhält den Wert 7.

result = x;

Der Wert der Variablen x wird ermittelt und der Variablen

result zugewiesen.

result = x + 19;

Der Wert der Variablen x wird ermittelt, 19 dazu gezählt und

dann das Ergebnis der Variablen result zugewiesen.

(13)

result = x - 5;

Der Wert der Variablen x wird ermittelt, 5 abgezogen und dann

das Ergebnis der Variablen result zugewiesen.

Ahtung:

Java bezeihnet die Zuweisung mit =anstelle von :=

(Erbshaft von C ...)

Jede Zuweisung wird mit einem Semikolon ; beendet.

In der Zuweisung x = x + 1; greift das x auf der rehten Seite

auf den Wert vor der Zuweisung zu.

(14)

bzw. ausgeben zu können.

x = read();

Diese Operation liest eine Folge von Zeihen vom Terminal ein

und interpretiert sie als eine ganze Zahl, deren Wert sie der

Variablen x als Wert zu weist.

write(42);

Diese Operation shreibt 42 auf die Ausgabe.

write(result);

Diese Operation bestimmt den Wert der Variablen result und

shreibt dann diesen auf die Ausgabe.

write(x-14);

Diese Operation bestimmt den Wert der Variablen x,

subtrahiert 14 und shreibt das Ergebnis auf die Ausgabe.

(15)

Das Argument der write-Operation in den Beispielen ist ein int.

Um es ausgeben zu können, muss es in eine Folge von Zeihen

umgewandelt werden, d.h. einen String.

Damit wir auh freundlihe Worte ausgeben können, gestatten wir

auh direkt Strings als Argumente:

write("Hello World!");

... shreibt Hello World! auf die Ausgabe.

(16)

Sequenz:

int x, y, result;

x = read();

y = read();

result = x + y;

write(result);

(17)

Zu jedem Zeitpunkt wird nur eine Operation ausgeführt.

Jede Operation wird genau einmal ausgeführt. Keine wird wiederholt, keine ausgelassen.

Die Reihenfolge, in der die Operationen ausgeführt werden, ist die gleihe, in der sie im Programm stehen (d.h. naheinander).

Mit Beendigung der letzten Operation endet die

Programm-Ausführung.

== ⇒

Sequenz alleine erlaubt nur sehr einfahe Programme.

(18)

int x, y, result;

x = read();

y = read();

if (x > y)

result = x - y;

else

result = y - x;

write(result);

Zuerst wird die Bedingung ausgewertet.

Ist sie erfüllt, wird die nähste Operation ausgeführt.

Ist sie niht erfüllt, wird die Operation nah dem else

ausgeführt.

(19)

Statt aus einzelnen Operationen können die Alternativen auh aus Statements bestehen:

int x;

x = read();

if (x == 0)

write(0);

else if (x < 0)

write(-1);

else

write(+1);

(20)

... oder aus (geklammerten) Folgen von Operationen und Statements:

int x, y;

x = read();

if (x != 0) {

y = read();

if (x > y)

write(x);

else

write(y);

} else

write(0);

(21)

... eventuell fehlt auh der else-Teil:

int x, y;

x = read();

if (x != 0) {

y = read();

if (x > y)

write(x);

else

write(y);

}

Auh mit Sequenz und Selektion kann noh niht viel berehnet

werden ...

(22)

int x, y;

x = read();

y = read();

while (x != y)

if (x < y)

y = y - x;

else

x = x - y;

write(x);

(23)

Zuerst wird die Bedingung ausgewertet.

Ist sie erfüllt, wird der Rumpf des while-Statements ausgeführt.

Nah Ausführung des Rumpfs wird das gesamte

while-Statement erneut ausgeführt.

Ist die Bedingung niht erfüllt, fährt die Programm-Ausführung hinter dem while-Statement fort.

(24)

berehenbar ist, läÿt sih mit Selektion, Sequenz, Iteration,

d.h. mithilfe eines MiniJava-Programms berehnen !!

Beweis:

Berehenbarkeitstheorie.

Idee:

Eine Turing-Mashine kann alles berehnen...

Versuhe, eine Turing-Mashine zu simulieren!

(25)

Man muss sie nur geeignet dekorieren !

(26)

Man muss sie nur geeignet dekorieren !

Beispiel: Das GGT-Programm

int x, y;

x = read();

y = read();

while (x != y)

if (x < y)

y = y - x;

else

x = x - y;

write(x);

Daraus wird das Java-Programm:

(27)

publi lass GGT extends MiniJava

{

publi stati void main (String[℄ args)

{

int x, y;

x = read();

y = read();

while (x != y)

if (x < y)

y = y - x;

else

x = x - y;

write(x);

} //

Ende der Definition von main();

} //

Ende der Definition der Klasse GGT;

(28)

Jedes Programm hat einen Namen (hier: GGT).

Der Name steht hinter dem Shlüsselwort lass (was eine Klasse, was publi ist, lernen wir später)

Der Datei-Name muss zum Namen des Programms passen,

d.h. in diesem Fall GGT.java heiÿen.

Das MiniJava-Programm ist der Rumpf des Hauptprogramms, d.h. der Funktion main().

Die Programm-Ausführung eines Java-Programms startet stets mit einem Aufruf von dieser Funktion main().

Die Operationen write() und read() werden in der Klasse MiniJava deniert.

Durh GGT extends MiniJava mahen wir diese

(29)

import javax.swing.JOptionPane;

import javax.swing.JFrame;

publi lass MiniJava {

publi stati int read () {

JFrame f = new JFrame ();

String s = JOptionPane.showInputDialog (f, "Eingabe:");

int x = 0; f.dispose ();

if (s == null) System.exit (0);

try { x = Integer.parseInt (s.trim ());

} ath (NumberFormatExeption e) { x = read (); }

return x;

}

publi stati void write (String x) {

JFrame f = new JFrame ();

JOptionPane.showMessageDialog (f, x, "Ausgabe",

JOptionPane.PLAIN_MESSAGE);

f.dispose ();

}

publi stati void write (int x) { write (""+x); }

}

(30)

Jedes Programm sollte Kommentare enthalten, damit man sih

selbst später noh darin zureht ndet!

Ein Kommentar in Java hat etwa die Form:

// Das ist ein Kommentar!!!

Wenn er sih über mehrere Zeilen erstreken soll, kann er auh

so aussehen:

/* Dieser Kommentar geht

"uber mehrere Zeilen! */

(31)

Auf der Kommandozeile sieht das so aus:

seidl> java GGT.java

seidl> java GGT

Der Compiler java liest das Programm aus den Dateien

GGT.java und MiniJava.java ein und erzeugt für sie

JVM-Code, den er in den Dateien GGT.lass und

MiniJava.lass ablegt.

Das Laufzeitsystem java liest die Dateien GGT.lass und MiniJava.lass ein und führt sie aus.

(32)

MiniJava ist sehr primitiv.

Die Programmiersprahe Java bietet noh eine Fülle von Hilfsmitteln an, die das Programmieren erleihtern sollen.

Insbesondere gibt es

viele weitere Datenstrukturen (niht nur int) und

viele weitere Kontrollstrukturen.

... kommt später in der Vorlesung !!

(33)

Syntax (Lehre vom Satzbau):

formale Beshreibung des Aufbaus der Worte und Sätze, die

zu einer Sprahe gehören;

im Falle einer Programmier-Sprahe Festlegung, wie Programme aussehen müssen.

(34)

Wörterbüher;

Rehtshreibregeln, Trennungsregeln, Grammatikregeln;

Ausnahme-Listen;

Sprah-Gefühl.

(35)

Listen von Shlüsselworten wie if, int, else, while ...

Regeln, wie einzelne Worte (Tokens) z.B. Namen gebildet

werden.

Frage:

Ist x10 ein zulässiger Name für eine Variable?

oder _ab$ oder A#B oder 0A?B ...

Grammatikregeln, die angeben, wie gröÿere Komponenten aus kleineren aufgebaut werden.

Frage:

Ist ein while-Statement im else-Teil erlaubt?

(36)

Kontextbedingungen.

Beispiel:

Eine Variable muss erst deklariert sein, bevor sie verwendet

wird.

== ⇒

formalisierter als natürlihe Sprahe

== ⇒

besser für mashinelle Verarbeitung geeignet

(37)

Ein Satz einer (natürlihen) Sprahe verfügt zusätzlih über eine Bedeutung, d.h. teilt einem Hörer/Leser einen Sahverhalt mit

(

Information)

Ein Satz einer Programmiersprahe, d.h. ein Programm verfügt ebenfalls über eine Bedeutung ...

(38)

alle möglihen Ausführungen der beshriebenen Berehnung

(

operationelle Semantik); oder

die denierte Abbildung der Eingaben auf die Ausgaben

(

denotationelle Semantik).

Ahtung!

Ist ein Programm syntaktish korrekt, heiÿt das noh lange niht,

dass es auh das rihtige tut, d.h. semantish korrekt ist !!!

(39)

alle möglihen Ausführungen der beshriebenen Berehnung

(

operationelle Semantik); oder

die denierte Abbildung der Eingaben auf die Ausgaben

(

denotationelle Semantik).

Ahtung!

Ist ein Programm syntaktish korrekt, heiÿt das noh lange niht,

dass es auh das rihtige tut, d.h. semantish korrekt ist !!!

(40)

int

Bezeihner für Basis-Typen;

if, else, while

Shlüsselwörter aus Programm-Konstrukten;

(,), ",', {,}, ,,;

Sonderzeihen.

(41)

Shritt 1: Angabe der erlaubten Zeihen:

letter

:: =

$

|

_

|

a

| . . . |

z

|

A

| . . . |

Z

digit

:: =

0

| . . . |

9

(42)

Shritt 1: Angabe der erlaubten Zeihen:

letter

:: =

$

|

_

|

a

| . . . |

z

|

A

| . . . |

Z

digit

:: =

0

| . . . |

9

letter und digit bezeihnen Zeihenklassen, d.h. Mengen von Zeihen, die gleih behandelt werden.

Das Symbol

|

trennt zulässige Alternativen.

Das Symbol

. . .

repräsentiert die Faulheit, alle Alternativen wirklih aufzuzählen.

(43)

name

:: =

letter ( letter

|

digit )*

Erst kommt ein Zeihen der Klasse letter, dann eine (eventuell

auh leere) Folge von Zeihen entweder aus letter oder aus digit.

Der Operator * bedeutet beliebig ofte Wiederholung (weglassen ist 0-malige Wiederholung).

Der Operator * ist ein Postx-Operator. Das heiÿt, er steht hinter seinem Argument.

(44)

_178

Das_ist_kein_Name

x

_

$Password$

... sind legale Namen.

(45)

5ABC

!Hallo!

x'

-178

... sind keine legalen Namen.

Ahtung:

Reservierte Wörter sind als Namen verboten !!!

(46)

5ABC

!Hallo!

x'

-178

... sind keine legalen Namen.

Ahtung:

Reservierte Wörter sind als Namen verboten !!!

(47)

Werte, die direkt im Programm stehen, heiÿen Konstanten.

Ganze nihtnegative Zahlen bestehen aus einer nihtleeren Folge von

Ziern:

number

:: =

digit digit*

(48)

Werte, die direkt im Programm stehen, heiÿen Konstanten.

Ganze nihtnegative Zahlen bestehen aus einer nihtleeren Folge von

Ziern:

number

:: =

digit digit*

Wie sähe die Regel aus, wenn wir führende Nullen verbieten

wollen?

(49)

17

12490

42

0

00070

... sind alles legale int-Konstanten.

"Hello World!"

0.5e+128

... sind keine int-Konstanten.

(50)

|

(Alternative)

* (Iteration)

(Konkatenation) sowie

? (Option)

... aufgebaut sind, heiÿen reguläre Ausdrüke a

(

Automatentheorie).

Der Postx-Operator ? besagt, dass das Argument eventuell auh

fehlen darf, d.h. einmal oder keinmal vorkommt.

a

Gelegentlih sind auh

ǫ

, d.h. das leere Wort sowie

, d.h. die leere Menge

zugelassen.

(51)

Worten aus.

( letter letter )*

alle Wörter gerader Länge (über a,...,z,A,...,Z);

letter* test letter*

alle Wörter, die das Teilwort test enthalten;

_ digit* 17

alle Wörter, die mit _ anfangen, dann eine beliebige Folge von

Ziern aufweisen, die mit 17 aufhört;

• exp ::= ( e | E )(

+

|

-

)? digit digit

*

float ::= digit digit

*

exp |

digit

*

(digit . | . digit) digit

*

exp?

alle Gleitkomma-Zahlen ...

(52)

reservierten Wörtern,

Namen,

Konstanten

Ignorierung von

White Spae,

Kommentaren

... erfolgt in einer ersten Phase (

Sanner)

== ⇒

Input wird mit regulären Ausdrüken verglihen und dabei in

Wörter (Tokens) aufgeteilt.

In einer zweiten Phase wird die Struktur des Programms analysiert

(

Parser).

(53)

Programme sind hierarhish aus Komponenten aufgebaut. Für jede

Komponente geben wir Regeln an, wie sie aus anderen Komponenten

zusammengesetzt sein können.

program

:: =

del* stmt*

del

:: =

type name ( , name )* ;

type

:: =

int

Ein Programm besteht aus einer Folge von Deklarationen, gefolgt von einer Folge von Statements.

Eine Deklaration gibt den Typ an, hier: int, gefolgt von einer Komma-separierten Liste von Variablen-Namen.

(54)

Programme sind hierarhish aus Komponenten aufgebaut. Für jede

Komponente geben wir Regeln an, wie sie aus anderen Komponenten

zusammengesetzt sein können.

program

:: =

del* stmt*

del

:: =

type name ( , name )* ;

type

:: =

int

Ein Programm besteht aus einer Folge von Deklarationen, gefolgt von einer Folge von Statements.

Eine Deklaration gibt den Typ an, hier: int, gefolgt von einer Komma-separierten Liste von Variablen-Namen.

(55)

stmt

:: =

;

|

{ stmt* }

|

name = expr;

|

name = read();

|

write( expr );

|

if ( ond ) stmt

|

if ( ond ) stmt else stmt

|

while ( ond ) stmt

Ein Statement ist entweder leer (d.h. gleih ;) oder eine

geklammerte Folge von Statements;

oder eine Zuweisung, eine Lese- oder Shreib-Operation;

eine (einseitige oder zweiseitige) bedingte Verzweigung;

oder eine Shleife.

(56)

expr

:: =

number

|

name

|

( expr )

|

unop expr

|

expr binop expr

unop

:: =

-

binop

:: =

-

|

+

|

*

|

/

|

%

Ein Ausdruk ist eine Konstante, eine Variable oder ein

geklammerter Ausdruk

oder ein unärer Operator, angewandt auf einen Ausdruk,

oder ein binärer Operator, angewand auf zwei

Argument-Ausdrüke.

Einziger unärer Operator ist (bisher) die Negation.

Möglihe binäre Operatoren sind Addition, Subtraktion, Multiplikation, (ganz-zahlige) Division und Modulo.

(57)

ond

:: =

true

|

false

|

( ond )

|

expr omp expr

|

bunop ond

|

ond bbinop ond

omp

:: =

==

|

!=

|

<=

|

<

|

>=

|

>

bunop

:: =

!

bbinop

:: =

&&

|

||

Bedingungen untersheiden sih dadurh von Ausdrüken, dass ihr Wert niht vom Typ int ist sondern true oder false (ein

Wahrheitswert vom Typ boolean).

Bedingungen sind darum Konstanten, Vergleihe

oder logishe Verknüpfungen anderer Bedingungen.

(58)
(59)

int x;

x = read();

if (x > 0)

write(1);

else

write(0);

Die hierarhishe Untergliederung von Programm-Bestandteilen

veranshaulihen wir durh Syntax-Bäume:

(60)

expr

number name

expr

comp cond

0 x >

number expr stmt

number expr stmt

) ;

write ( 1 write ( 0 ) ;

Blätter: Wörter/Tokens

innere Knoten: Namen von Programm-Bestandteilen

(61)

program

stmt

>

cond

comp

if ( x name

expr

number expr stmt

write ( 0 ) ; 0

number expr

number expr stmt

) ;

write ( 1 else

) name

stmt

x = read ( ) ; decl

; name

x type

int

(62)

Die vorgestellte Methode der Beshreibung von Syntax heiÿt EBNF-Notation (Extended Bakus Naur Form Notation).

Ein anderer Name dafür ist erweiterte kontextfreie Grammatik

(

Linguistik, Automatentheorie).

Linke Seiten von Regeln heiÿen auh Niht-Terminale.

Tokens heiÿen auh Terminale.

(63)

Noam Chomsky,

MIT

Turing Award

(Ernder von Fortran)

Peter Naur,

Turing Award

(Ernder von Algol60)

(64)

Die regulären Ausdrüke auf den rehten Regelseiten können sowohl Terminale wie Niht-Terminale enthalten.

Deshalb sind kontextfreie Grammatiken mähtiger als reguläre Ausdrüke.

Beispiel:

L = {ǫ,

ab

,

aabb

,

aaabbb

, . . .}

lässt sih mithilfe einer Grammatik beshreiben:

A

:: =

( a A b )?

(65)

a a a

A

b b b

A A A

Für

L

gibt es aber keinen regulären Ausdruk!!! (

Automatentheorie)

(66)

In welher Weise die Operationen eines Programms naheinander

ausgeführt werden, lässt sih anshaulih mithilfe von

Kontrolluss-Diagrammen darstellen.

Ingredienzien:

Start Stop

Endknoten Startknoten

(67)

x = read(); write(y); x = x - y;

Eingabe Ausgabe Zuweisung

(68)

no yes x < y

Kante Zusammenlauf

bedingte Verzweigung

(69)

int x, y;

x = read();

y = read();

while (x != y)

if (x < y)

y = y - x;

else

x = x - y;

write(x);

Start

no yes

Stop

yes write(x); no

x = read();

y = read();

y=y−x;

x=x−y;

x != y

x < y

(70)

Die Ausführung des Programms entspriht einem Pfad durh

das Kontrolluss-Diagramm vom Startknoten zum Endknoten.

Die Deklarationen von Variablen muss man sih am Startknoten vorstellen.

Die auf dem Pfad liegenden Knoten (auÿer dem Start- und

Endknoten) sind die dabei auszuführenden Operationen bzw.

auszuwertenden Bedingungen.

Um den Nahfolger an einem Verzweigungsknoten zu

bestimmen, muss die Bedingung für die aktuellen Werte der

Variablen ausgewertet werden.

== ⇒

operationelle Semantik

(71)

Start

no yes

Stop

yes write(x); no

x = read();

y = read();

y=y−x;

x=x−y;

x != y

x < y

(72)

Start

no yes

Stop

yes write(x); no

x = read();

y = read();

y=y−x;

x=x−y;

x != y

x < y

x == 18, y == 24

(73)

Start

no yes

Stop

yes write(x); no

x = read();

y = read();

y=y−x;

x=x−y;

x != y

x < y

x == 18, y == 24

(74)

Start

no yes

Stop

yes write(x); no

x = read();

y = read();

y=y−x;

x=x−y;

x != y

x < y

x == 18, y == 24

(75)

Start

no yes

Stop

yes write(x); no

x = read();

y = read();

y=y−x;

x=x−y;

x != y

x < y

x == 18, y == 6

(76)

Start

no yes

Stop

yes write(x); no

x = read();

y = read();

y=y−x;

x=x−y;

x != y

x < y

x == 18, y == 6

(77)

Start

no yes

Stop

yes write(x); no

x = read();

y = read();

y=y−x;

x=x−y;

x != y

x < y

x == 12, y == 6

(78)

Start

no yes

Stop

yes write(x); no

x = read();

y = read();

y=y−x;

x=x−y;

x != y

x < y

x == 12, y == 6

(79)

Start

no yes

Stop

yes write(x); no

x = read();

y = read();

y=y−x;

x=x−y;

x != y

x < y

x == 6, y == 6

(80)

Start

no yes

Stop

yes write(x); no

x = read();

y = read();

y=y−x;

x=x−y;

x != y

x < y

x == 6, y == 6

(81)

Start

no yes

Stop

yes write(x); no

x = read();

y = read();

y=y−x;

x=x−y;

x != y

x < y

x == 6, y == 6

(82)

Start

no yes

Stop

yes write(x); no

x = read();

y = read();

y=y−x;

x=x−y;

x != y

x < y

(83)

Zu jedem MiniJava-Programm lässt sih ein Kontrolluss-Diagramm konstruieren;

die umgekehrte Rihtung gilt zwar ebenfalls, liegt aber niht so

auf der Hand.

(84)

Stop Start

no yes

no yes yes

no yes yes

(85)

Um komfortabel programmieren zu können, brauhen wir

mehr Datenstrukturen;

mehr Kontrollstrukturen.

(86)

Auÿer int, stellt Java weitere Basistypen zur Verfügung.

Zu jedem Basistyp gibt es eine Menge mögliher Werte.

Jeder Wert eines Basistyps benötigt die gleihe Menge Platz,

um ihn im Rehner zu repräsentieren.

Der Platz wird in Bit gemessen.

(Wie viele Werte kann man mit

n

Bit darstellen?)

(87)

Typ Platz kleinster Wert gröÿter Wert

byte 8

−128 127

short 16

−32 768 32 767

int 32

−2 147 483 648 2 147 483 647

long 64

−9 223 372 036 854 775 808 9 223 372 036 854 775 807

Die Benutzung kleinerer Typen wie byte oder short spart Platz.

Ahtung: Java warnt niht vor Überlauf/Unterlauf !!

(88)

Typ Platz kleinster Wert gröÿter Wert

byte 8

−128 127

short 16

−32 768 32 767

int 32

−2 147 483 648 2 147 483 647

long 64

−9 223 372 036 854 775 808 9 223 372 036 854 775 807

Die Benutzung kleinerer Typen wie byte oder short spart Platz.

Ahtung: Java warnt niht vor Überlauf/Unterlauf !!

(89)

int x = 2147483647; // grösstes int

x = x+1;

write(x);

... liefert -2147483648 ...

In realem Java kann man bei der Deklaration einer Variablen ihr direkt einen ersten Wert zuweisen (Initialisierung).

Man kann sie sogar (statt am Anfang des Programms) erst an

der Stelle deklarieren, an der man sie das erste Mal brauht!

(90)

Typ Platz kleinster Wert gröÿter Wert

float 32 a. -3.4e+38 a. 3.4e+38 7 signikante Stellen

double 64 a. -1.7e+308 a. 1.7e+308 15 signikante Stellen

Überlauf/Unterlauf liefert die Werte Infinity bzw.

-Infinity.

Für die Auswahl des geeigneten Typs sollte die gewünshte

Genauigkeit des Ergebnisses berüksihtigt werden.

Gleitkomma-Konstanten im Programm werden als double aufgefasst.

Zur Untersheidung kann man an die Zahl f (oder F) bzw. d

(91)

Typ Platz Werte

boolean 1 true, false

har 16 alle Uniode-Zeihen

Uniode ist ein Zeihensatz, der alle irgendwo auf der Welt gängigen

Alphabete umfasst, also zum Beispiel:

die Zeihen unserer Tastatur (inklusive Umlaute);

die hinesishen Shriftzeihen;

die ägyptishen Hieroglyphen ...

har-Konstanten shreibt man mit Hohkommas: 'A', ';', '\n'.

(92)

Die Operatoren +, -, *, / und % gibt es für jeden der

aufgelisteten Zahltypen.

Werden sie auf ein Paar von Argumenten vershiedenen Typs

angewendet, wird automatish vorher der speziellere in den

allgemeineren umgewandelt (impliziter Type Cast) ...

(93)

Gleitkomma-Zahlen

ganze Zahlen

float

byte

long

int

short

har

(94)

short xs = 1;

int x = 999999999;

write(x + xs);

... liefert den int-Wert 1000000000 ...

float xs = 1.0f;

int x = 999999999;

write(x + xs);

... liefert den float-Wert 1.0E9 ...

... vorausgesetzt, write() kann Gleitkomma-Zahlen ausgeben.

(95)

short xs = 1;

int x = 999999999;

write(x + xs);

... liefert den int-Wert 1000000000 ...

float xs = 1.0f;

int x = 999999999;

write(x + xs);

... liefert den float-Wert 1.0E9 ...

... vorausgesetzt, write() kann Gleitkomma-Zahlen ausgeben.

(96)

Das Ergebnis einer Operation auf float kann aus dem Bereih

von float herausführen. Dann ergibt sih der Wert Infinity

oder -Infinity.

Das gleihe gilt für double.

Das Ergebnis einer Operation auf Basistypen, die in int enthalten sind (auÿer har), liefern ein int.

Wird das Ergebnis einer Variablen zugewiesen, sollte deren Typ dies zulassen.

(97)

Der Datentyp String für Wörter ist kein Basistyp, sondern eine

Klasse (dazu kommen wir später)

Hier behandeln wir nur drei Eigenshaften:

Werte vom Typ String haben die Form "Hello World!";

Man kann Wörter in Variablen vom Typ String abspeihern.

Man kann Wörter mithilfe des Operators + konkatenieren.

(98)

String s0 = "";

String s1 = "Hel";

String s2 = "lo Wo";

String s3 = "rld!";

write(s0 + s1 + s2 + s3);

... shreibt Hello World! auf die Ausgabe.

(99)

Jeder Wert in Java hat eine Darstellung als String.

Wird der Operator + auf einen Wert vom Typ String und

einen anderen Wert

x

angewendet, wird

x

automatish in seine

String-Darstellung konvertiert ...

== ⇒

... liefert einfahe Methode, um float oder double

auszugeben !!!

Beispiel:

double x = -0.55e13;

write("Eine Gleitkomma-Zahl: "+x);

... shreibt Eine Gleitkomma-Zahl: -0.55E13 auf die Ausgabe.

(100)

Oft müssen viele Werte gleihen Typs gespeihert werden.

Idee:

Lege sie konsekutiv ab!

Greife auf einzelne Werte über ihren Index zu!

3 -2 0 1

17 9

0 1 2 3 4 5

Index:

Feld:

(101)

int[℄ a; // Deklaration

int n = read();

a = new int[n℄;

// Anlegen des Felds

int i = 0;

while (i < n) {

a[i℄ = read();

i = i+1;

}

(102)

type [℄ name ; deklariert eine Variable für ein Feld (array),

dessen Elemente vom Typ type sind.

Alternative Shreibweise:

type name [℄;

Das Kommando new legt ein Feld einer gegebenen Gröÿe an und

liefert einen Verweis darauf zurük:

a a

a = new int[6℄;

(103)

Der Wert einer Feld-Variable ist also ein Verweis.

int[℄ b = a; kopiert den Verweis der Variablen a in die

Variable b:

a

b a

int[℄ b = a;

(104)

Die Elemente eines Felds sind von 0 an durhnumeriert.

Die Anzahl der Elemente des Felds name ist name.length.

Auf das

i

-te Element des Felds name greift man mittels

name[i℄ zu.

Bei jedem Zugri wird überprüft, ob der Index erlaubt ist, d.h.

im Intervall

{0, . . . ,

name.length-1

}

liegt.

Liegt der Index auÿerhalb des Intervalls, wird die

ArrayIndexOutofBou nd sEx ep ti on ausgelöst (

Exeptions).

(105)

Java unterstützt direkt nur ein-dimensionale Felder.

Ein zwei-dimensionales Feld ist ein Feld von Feldern ...

a a a

a = new int[5℄[6℄;

(106)

Typishe Form der Iteration über Felder:

Initialisierung des Laundex;

while-Shleife mit Eintrittsbedingung für den Rumpf;

Modizierung des Laundex am Ende des Rumpfs.

(107)

int result = a[0℄;

int i = 1; // Initialisierung

while (i < a.length) {

if (a[i℄ < result)

result = a[i℄;

i = i+1; // Modifizierung

}

write(result);

(108)

int result = a[0℄;

for (int i = 1; i < a.length; ++i)

if (a[i℄ < result)

result = a[i℄;

write(result);

(109)

for ( init; ond; modify ) stmt

... entspriht:

{ init ; while ( ond ) { stmt modify ;} }

... wobei ++i äquivalent ist zu i = i+1 .

(110)

Die Zuweisung x = x-1 ist in Wahrheit ein Ausdruk.

Der Wert ist der Wert der rehten Seite.

Die Modizierung der Variable x erfolgt als Seiteneekt.

Der Semikolon ; hinter einem Ausdruk wirft nur den Wert

weg.

== ⇒

... fatal für Fehler in Bedingungen ...

boolean x = false;

if (x = true)

write("Sorry! This must be an error ...");

(111)

Die Operatoranwendungen ++x und x++ inkrementieren beide den Wert der Variablen x.

++x tut das, bevor der Wert des Ausdruks ermittelt wird

(Pre-Inrement).

x++ tut das, nahdem der Wert ermittelt wurde

(Post-Inrement).

a[x++℄ = 7; entspriht:

a[x℄ = 7;

x = x+1;

a[++x℄ = 7; entspriht:

x = x+1;

a[x℄ = 7;

(112)

Teilprobleme separat lösen; und dann

die Lösung mehrfah verwenden;

== ⇒

Funktionen, Prozeduren

Beispiel: Einlesen eines Felds

publi stati int[℄ readArray(int n) {

// n = Anzahl der zu lesenden Elemente

int[℄ a = new int[n℄; // Anlegen des Felds

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

a[i℄ = read();

}

return a;

(113)

Die erste Zeile ist der Header der Funktion.

publi sagt, wo die Funktion verwendet werden darf

(

kommt später)

stati kommt ebenfalls später.

int[℄ gibt den Typ des Rükgabe-Werts an.

readArray ist der Name, mit dem die Funktion aufgerufen

wird.

Dann folgt (in runden Klammern und komma-separiert) die Liste der formalen Parameter, hier: (int n).

Der Rumpf der Funktion steht in geshwungenen Klammern.

return expr beendet die Ausführung der Funktion und liefert

den Wert von expr zurük.

(114)

Die Variablen, die innerhalb eines Bloks angelegt werden, d.h.

innerhalb von { und }, sind nur innerhalb dieses Bloks

sihtbar, d.h. benutzbar (lokale Variablen).

Der Rumpf einer Funktion ist ein Blok.

Die formalen Parameter können auh als lokale Variablen

aufgefasst werden.

Bei dem Aufruf readArray(7) erhält der formale Parameter n den Wert 7.

(115)

publi stati int min (int[℄ a) {

int result = a[0℄;

for (int i = 1; i < a.length; ++i) {

if (a[i℄ < result)

result = a[i℄;

}

return result;

}

(116)

publi lass Min extends MiniJava {

publi stati int[℄ readArray (int n) { ... }

publi stati int min (int[℄ a) { ... }

// Jetzt kommt das Hauptprogramm

publi stati void main (String[℄ args) {

int n = read();

int[℄ a = readArray(n);

int result = min(a);

write(result);

} // end of main()

} // end of lass Min

(117)

Manhe Funktionen, deren Ergebnistyp void ist, geben gar keine Werte zurük im Beispiel: write() und main(). Diese

Funktionen heiÿen Prozeduren.

Das Hauptprogramm hat immer als Parameter ein Feld args von String-Elementen.

In diesem Argument-Feld werden dem Programm

Kommandozeilen-Argumente verfügbar gemaht.

publi lass Test extends MiniJava {

publi stati void main (String [℄ args) {

write(args[0℄+arg s[ 1℄) ;

}

} // end of lass Test

(118)

java Test "Hel" "lo World!"

... die Ausgabe: Hello World!

(119)

erweitern/modizieren wir die Kontrolluss-Diagramme:

x = f(7,z); return 42;

f(x,y)

Funktionsaufruf Endknoten Startknoten

der Funktion

f

Für jede Funktion wird ein eigenes Teildiagramm erstellt.

Ein Aufrufknoten repäsentiert eine Teilberehnung der aufgerufenen Funktion.

(120)

result = a[0];

i = 1;

i = i+1;

a[i]<result

result = a[i];

i<a.length

no yes

no yes

min(a)

return result;

(121)

return a;

return;

n = read();

main(args)

result = min(a);

a = readArray(n);

min(a)

return result;

write(result);

readArray(n)

(122)

min(a)

return result;

n = read();

return;

return a;

readArray(n)

result = min(a);

a = readArray(n);

main(args)

write(result);

Aufruf

Rükkehr

(123)

min(a)

return result;

n = read();

return;

result = min(a);

a = readArray(n);

return a;

readArray(n) main(args)

write(result);

Rükkehr

Aufruf

(124)

Gegeben: eine Folge von ganzen Zahlen.

Gesuht: die zugehörige aufsteigend sortierte Folge.

(125)

Gegeben: eine Folge von ganzen Zahlen.

Gesuht: die zugehörige aufsteigend sortierte Folge.

Idee:

speihere die Folge in einem Feld ab;

lege ein weiteres Feld an;

füge der Reihe nah jedes Element des ersten Felds an der

rihtigen Stelle in das zweite Feld ein!

== ⇒

Sortieren durh Einfügen ...

(126)

int n = a.length;

int[℄ b = new int[n℄;

for (int i = 0; i < n; ++i)

insert (b, a[i℄, i);

// b = Feld, in das eingefügt wird

// a[i℄ = einzufügendes Element

// i = Anzahl von Elementen in b

return b;

} // end of sort ()

Teilproblem: Wie fügt man ein ???

(127)
(128)

17

(129)

17

(130)

3 17

(131)

3 17

(132)

17 3

-2

(133)

17 3

-2

(134)

3

-2 9 17

(135)

3 9 17 -2

(136)

3 9 17 -2 0

(137)

3 9 17 -2 0

(138)

17 9

-2 0 1 3

(139)

17 9

-2 0 1 3

(140)

17 9

-2 0 1 3 7

(141)

-2 0 1 3 7 9 17 42

(142)

7 9 17 42 -2 0 1 3

(143)

-2 0 1 3 5 7 9 17 42

(144)

int j = loate (b,x,i);

// findet die Einfügestelle j für x in b

shift (b,j,i);

// vershiebt in b die Elemente b[j℄,...,b[i-1℄

// nah rehts

b[j℄ = x;

}

Neue Teilprobleme:

Wie ndet man die Einfügestelle?

Wie vershiebt man nah rehts?

(145)

int j = 0;

while (j < i && x > b[j℄) ++j;

return j;

}

publi stati void shift (int[℄ b, int j, int i) {

for (int k = i-1; k >= j; --k)

b[k+1℄ = b[k℄;

}

Warum läuft die Iteration in shift() von i-1 abwärts nah j ?

Das zweite Argument des Operators && wird nur ausgewertet, sofern das erste true ergibt (Kurzshluss-Auswertung!). Sonst

würde hier auf eine uninitialisierte Variable zugegrien !!!

(146)

Das Feld b ist (ursprünglih) eine lokale Variable von sort().

Lokale Variablen sind nur im eigenen Funktionsrumpf sihtbar, niht in den aufgerufenen Funktionen !

Damit die aufgerufenen Hilfsfunktionen auf b zugreifen können, muss b explizit als Parameter übergeben werden !

Ahtung:

Das Feld wird niht kopiert. Das Argument ist der Wert der

Variablen b, also nur eine Referenz !

Deshalb benötigen weder insert(), noh shift() einen

separaten Rükgabewert ...

Weil das Problem so klein ist, würde eine erfahrene

Programmiererin hier keine Unterprogramme benutzen ...

(147)

int[℄ b = new int[a.length℄;

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

// begin of insert

int j = 0;

while (j < i && a[i℄ > b[j℄) ++j;

// end of loate

for (int k = i-1; k >= j; --k)

b[k+1℄ = b[k℄;

// end of shift

b[j℄ = a[i℄;

// end of insert

}

return b;

} // end of sort

(148)

Die Anzahl der ausgeführten Operationen wähst quadratish in der Gröÿe des Felds a ??

Gükliherweise gibt es Sortier-Verfahren, die eine bessere Laufzeit haben (

Algorithmen und Datenstrukturen).

(149)

Nehmen wir an, wir wollen herausnden, ob das Element 7 in

unserem Feld a enthalten ist.

Naives Vorgehen:

Wir vergleihen 7 der Reihe nah mit den Elementen a[0℄,

a[1℄, usw.

Finden wir ein i mit a[i℄ == 7, geben wir i aus.

Andernfalls geben wir -1 aus: Sorry, gibt's leider niht !

(150)

int i = 0;

while (i < a.length && a[i℄ != x)

++i;

if (i == a.length)

return -1;

else

return i;

}

(151)

17 3 -2 9 0 1 7 42 5

(152)

17 3 -2 9 0 1 7 42 5

(153)

17 3 -2 9 0 1 7 42 5

(154)

17 3 -2 9 0 1 7 42 5

(155)

17 3 -2 9 0 1 7 42 5

(156)

17 3 -2 9 0 1 7 42 5

(157)

17 3 -2 9 0 1 7 42 5

(158)

Im Beispiel benötigen wir 7 Vergleihe.

Im shlimmsten Fall benötigen wir bei einem Feld der Länge

n

sogar

n

Vergleihe ??

Kommt 7 tatsählih im Feld vor, benötigen wir selbst im

Durhshnitt

(n + 1)/2

viele Vergleihe ??

Geht das niht besser ???

(159)

Sortiere das Feld.

Vergleihe 7 mit dem Wert, der in der Mitte steht.

Liegt Gleihheit vor, sind wir fertig.

Ist 7 kleiner, brauhen wir nur noh links weitersuhen.

Ist 7 gröÿer, brauhen wir nur noh rehts weiter suhen.

== ⇒

binäre Suhe ...

(160)

0 1 3 5 7 9 17 42 -2

(161)

0 1 3 5 7 9 17 42 -2

(162)

0 1 3 5 7 9 17 42 -2

(163)

0 1 3 5 7

-2 9 17 42

(164)

0 1 3 5 7 9 17 42 -2

Referenzen

ÄHNLICHE DOKUMENTE

Sofern noh niht vorhanden, füge das neue Element als Blatt. so ein, dass die Suhbaumeigenshaft erfüllt ist,

Idee: zunähst Entsheidung, ob s[0℄ und t[0℄ einander. gegenübergestellt, oder eines

Dies soll jedoh in linearisierter Form erfolgen,.. insbesondere eine Operation immer nur

Sie wissen niht wo der Ferrari steht, können aber eine Tür wählen.. Der Spielleiter önet

Jeder Autofahrer a hat sein individuelles Risikoprol, das durh den Parameter ϑ a beshrieben wird... Jeder Autofahrer a hat sein individuelles Risikoprol, das durh den Parameter ϑ

Jeder Autofahrer a hat sein individuelles Risikoprol, das durh den Parameter ϑ a beshrieben wird... Jeder Autofahrer a hat sein individuelles Risikoprol, das durh den Parameter ϑ

Man spriht von einer 100 Jahr Flut, falls durhshnittlih jede hundert Jahre eine.. Flut mit mindestens dieser

Resnik: Heavy Tailed Phenomena (Springer) 2006. Coles, S (2001): An Introdution to Statistial Modeling