3. Übungsblatt zu Algorithmen I im SS 2010

Ähnliche Dokumente
3. Übungsblatt zu Algorithmen I im SoSe 2017

Übungsklausur Algorithmen I

Beispiellösung zu den Übungen Datenstrukturen und Algorithmen SS 2008 Blatt 5

3. Übung Algorithmen I

Grundlagen Algorithmen und Datenstrukturen Kapitel 13


Kapitel 2: Analyse der Laufzeit von Algorithmen Gliederung

Verkettete Listen. KIT Institut für Theoretische Informatik 1

Vorlesung Informatik 2 Algorithmen und Datenstrukturen

Informatik II, SS 2014

8 Elementare Datenstrukturen

1. Übungsblatt zu Algorithmen II im WS 2011/2012

Counting - Sort [ [ ] [ [ ] 1. SS 2008 Datenstrukturen und Algorithmen Sortieren in linearer Zeit

Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 11/12 1. Kapitel 11. Listen. Listen

Vorlesung Informatik 2 Algorithmen und Datenstrukturen

Übung: Algorithmen und Datenstrukturen SS 2007

C- Kurs 09 Dynamische Datenstrukturen

Algorithmen und Datenstrukturen

Algorithmen und Datenstrukturen VO 3.0 Vorlesungsprüfung 19. Oktober 2007

11. Elementare Datenstrukturen

14. Rot-Schwarz-Bäume

Praxis der Programmierung

6. Verkettete Strukturen: Listen

INSTITUT FÜR THEORETISCHE INFORMATIK, PROF. SANDERS

12. Hashing. Hashing einfache Methode um Wörtebücher zu implementieren, d.h. Hashing unterstützt die Operationen Search, Insert, Delete.

Theoretische Informatik SS 03 Übung 3

Schwerpunkte. Verkettete Listen. Verkettete Listen: 7. Verkettete Strukturen: Listen. Überblick und Grundprinzip. Vergleich: Arrays verkettete Listen

Algorithmen und Datenstrukturen (ESE) Entwurf, Analyse und Umsetzung von Algorithmen (IEMS) WS 2013 / Vorlesung 7, Donnerstag 5.

Master Theorem Beispiele

Programmieren in C. Rekursive Strukturen. Prof. Dr. Nikolaus Wulff

12. Dynamische Datenstrukturen

Informatik II, SS 2014

Amortisierte Analysen

8. A & D - Heapsort. Werden sehen, wie wir durch geschicktes Organsieren von Daten effiziente Algorithmen entwerfen können.

Datenstrukturen & Algorithmen Lösungen zu Blatt 5 FS 14

Suchbäume balancieren

Algorithmen und Datenstrukturen

Übungspaket 31 Entwicklung eines einfachen Kellerspeiches (Stacks)

Übersicht. Berechnung der Potenz für zwei ganze Zahlen Klausuraufgabe SS 2010! Berechnung der Cosinus-Funktion Klausuraufgabe WS 2010/2011!

Übung zur Vorlesung Berechenbarkeit und Komplexität

Algorithm Engineering. Alexander Kröller, Abteilung Algorithmik, IBR

Probeklausur: Programmierung WS04/05

Einfach verkettete Liste

Algorithmen und Datenstrukturen

Algorithmen & Datenstrukturen 1. Klausur

Algorithmen und Datenstrukturen

Grundlagen der Informatik. Prof. Dr. Stefan Enderle NTA Isny

Informatik II, SS 2014

Abgabe: (vor der Vorlesung) Aufgabe 2.1 (P) O-Notation Beweisen Sie die folgenden Aussagen für positive Funktionen f und g:

VBA-Programmierung: Zusammenfassung

Freispeicherverwaltung Martin Wahl,

Algorithmen und Datenstrukturen (ESE) Entwurf, Analyse und Umsetzung von Algorithmen (IEMS) WS 2014 / Vorlesung 10, Donnerstag 8.

Über Arrays und verkettete Listen Listen in Delphi

Grundbegriffe der Informatik

Lösungsvorschlag 1. Vorlesung Algorithmentechnik im WS 09/10

15. Elementare Graphalgorithmen

Theoretische Informatik 1 WS 2007/2008. Prof. Dr. Rainer Lütticke

Algorithmen II Vorlesung am

Höhere Mathematik II für die Fachrichtung Informatik. Lösungsvorschläge zum 1. Übungsblatt

Einführung in die Programmierung mit C++

Übungen zu Programmierung I - Blatt 8

Schnittstellen, Stack und Queue

Online-Algorithmen. Proseminar von Prof. Dr. Rolf Klein, Dr. Elmar Langetepe, Dipl. Inform. Thomas Kamphans im Wintersemester 00/01

Verkettete Listen. Implementierung von einfach verketteten Listen. Implementierung von doppelt verketteten Listen

Stephan Brumme, SST, 2.FS, Matrikelnr

Algorithmen und Datenstrukturen

Algorithmen und Datenstrukturen (für ET/IT) Wiederholung: Ziele der Vorlesung. Wintersemester 2012/13. Dr. Tobias Lasser

Klausur Algorithmen und Datenstrukturen

1. Musterlösung. Problem 1: Average-case-Laufzeit vs. Worst-case-Laufzeit

Übung: Algorithmen und Datenstrukturen SS 2007

Informatik II, SS 2014

Algorithmen & Komplexität

= 7 (In Binärdarstellung: = 0111; Unterlauf) = -8 (In Binärdarstellung: = 1000; Überlauf)

Assertions (Zusicherungen)

11. Übungsblatt zu Algorithmen I im SS 2010

Algorithmen und Datenstrukturen in der Bioinformatik Viertes Übungsblatt WS 05/06 Musterlösung

Theoretische Informatik SS 03 Übung 4

Informatik II, SS 2014

Grundlagen: Algorithmen und Datenstrukturen

Vorlesung Informatik 2 Algorithmen und Datenstrukturen

Tutoraufgabe 1 (Sortieren): Lösung: Datenstrukturen und Algorithmen SS14 Lösung - Übung 4

Informatik I WS 07/08 Tutorium 24

Student: Alexander Carls Matrikelnummer: Aufgabe: Beschreibung des euklidischen Algorithmus Datum:

Informatik II, SS 2014

Algorithmen und Datenstrukturen

Programmieren in C. Speicher anfordern, Unions und Bitfelder. Prof. Dr. Nikolaus Wulff

Dynamischer Speicher

Grundlagen der Künstlichen Intelligenz

Datenstrukturen. Mariano Zelke. Sommersemester 2012

Datenstrukturen & Algorithmen Lösungen zu Blatt 6 FS 14

9. Übung Algorithmen I

Algorithmische Intelligenz. Amortisierung. Stefan Edelkamp

C# - Einführung in die Programmiersprache Arrays, Enumeration und Collections. Leibniz Universität IT Services Anja Aue

Hochschule Augsburg, Fakultät für Informatik Name:... Prüfung "Programmieren 1", IN1bac, WS 10/11 Seite 1 von 6

Effiziente Algorithmen und Datenstrukturen I. Kapitel 9: Minimale Spannbäume

Programmierung im Grossen

Klausur Algorithmen und Datenstrukturen II 29. Juli 2013

Algorithmen & Datenstrukturen Lösungen zu Blatt 9 HS 16

Informatik B Sommersemester Musterlösung zur Klausur vom

Algorithmen und Datenstrukturen 2

Transkript:

Karlsruher Institut für Technologie Institut für Theoretische Informatik Prof. Dr. Peter Sanders G.V. Batz, C. Schulz, J. Speck 3. Übungsblatt zu Algorithmen I im SS 2010 http://algo2.iti.kit.edu/algorithmeni.php {sanders,batz,christian.schulz,speck}@kit.edu Aufgabe 1 (Amortisierte Analyse, 2 + 4 + 2) Musterlösungen Auf einer Datenstruktur wird eine Sequenz σ = (σ 1,, σ n ) von Operationen ausgefüht. Die Operation σ i kostet i, wenn i eine Potenz von zwei ist, sonst 1. Mit anderen Worten: a) Berechnen Sie die Kosten für 16 Operationen T (16). b) Geben Sie eine geschlossene Form T (n) für die Kosten von n Operationen an. Nehmen Sie dabei vereinfachend an, dass n = 2 m für ein m N ist. c) Wie groß sind dann die amortisierten Kosten pro Operation? Schätzen Sie die amortisierten Kosten auch in O-Notation ab. Musterlösung: a) Auflisten der Operationen und deren Kosten ergibt folgende Tabelle: Op. No. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 cost(i) 1 2 1 4 1 1 1 8 1 1 1 1 1 1 1 16 Aufsummieren der Kosten liefert T (16) = 42. b) Wir zeigen T (n) = 3n log n 2 auf zwei verschiedenen Wegen, die beide darlegen wie man auf diese Formel kommt. Es ist zunächst S(m) := T (2 m ) = T (n) = 2 m i=1 cost(i) Es ist n = 2 m. Nun stellt man S(m) als Rekurrenz dar, um nachher eine schöne Summenformel zu bekommen. Das überlegt man sich folgendermaßen: Beim Übergang von m 1 nach m haben alle Zahlen zwischen 2 m 1 und 2 m Kosten cost(i) = 1. Das sind genau 2 m 2 m 1 1 viele. Die einzige Operation die höhere Kosten hat ist die Letzte. Sie hat Kosten cost(2 m ) = 2 m. Also ist S(m) = S(m 1)+2 m +(2 m 2 m 1 1) = S(m 1)+3 2 m 1 1. Ausrollen der Rekurrenz ergibt: S(m) = m 1 i=1 (3 2i 1) = 3 m 1 i=0 2i (m 1) 3 = 3 2 m m 2. Und da m = log n liefert uns rücksubstituieren eine Formel für T nämlich: T (n) = 3n log n 2. Die zweite Möglichkeit diese Formel zu zeigen ist die Folgende: Im Wesentlichen teilt man die Kosten für S(m) = S 1 (m)+s 2 (m) in zwei Hälften. S 1 (m) seien dabei gerade die Kosten für die Operationen die jeweils Kosten 1 haben und S 2 (m) für die Operationen mit Kosten > 1. Unter den 2 m Operationen gibt es genau m, die Kosten > 1 haben (nämlich genau die zweier Potenzen, 1 ausgenommen). Also ergibt sich S 1 (m) = 2 m m. Die Operationen mit Kosten >1 sind genau die zweier Potenzen. Also S 2 (m) = m i=1 2i = 1 + m i=0 2i = 2 m+1 2. Also ist S(m) = 2 m m + 2 m+1 2 = 2 m (2 + 1) m 2 = 3 2 m m 2 und damit T (n) = 3n log n 2. c) Als amortisierte Kosten pro Operation ergibt sich T (n) n = 3 log n/n 3. Das liefert T (n)/n = O(1), also konstante amortisierte Kosten pro Operation. 1

Aufgabe 2 (Stack, Queue und Deque mittels einfach verketteter Liste, 3 + 3 + 2 Punkte) a) Wie baut man einen unbeschränkten Stack mittels einer einfach verketteten Liste? Geben Sie hierzu Implementierungen von pushfront und popfront in Pseudocode an, so dass die Operationen jeweils nur konstante Zeit benötigen. Dabei darf keine bereits fertig implementierte Datenstruktur verwendet werden, d.h. Sie müssen alles selbst bauen. b) Wie baut man eine unbeschränkte Queue mittels einer einfach verketteten Liste? Erweitern Sie hierzu Ihre Implementierung aus Teilaufgabe a) um eine Operation pushback und geben Sie diese in Pseudocode an, so dass die Operation nur konstante Zeit benötigt. c) Eine Double-Ended Queue (Deque) hat die Operationen pushfront, pushback, popfront und popback. Lässt sich auch eine Deque mit einer einfach verketteten Liste so konstruieren, dass die Operationen pushfront, pushback, popfront und popback alle nur konstante Zeit benötigen? Oder braucht man z.b. eine doppelt verkettete Liste? Begründen Sie kurz! Musterlösung: a) Bitte beachten Sie, dass bei dieser Lösung die einfach verkettete Liste stets einen Kreis bildet. Das wird schon beim erschaffen eines neuen Listen Items sichergestellt, indem next immer auf das Item selbst zeigt. Außerdem gibt es ein Kopf-Item. D.h. die leere Liste wird durch ein Item dargestellt, bei dem next auf das Item selbst verweist. So werden die Einzelteile der einfach verketteten Liste dargestellt: 1: class SinglyLinkedListItem of Element 2: next := this : Handle // WICHTIG: bei neuen Items zeigt next auf das Item selbst 3: e : Element 4: end class Der Stack selbst: 1: class Stack of Element 2: invariant Die Liste mit Kopf-Item data bildet einen Kreis oder eine Schleife. 3: data := allocate SinglyLinkedListItem of Element : Handle 4: procedure pushfront(e : Element) 5: old first := data.next : Handle 6: data.next := allocate SinglyLinkedListItem 7: data.next.e := e 8: data.next.next := old first // Liste wieder ein Kreis oder eine Schleife 9: end procedure 10: procedure popfront 11: assert data.next data // popfront sinnlos bei leerer Queue 12: old first := data.next : Handle 13: data.next := data.next.next // Liste wieder ein Kreis oder eine Schleife 14: dispose old first 15: end procedure 16: end class b) Hier muss die Klasse aus Teilaufgabe a) lediglich erweitert werden. Wir schreiben das mit Hilfe einer Art Vererbung auf, wie vom objektorientierten Programmieren bekannt: 1: class Queue of Element is a Stack of Element 2: procedure pushback(e : Element) 3: pushfront( ) 4: data.e = e 5: data := data.next 6: end procedure 7: end class 2

