Algorithmen und Datenstrukturen II

Werbung
Datenstrukturen in Java
Datenstrukturen in Java
Gliederung
Algorithmen und Datenstrukturen II
1
Datenstrukturen in Java
Datenstrukturen in Java
Listen
Node
LinkedList
Abstraktion
D. Rösner
Stack
Institut für Wissens- und Sprachverarbeitung
Fakultät für Informatik
Otto-von-Guericke Universität Magdeburg
Interface
Implementierung
LinkedStack
Beispiel
c
Sommer 2009, 4. Mai 2009, 2009
D.Rösner
D. Rösner AuD II 2009 . . .
Datenstrukturen in Java
D. Rösner AuD II 2009 . . .
1
Listen
Stack
Datenstrukturen in Java
Java: Listen
2
Listen
Stack
Java: Listen
Klasse für Knoten in Java
public class Node {
einfach verkettete Listen (engl. singly linked lists)
// Instance variables:
Grundbaustein:
Knoten, der Referenz auf ein Element und Referenz auf
den Folgeknoten speichert
lineare Ordnung der Elemente
Ende der Liste, wenn Folgeknoten-Verweis auf null
private Object element;
// beliebige Objekte als Elemente
s.a. [GT01] bzw. [SS02]
private Node next;
// Folgeknoten
...
D. Rösner AuD II 2009 . . .
4
D. Rösner AuD II 2009 . . .
5
Datenstrukturen in Java
Listen
Stack
Datenstrukturen in Java
Java: Listen
Listen
Stack
Java: Listen
...
// Selektoren
Object getElement() {
return element;
}
Node getNext() {
return next;
}
Klasse für Knoten cont.
...
// Konstruktoren
public Node() {
this(null, null);
}
// Modifikatoren
void setElement(Object newElem) {
element = newElem;
}
void setNext(Node newNext) {
next = newNext;
}
public Node(Object e, Node n) {
element = e;
next = n;
}
...
D. Rösner AuD II 2009 . . .
Datenstrukturen in Java
6
}
D. Rösner AuD II 2009 . . .
Listen
Stack
Datenstrukturen in Java
Java: Listen
7
Listen
Stack
Java: Listen
Klasse LinkedList
public class LinkedList {
// Instance variables:
Operation: Einfügen eines neuen Knoten am Kopf einer
Liste
Ablauf:
//
Zeiger auf Listenbeginn
private Node head;
kreiere neuen Knoten
dessen next zeige auf das von head referenzierte Objekt
head zeige auf neuen Knoten
//
Laenge der Liste
private int length;
Zeitbedarf konstant, d.h. O(1)
// optional: Zeiger auf letztes
//
Element
private Node last;
...
D. Rösner AuD II 2009 . . .
8
D. Rösner AuD II 2009 . . .
9
Datenstrukturen in Java
Listen
Stack
Datenstrukturen in Java
Java: Listen
Listen
Stack
Java: Listen
Operationen am Ende einer Liste
Bemerkungen zu Listen
Einfügen eines neuen Elements:
wenn Referenz auf letztes Listenelement verfügbar, analog
zum Einfügen am Kopf in konstanter Zeit
Entfernen:
selbst wenn Referenz auf letztes Listenelement verfügbar,
ist der letzte Knoten in einer einfach verketteten liste nicht
in konstanter Zeit entfernbar, da der vorletzte Knoten nur
ausgehend vom Listenbeginn erreicht werden kann
D. Rösner AuD II 2009 . . .
Datenstrukturen in Java
rekursiv definierte Datenstruktur:
eine Liste ist entweder leer oder sie hat ein erstes Element
und einen Rest, der Liste ist
damit: viele Operationen auf Listen rekursiv
Listenelemente können selbst Listen sein (verschachtelte
Listen)
durch entsprechende Verkettung von Knoten lassen sich
auch zirkuläre Listen kreieren
D. Rösner AuD II 2009 . . .
10
Listen
Stack
Datenstrukturen in Java
Java: Algorithmen auf Listen
Listen
Stack
Java: Listen
Abstraktion: einer Liste wird ein Wert zugewiesen
Aufbau:
die induktive Definition des ADT Liste spiegelt sich in
vielen Algorithmen auf Listen direkt wieder
viele Algorithmen folgen dabei abstrakten Mustern
z.B. Muster: Rekursion mit Restliste (tail recursion)
vgl. rekursive Berechnung der Länge einer Liste
if (isEmpty(list))
return <Wert-fuer-leere-Liste>;
else return <Wert-fuer-erstes-Element>
<verknuepft-mit>
<Wert-fuer-Rest-der-Liste>;
public static int length(LinkedList list) {
if (isEmpty(list))
return 0;
else return 1 + length(rest(list));
}
Variante:
if (isSingleton(list))
return <Wert-fuer-einelementige-Liste>;
else return <Wert-fuer-erstes-Element>
<verknuepft-mit>
<Wert-fuer-Rest-der-Liste>;
Bem: O(n); effizienter mit Verwendung und Fortschreibung
einer Instanzvariable size
D. Rösner AuD II 2009 . . .
11
12
D. Rösner AuD II 2009 . . .
13
Datenstrukturen in Java
Listen
Stack
Datenstrukturen in Java
Java: Listen
Listen
Stack
Java: Listen
Beispiele für Abstraktion: einer Liste wird ein Wert
zugewiesen
Bestimmung des Produkts der Werte in einer Zahlenliste
Bestimmung der Summe der Werte in einer Zahlenliste
public static int listProd(LinkedList list) {
// list enthalte nur Zahlen
if (isEmpty(list))
return 1;
else return firstElem(list) * listProd(rest(list));
}
public static int listSum(LinkedList list) {
// list enthalte nur Zahlen
if (isEmpty(list))
return 0;
else return firstElem(list) + listSum(rest(list));
}
D. Rösner AuD II 2009 . . .
Datenstrukturen in Java
14
D. Rösner AuD II 2009 . . .
Listen
Stack
Datenstrukturen in Java
Java: Listen
15
Listen
Stack
Java: Listen
Prädikate auf Listen über Prädikate auf Elementen
Beispiele für Abstraktion cont.
Muster: Prädikate auf Listen, die dann true, wenn ein
Elementprädikat für alle Listenelemente zutrifft
Bestimmung des grössten Werts in einer Zahlenliste
public static int listMax(LinkedList list) {
// list enthalte nur Zahlen
if (isSingleton(list))
return firstElem(list);
else return max(firstElem(list),
listMax(rest(list)));
}
D. Rösner AuD II 2009 . . .
Muster:
if (isEmpty(list))
return true;
else return (<elemPraed>(firstElem(list))
&& <listPraed>(rest(list)));
16
D. Rösner AuD II 2009 . . .
17
Datenstrukturen in Java
Listen
Stack
Datenstrukturen in Java
Java: Listen
Listen
Stack
Java: Listen
Muster: Filtern einer Liste mit einem Prädikat
Prädikate auf Listen cont.
ein Prädikat wird auf die Elemente einer Liste angewendet
Muster: Prädikate auf Listen, die dann true, wenn ein
Element existiert, auf das ein Elementprädikat zutrifft
Ergebnis ist eine Liste, in der nur noch die Elemente
enthalten sind, auf die das Prädikat zutrifft
Muster:
if (isEmpty(list))
return list;
else if (<Praedikat>(firstElem(list)))
return new Linkedlist(firstElem(list),
<Filter>(rest(list)));
else <Filter>(rest(list));
if (isEmpty(list))
return false;
else return (<elemPraed>(firstElem(list))
|| <listPraed>(rest(list)));
D. Rösner AuD II 2009 . . .
Datenstrukturen in Java
D. Rösner AuD II 2009 . . .
18
Listen
Stack
Datenstrukturen in Java
Java: Stack
19
Listen
Stack
Java: Stack
abstrakter Datentyp Stack
abstrakter Datentyp (ADT):
spezifiziert durch Angabe von
LIFO-Prinzip: last-in, first-out
zwei zentrale Operationen:
push(obj)
Input: obj; Output: void
füge obj als neues oberstes Element in den Stack ein
pop()
Input: (); Output: obj
entferne das aktuelle oberste Element vom Stack und gib
es als Wert zurück; Fehler, falls Stack leer
Konstruktor(en)
Selektor(en)
Prädikat(en)
Modifikator(en)
in Java: Spezifikation eines ADT durch Definition eines
Interface
D. Rösner AuD II 2009 . . .
21
D. Rösner AuD II 2009 . . .
22
Datenstrukturen in Java
Listen
Stack
Datenstrukturen in Java
Java: Stack
Listen
Stack
Java: Stack
Interface für Stack
(vgl. [GT01], Ch. 4.1])
Interface für Stack cont.
public interface Stack {
...
// Hilfsmethoden
// Kernmethoden
/**
* @return number of elements in the stack.
*/
public int size();
/**
* Insert an element at the top of the stack.
*/
public void push (Object element);
/**
* @return true if the stack is empty,
* false otherwise.
*/
public boolean isEmpty();
/**
* Remove the top element from the stack.
* @return element removed.
*/
public Object pop()
throws StackEmptyException;
...
D. Rösner AuD II 2009 . . .
Datenstrukturen in Java
23
D. Rösner AuD II 2009 . . .
Listen
Stack
Datenstrukturen in Java
Java: Stack
24
Listen
Stack
Java: Stack
Implementierung des ADT Stack mit konkretem Datentyp
Array (vgl. [GT01], Ch. 4.1)
public class ArrayStack implements Stack {
/**
* Default length of array used to implement the stack.
*/
public static final int CAPACITY = 1000;
/**
* Lenght of the array used to implement the stack.
*/
private int capacity;
/**
* Array used to implement the stack.
*/
private Object S[];
/**
* Index of the top element of the stack in the array.
*/
private int top = -1;
...
Interface für Stack cont.
/**
* @return top element in the stack.
* @exception StackEmptyException if the stack is empty.
*/
public Object top()
throws StackEmptyException;
}
D. Rösner AuD II 2009 . . .
25
D. Rösner AuD II 2009 . . .
26
Datenstrukturen in Java
Listen
Stack
Datenstrukturen in Java
Java: Stack
Listen
Stack
Java: Stack
Implementierung mit Array cont.
...
/**
* Initialize the stack to use an array
* of default length CAPACITY.
*/
public ArrayStack() {
this(CAPACITY);
}
...
/**
* Initialize the stack to use an array
* of given length.
* @param cap length of the array.
*/
public ArrayStack(int cap) {
capacity = cap;
S = new Object[capacity];
}
...
D. Rösner AuD II 2009 . . .
Datenstrukturen in Java
Implementierung mit Array cont.
...
/**
* O(1) time.
*/
public int size() {
return (top + 1);
}
...
/**
* O(1) time.
*/
public boolean isEmpty() {
return (top < 0);
}
27
D. Rösner AuD II 2009 . . .
Listen
Stack
Datenstrukturen in Java
Java: Stack
28
Listen
Stack
Java: Stack
Implementierung mit Array cont.
Implementierung mit Array cont.
/**
* O(1) time.
* @exception StackFullException if the array is full.
*/
public void push(Object obj)
throws StackFullException {
if (size() == capacity)
throw new StackFullException("Stack overflow.");
S[++top] = obj;
}
...
D. Rösner AuD II 2009 . . .
...
/**
* O(1) time.
*/
public Object top() throws StackEmptyException {
if (isEmpty())
throw new StackEmptyException("Stack is empty.");
return S[top];
}
29
D. Rösner AuD II 2009 . . .
30
Datenstrukturen in Java
Listen
Stack
Datenstrukturen in Java
Java: Stack
Listen
Stack
Java: Stack
Implementierung mit Array cont.
Stacks werden in vielen Situationen verwendet
Beispiele:
/**
* O(1) time.
*/
public Object pop() throws StackEmptyException {
Object elem;
if (isEmpty())
throw new StackEmptyException("Stack is Empty.");
elem = S[top];
S[top--] = null;
// dereference S[top] for garbage collection.
return elem;
}
}
D. Rösner AuD II 2009 . . .
Datenstrukturen in Java
WWW-Browser: Stack der zuletzt besuchten Seiten;
verwendet für Operation Back
Editoren: Stack der zuletzt ausgeführten Befehle;
verwendet für Operation Undo
bei der Programmabarbeitung: Stack der offenen
Methodenaufrufe
Operandenstack beim Auswerten arithmetischer Ausdrücke
u.v.a.m.
D. Rösner AuD II 2009 . . .
31
Listen
Stack
Datenstrukturen in Java
Java: Stack
32
Listen
Stack
Java: Stack
Beispiel: Verwendung eines Stack zum ‘Umdrehen’ eines
Array (vgl. [GT01], Ch. 4.1)
vordefinierte Klasse Stack in Java
Klasse java.util.Stack
speichert beliebige Java-Objekte
Kernmethoden: push(obj) , pop()
Hilfsmethoden: peek() (entspricht: top() )
size(), empty() (entspricht: isEmpty() )
peek() und pop() werfen bei leerem Stack die
StackEmptyException
public static Integer[] reverse(Integer[] a) {
ArrayStack S = new ArrayStack(a.length);
Integer[] b = new Integer[a.length];
for (int i=0; i < a.length; i++)
S.push(a[i]);
for (int i=0; i < a.length; i++)
b[i] = (Integer) (S.pop());
// Beachte: Casting erforderlich !
return b;
}
D. Rösner AuD II 2009 . . .
33
D. Rösner AuD II 2009 . . .
34
Datenstrukturen in Java
Listen
Stack
Datenstrukturen in Java
Java: Stack
Listen
Stack
Java: Stack
Stack als Liste
public class LinkedStack implements Stack {
// Instanzvariable
private Node top; // oberstes Element
private int size; // Groesse des Stack
Stack mit einer einfach verketteten Liste implementieren
im Prinzip könnte Einfügen/Entfernen am Listenanfang
oder am Listenende erfolgen
Einfügen/Entfernen am Listenanfang ist aber O(1) für beide
Operationen
Speicherbedarf ist O(n) mit n Anzahl der Listenelemente
beachte: bei der folgenden Implementierung kann Problem
des Stack-Überlauf auf Laufzeitsystem verlagert werden
(OutOfMemoryError)
D. Rösner AuD II 2009 . . .
Datenstrukturen in Java
35
// Konstruktor
public LinkedStack() {
top = null;
size = 0;
}
// Selektor fuer Groesse
public int size() {
return size;
}
// Praedikat
public boolean isEmpty() {
if (top == null)
return true;
return false;
}
D. Rösner AuD II 2009 . . .
...
Listen
Stack
Datenstrukturen in Java
Java: Stack
36
Listen
Stack
Java: Stack
Stack als Liste cont.
Stack als Liste cont.
...
public void push(Object elem) {
Node v = new Node(); // neuer Knoten
v.setElement(elem);
v.setNext(top); // ‘Einbauen’ des neuen Knoten
top = v;
size++;
// ‘Buchfuehrung’ fuer Groesse
}
...
public Object pop()
throws StackEmptyException {
if (isEmpty())
throw
new StackEmptyException("Stack is empty.");
Object temp = top.getElement();
top = top.getNext();
// Entfernen des obersten Elements
size--;
// ‘Buchfuehrung’ fuer Groesse
return temp;
}
}
public Object top() throws StackEmptyException {
if (isEmpty())
throw new StackEmptyException("Stack is empty.");
return top.getElement();
}
...
D. Rösner AuD II 2009 . . .
37
D. Rösner AuD II 2009 . . .
38
Datenstrukturen in Java
Listen
Stack
Datenstrukturen in Java
Java: Stack
Listen
Stack
Java: Stack
Anwendung eines Stack: Berechnung von Spannen
Definition
Die Spanne eines Preises an einem bestimmten Tag einer
Zeitreihe sei die maximale Zahl aufeinanderfolgender Tage bis
zum aktuellen Tag, an dem der Preis niedriger als oder
höchstens gleich dem aktuellen Preis war.
Ein quadratischer Algorithmus für Berechnung von
Spannen (vgl. [GT01], Ch. 4.5])
Idee: für jedes i = 0 bis n - 1:
Vergleiche P[i] mit P[i-k] für k = 0, 1, 2, ..., i
solange wie P[i-k] ≤ P[i]
Formal:
Preisaufzeichnungen beginnen mit Tag 0
pi sei Preis am Tag i
Spanne si am Tag i ist das grösste ganzzahlige k mit k ≤ i +
1 und
pj ≤ pi für alle j = i - k + 1, i - k + 2, ... , i
D. Rösner AuD II 2009 . . .
Datenstrukturen in Java
D. Rösner AuD II 2009 . . .
39
Listen
Stack
Datenstrukturen in Java
Java: Stack
40
Listen
Stack
Java: Stack
Ein quadratischer Algorithmus für Berechnung von
Spannen
Analyse von ComputeSpans1
Initialisieren und Rückgabe des Array S erfordert für jedes
Element konstanten Aufwand, also O(n)
repeat-Schleife innerhalb for-Schleife
for-Schleife wird n-mal ausgeführt
die Befehle dort ausserhalb des repeat werden n-mal
ausgeführt und tragen O(n) zum Gesamtaufwand bei
bei i-ter Iteration der for-Schleife wird Körper des repeat
höchstens (i + 1)-mal ausgeführt
[worst case: P[i] grösser als alle vorausgegangen P[i-k]]
m.a.W. höchstens 1 + 2 + 3 + ... + n Beiträge aus
repeat-loop, d.h. O(n (n+1) /2) = O(n2 )
Pseudocode:
Algorithm computeSpans1(P)
Input: ein n-el. Array P von Zahlen
Output: ein n-el. Array S mit Spannen
for i ← 0 to n - 1 do
k←0
done ← false
repeat
if P[i-k] ≤ P[i] then
k←k+1
else
done ← true
until (k > i) or done
S[i] ← k
return array S
D. Rösner AuD II 2009 . . .
41
D. Rösner AuD II 2009 . . .
42
Datenstrukturen in Java
Listen
Stack
Datenstrukturen in Java
Java: Stack
Listen
Stack
Java: Stack
Algorithmus mit linearem Aufwand
Algorithmus mit linearem Aufwand
Für effizientere Berechnung der Spannen:
beim Übergang von Tag i - 1 auf Tag i wird der Preis am
Tag i mit dem obersten Stackelement verglichen:
wenn für Tag i derjenige Tag h(i) bekannt, der i vorausgeht
und der - von i ausgehend - der nächste ist, an dem der
Preis grösser ist als am Tag i, dann
si = i - h(i)
beim Berechnen der Spannen werden in einem Stack nur
diese Tage mit grössten Preisen mitgeführt, d.h. i, h(i),
h(h(i)), . . .
D. Rösner AuD II 2009 . . .
Datenstrukturen in Java
ist der Preis des obersten Stackelements kleiner oder gleich
dem pi wird solange pop() ausgeführt, bis entweder ein
oberstes Stackelement auftaucht, dessen Preis grösser als
pi , oder bis Stack leer
i wird in Stack gepusht
D. Rösner AuD II 2009 . . .
43
Listen
Stack
Datenstrukturen in Java
Java: Stack
44
Listen
Stack
Java: Stack
Ein linearer Algorithmus für Berechnung von Spannen
Pseudocode:
Algorithm computeSpans2(P)
Input: ein n-el. Array P von Zahlen und
ein leerer Stack D
Output: ein n-el. Array S mit Spannen
for i ← 0 to n - 1 do
done ← false
while not (D.isEmpty() or done) do
if P[i] ≥ P[D.top()] then
D.pop()
else
done ← true
if D.isEmpty() then
h ← -1
else
h ← D.top()
S[i] ← i - h
D.push(i)
return array S
D. Rösner AuD II 2009 . . .
Java Implementation
public void computeDailyHighSpan (Quote Q[]) {
int prevHigh; // closest preceding day
// when the stock price was higher
Stack D = new ArrayStack();
...
45
D. Rösner AuD II 2009 . . .
46
Datenstrukturen in Java
Listen
Stack
Datenstrukturen in Java
Java: Stack
Listen
Stack
Java: Stack
Java Implementation
Berechnung von Spannen
Hilfsklasse:
...
for (int i = 0 ; i < Q.length ; i++) {
// process the current day i
while ( !D.isEmpty() &&
Q[i].getPrice() >=
((Quote) D.top()).getPrice() )
D.pop();
if (D.isEmpty())
prevHigh = -1;
// day i is a new high for the stock price
else
prevHigh = ((Quote) D.top()).getDay();
Q[i].setSpan(i - prevHigh);
// compute and store the span
D.push(Q[i]);
// add to the stack the current quote
}
public class Quote {
private int day, price, span;
public Quote(int d, int p) {
setDay(d);
setPrice(p);
}
public void setDay(int d) { day = d; }
public int getDay() { return day; }
public void setPrice(int p) { price = p; }
public int getPrice() { return price; }
public void setSpan(int s) { span = s; }
public int getSpan() { return span; }
}
}
D. Rösner AuD II 2009 . . .
Datenstrukturen in Java
47
Listen
Stack
Literatur: I
Michael T. Goodrich and Roberto Tamassia.
Data Structures and Algorithms in Java.
John Wiley & Sons, New York, 2001.
ISBN 0-471-38367-8; 2nd edition.
Gunter Saake and Kai-Uwe Sattler.
Algorithmen und Datenstrukturen – Eine Einführung mit
Java.
dpunkt.verlag, Heidelberg, 2002.
ISBN 3-89864-122-8.
D. Rösner AuD II 2009 . . .
49
D. Rösner AuD II 2009 . . .
48
Herunterladen