c) In a) und b) wurde schon die Operationen pushfront, pushback und popfront in konstanter Zeit realisiert. Die Operation popback aber kann man mit einer einfach verketteten Liste nicht ohne weiteres in konstanter Zeit ausführen. Das liegt daran, dass man vom Einstiegspunkt in die Liste aus gesehen keinen Handle zum anderen Ende hat. Somit kann auf das andere Ende nicht in konstanter Zeit zugegriffen werden. Dort müssen beim entfernen des letzten Elementes aber die Handles richtig gesetzt werden. Natürlich kann man sich einen bzw. eine feste Anzahl Handles auf das letzte Element bzw. die letzten Elemente merken und diese Handles dann in popback verwenden. Man kann aber immer ein popback mehr ausführen als man Handles hat, was diesen Trick aushebelt. Mit einer doppelt verketteten Liste wäre das kein Problem. Aufgabe 3 (Queue mittels Arrays, 3 + 3 Punkte) Wie baut man eine unbeschränkte Queue mit Hilfe von (unbeschränkten) Arrays? a) Geben Sie hierzu Implementierungen von pushback und popfront in Pseudocode an, so dass die Operationen jeweils nur amortisiert konstante Zeit benötigen. b) Zeigen Sie, dass pushback und popfront, wie von Ihnen in a) angegeben, tatsächlich das gewünschte Zeitverhalten aufweisen. Musterlösung: a) 1: class Queue of Element 2: capacity := 1 : N >0 3: data := allocate BoundedFifo(1) of Element 4: procedure reallocate(capacity : N >0 ) 5: data := allocate BoundedFifo(capacity ) of Element 6: while data.isempty do // loop copies all elements of data to data 7: data.pushback(data.first) 8: data.popfront 9: end while 10: dispose data 11: data := data // pointer assignment 12: capacity := capacity 13: end procedure 14: procedure pushback(e : Element) 15: if data.size = capacity then reallocate(2 capacity) 16: data.pushback(e) 17: end procedure 18: procedure popfront 19: assert data.isempty 20: data.popfront 21: if 4 data.size capacity data.size > 0 then reallocate(2 data.size) 22: end procedure 23: end class b) Die amortiesierten Laufzeiten ermitteln wir mit der Bankkontomethode. Die einzige Operation, die mehr als konstante Zeit benötigt, ist reallocate: Sie kopiert jeweils data.size Elemente. Das kopieren eines Elementes koste jeweils einen Token. Um das auszugleichen zahlen wir für jedes pushback zwei Token und für jedes popfront einen Token auf das Konto ein. Behauptung. Der Kontostand reicht immer aus, die durch reallocate anfallenden Kosten zu decken. Beweis. Beim ersten reallocate haben wir mindestens zwei Tokens auf dem Konto, die von 3

dem einen Element in der Queue stammen. Nun muss nur genau ein Element kopiert werden, was genau einen Token kostet. Nach einem Aufruf von reallocate hat man capacity/2 unbenutzte Plätze in data. Der nächste aufruf von reallocate findet statt, wenn entweder data.size = capacitiy oder 4 data.size capacitiy gilt. Im ersten Fall wurden seit dem vorherigen Aufruf mindestens capacity/2 Elemente eingefügt, die jeweils zwei Tokens mitbringen. Der Kontostand reicht also aus um capacity Elemente zu kopieren. Im zweiten Fall wurden seit dem vorherigen Aufruf mindestens capacity/4 Elemente entfernt, was jeweils einen Token erbrachte. Das ist genug um das Kopieren von capacity/4 Elementen zu Bezahlen. Aufgabe 4 (Unbounded Arrays, 2 Punkte) Im Unterschied zur Vorlesung und zur Übung sei hier α = β = 2. Das bedeutet die Größe des unbounded Arrays wird sofort halbiert, wenn er nur noch zur Hälfte gefüllt ist. Geben Sie eine Folge von n Operationen an, so dass ein derart schlecht implementierter unbounded Array mit diesen Operationen einen Aufwand von Θ ( n 2) verursacht. Zur Vereinfachung sei n eine Zweierpotenz. Musterlösung: Man führt zunächst n 2 pushback Operationen aus. Der Array enthält dann n 2 Elemente. Dann führt man n 4 Mal die Operationsfolge pushback popback aus. Bei jedem pushback wird ein Array der Größe n alloziiert, und n 2 Elemente umkopiert. Danach beim popback wird wieder ein kleineres Array der Größe n 2 alloziiert und alle verbliebenen n 2 Elemente dorthin kopiert. Für ein Operationspaar pushback popback müssen also n Kopieroperationen durchgeführt werden. Es werden nur die Kopieroperationen betrachtet, da der Aufwand für alle anderen Operationen insgesamt in O(n) liegt. Insgesamt werden für n Operationen damit mindestens n 4 n = Θ( n 2) Kopieroperationen durchgeführt. Zusatzaufgabe (Speicherverwaltung, 5 Punkte) Gegeben sei ein Programm, das zusammenhängende Speicherpakete der Größe 1 Block, 2 Blöcke und 4 Blöcke anfordern kann. Das Programm kann in jedem Schritt von ihm schon belegte Speicherpakete freigeben und neue Speicherpakete anfordern. Dabei wird bei einer Freigabe immer das ganze Paket freigegeben (bei einem 4 Blöcke großen Paket werden also immer alle 4 Blöcke gleichzeitig freigegeben). Die Summe der angeforderten Speicherblöcke ist dabei nie größer als n. Einmal an das Programm übergebene Blöcke dürfen nie geändert oder verschoben werden (es sei denn, das Programm gibt sie frei). Beispiel: Sei n = 8 und seien 15 Speicherblöcke verfügbar, die anfangs alle leer sind. Schritt 1: Das Programm fragt 8 Speicherpakete der Größe 1, 0 Speicherpakete der Größe 2 und 0 Speicherpakete der Größe 4 an. 4

Schritt 2: Das Programm gibt die Speicherpakete mit den Startadressen 0,2,4,6 frei und fragt 0 Speicherpakete der Größe 1, 2 Speicherpakete der Größe 2 und 0 Speicherpakete der Größe 4 an. Schritt 3: Das Programm gibt die Speicherpakete mit den Startadressen 1,5,8 frei. Schritt 4: Das Programm fragt 1 Speicherpaket der Größe 4 an. Diese Anfrage kann jedoch nicht befriedigt werden. Sei nun ein Speicher der Größe 2n gegeben. Geben Sie eine Strategie zur Befriedigung von Speicheranfragen an, und zeigen Sie, dass jede mögliche Folge von Speicheranfragen und Freigaben mit dieser Strategie und mit 2n Speicher befriedigt werden kann. Das Programm weiß natürlich welches Speicherpaket an welcher Stelle liegt. Gehen Sie davon aus, dass falls Ihre Strategie eine Schwachstelle hat, diese durch das Programm gefunden wird. n sei durch 8 teilbar. Wichtig: Da es sehr schwer ist zu entscheiden, ob eine Strategie in allen Fällen das Richtige tut, sollte zu jeder Strategie auch ein Beweis geliefert werden. Musterlösung: Der Speicher sei wie oben beginnend mit 0 durchnummeriert. Strategie: Platziere jedes Speicherpaket an der Stelle mit der kleinstmöglichen Adresse, wobei die Speicherpakete der Größe 1 bei jeder Adresse beginnen dürfen, die Speicherpakete der Größe 2 nur mit geraden Adressen und die Speicherpakete der Größe 4 dürfen nur bei durch 4 teilbaren Adressen (0, 4, 8,... ) beginnen. Beweis: Wir zeigen, dass mit dieser Strategie für Speicherpakete der Größe 1 immer eine Startadresse < n gewählt wird, für Speicherpakete der Größe 2 eine Startadresse < n + n 2 und für Speicherpakete der Größe 4 eine Startadresse < 2n. Insbesondere können alle Speicheranfragen mit dem gegebenen Speicher befriedigt werden. Ein Speicherpaket der Größe 1 wird mit dieser Strategie immer mit den Adressen 0,..., n 1 starten, denn falls keine dieser Adressen frei sein sollte, wären schon mindestens n Speicherblöcke belegt. Dann könnte das Programm jedoch keinen zusätzlichen Speicher anfordern. Falls ein Speicherpaket der Größe 2 an keiner Adresse von 0, 2,..., n 2 starten kann, so muss für jedes i {0, 2,..., n 2} mindestens eine der beiden Adressen i oder i + 1 belegt sein. Deshalb muss dann mindestens die Hälfte der Blöcke mit den Adressen 0,..., n 1 belegt sein. Insgesamt hat das Programm damit mindestens n 2 Speicherblöcke im Bereich 0,..., n 1 belegt. Da nie ein Speicherpaket der Größe 1 an einer Adresse n beginnt und alle Speicherpakete die an Adressen n beginnen, an einer geraden Adresse beginnen, ist für jede gerade Adresse n auch die nachfolgende ungerade Adresse belegt. Analog ist für jede belegte ungerade Adresse n + 1 auch die nächstkleinere gerade Adresse belegt. Falls ein Speicherpaket der Größe 2 also an keiner Adresse von n,..., n + n 2 2 starten kann, so müssen im Bereich n,..., n + n 2 1 alle Speicherblöcke belegt sein. Dies wären weitere n 2 Speicherblöcke. Damit wären insgesamt schon mindestens n Speicherblöcke belegt. Dann könnte das Programm jedoch keinen zusätzlichen Speicher anfordern. Damit startet ein Speicherpaket der Größe 2 nie an einer Adresse n + n 2. 5

Falls ein Speicherpaket der Größe 4 an keiner Adresse von 0, 4,..., n 4 starten kann, so muss für jedes i {0, 4,..., n 4} mindestens eine der 4 Adressen i, i + 1, i + 2 oder i + 3 belegt sein. Deshalb muss dann mindestens ein Viertel der Blöcke mit den Adressen 0,..., n 1 belegt sein. Insgesamt hat das Programm damit mindestens n 4 Speicherblöcke im Bereich 0,..., n 1 belegt. Da nie ein Speicherpaket der Größe 1 an einer Adresse n beginnt und alle Speicherpakete die an Adressen n beginnen, an einer geraden Adresse beginnen, ist für jede gerade Adresse n auch die nachfolgende ungerade Adresse belegt. Analog ist für jede belegte ungerade Adresse n + 1 auch die nächstkleinere gerade Adresse belegt. Falls ein Speicherpaket der Größe 4 also an keiner Adresse von n,..., n + n 2 4 starten kann, so müssen im Bereich n,..., n+ n 2 1 mindestens die Hälfte aller Speicherblöcke belegt sein. Dies wären weitere n 4 Speicherblöcke. Damit wären insgesamt schon mindestens n 2 Speicherblöcke belegt. Jede durch 4 teilbare Adresse n + n 2 und ihre drei folgenden sind genau dann belegt, wenn eine der vier Adressen belegt ist, da in diesem Adressbereich nur noch Speicherpakete der Größe 4 vergeben werden. Im Adressbereich n + n 2,..., 2n 1 ist Platz für n 8 Speicherpakete der Größe 4 (diese haben eine Gesamtgröße von n 2 ). Jedes Speicherpaket der Größe 4, dass nicht im Bereich 0,..., n + n 2 1 platziert werden kann, kann also im Adressbereich n + n 2,..., 2n 1 platziert werden. Damit kann jede Speicheranforderung des Programms erfüllt werden. 6