Algorithmen und Datenstrukturen Wintersemester 2013/14 10. Vorlesung Algorithmen in Java Krzysztof Fleszar Lehrstuhl für Informatik I 1 Übersicht • Berechnung der Potenz für zwei ganze Zahlen • Klausuraufgabe SS 2010 ! • Berechnung der Cosinus-Funktion • Klausuraufgabe WS 2010/2011 ! • Standard- und Referenzdatentypen • Sortieren mit InsertionSort und MergeSort • Anwendung: Zählen von falsch geordneten Paaren • Anpassung der Algorithmen 2 Iterative Berechnung der Potenz Berechnung der Potenz ๐ฅ ๐ฆ für zwei ganze Zahlen ๐ฅ und ๐ฆ. public class Potenz { public static void main(String[] args) { int x = 3; int y = 4; int potenz = 1; for (int i = 0; i < y; i++) { //wird y-mal ausgefuehrt potenz *= x; } System.out.println(x + " hoch " + y + " ist " + potenz); } } 3 Iterative Berechnung der Potenz Berechnung der Potenz ๐ฅ ๐ฆ für zwei ganze Zahlen ๐ฅ und ๐ฆ. public class Potenz { public static void main(String[] args) { int x = 3; int y = 4; Besser: Potenzberechnung in eigener Methode System.out.println(x + " hoch " + y + " ist " + potenz(x,y)); } } 4 Iterative Berechnung der Potenz Berechnung der Potenz ๐ฅ ๐ฆ für zwei ganze Zahlen ๐ฅ und ๐ฆ. public class Potenz { public static void main(String[] args) { int x = 3; int y = 4; System.out.println(x + " hoch " + y + " ist " + potenz(x,y)); } public static int potenz(int x, int y) { int potenz = 1; for (int i = 0; i < y; i++) { //wird y-mal ausgefuehrt potenz *= x; } return potenz; } } 5 Rekursive Berechnung der Potenz Berechnung der Potenz ๐ฅ ๐ฆ für zwei ganze Zahlen ๐ฅ und ๐ฆ. public class Potenz { public static void main(String[] args) { int x = 3; int y = 4; System.out.println(x + " hoch " + y + " ist " + potenz(x,y)); } public static int potenz(int x, int y) { if (y == 0) return 1; return x * potenz(x, y - 1); } } An Basisfall denken! ๐ฆ ๐ฅ =๐ฅ⋅ ๐ฆ−1 ๐ฅ 6 Rekursive Berechnung der Potenz Berechnung der Potenz ๐ฅ ๐ฆ für zwei ganze Zahlen ๐ฅ und ๐ฆ. public class Potenz { public static void main(String[] args) { int x = 3; int y = 4; System.out.println(x + " hoch " + y + " ist " + potenz(x,y)); } public static int potenz(int x, int y) { if (y == 0) return 1; return x * potenz(x, y - 1); } } ๐ฆ ๐ฅ =๐ฅ⋅ Wie oft wird potenz aufgerufen? ๐ฆ−1 ๐ฅ ๐ฆ + 1 -mal 7 Rekursive Berechnung der Potenz Berechnung der Potenz ๐ฅ ๐ฆ für zwei ganze Zahlen ๐ฅ und ๐ฆ. Geht es besser? ๐ฆ ๐ฅ =๐ฅ ๐ฆ ๐ฅ =๐ฅ ๐ฆ ⁄2 ⋅๐ฅ ๐ฆ ⁄2 ๐ฆ ⁄2 ⋅๐ฅ ๐ฆ ⁄2 falls ๐ฆ gerade ⋅ ๐ฅ falls ๐ฆ ungerade 8 Rekursive Berechnung der Potenz Berechnung der Potenz ๐ฅ ๐ฆ für zwei ganze Zahlen ๐ฅ und ๐ฆ. Geht es besser? ๐ฆ ๐ฅ =๐ฅ ๐ฆ ๐ฅ =๐ฅ ๐ฆ ⁄2 ๐ฆ ⁄2 ⋅๐ฅ ⋅๐ฅ ๐ฆ ⁄2 ๐ฆ ⁄2 falls ๐ฆ gerade ⋅ ๐ฅ falls ๐ฆ ungerade public static int potenz(int x, int y) { if (y == 0) return 1; int p = potenz(x, y / 2) * potenz(x, y / 2); if (y % 2 == 0) return p; return p * x; 9 } Rekursive Berechnung der Potenz Berechnung der Potenz ๐ฅ ๐ฆ für zwei ganze Zahlen ๐ฅ und ๐ฆ. Rekursionsgleichung (๐ = ๐ฆ): ๐ ๐ = 2๐ ๐⁄2 + Θ 1 public static int potenz(int x, int y) { if (y == 0) return 1; int p = potenz(x, y / 2) * potenz(x, y / 2); if (y % 2 == 0) return p; return p * x; 10 } Rekursive Berechnung der Potenz Berechnung der Potenz ๐ฅ ๐ฆ für zwei ganze Zahlen ๐ฅ und ๐ฆ. Rekursionsgleichung: ๐ ๐ = 2๐ ๐⁄2 + Θ 1 ๐ ๐ ๐ ๐ ๐ ∈ ๐ ๐1−๐ log ๐ ๐ = log 2 2 = 1 z.B. für ๐ = 0,5 Also gilt mit Fall 1 des Master-Theorems: ๐∈Θ ๐ 11 Rekursive Berechnung der Potenz Berechnung der Potenz ๐ฅ ๐ฆ für zwei ganze Zahlen ๐ฅ und ๐ฆ. Geht es besser? ๐ฆ ๐ฅ =๐ฅ ๐ฆ ๐ฅ =๐ฅ ๐ฆ ⁄2 ๐ฆ ⁄2 ⋅๐ฅ ⋅๐ฅ ๐ฆ ⁄2 ๐ฆ ⁄2 falls ๐ฆ gerade ⋅ ๐ฅ falls ๐ฆ ungerade public static int potenz(int x, int y) { if (y == 0) return 1; int p = potenz(x, y / 2) * potenz(x, y / 2); if (y % 2 == 0) return p; return p * x; 12 } Rekursive Berechnung der Potenz Berechnung der Potenz ๐ฅ ๐ฆ für zwei ganze Zahlen ๐ฅ und ๐ฆ. Geht es besser? ๐ฆ ๐ฅ =๐ฅ ๐ฆ ๐ฅ =๐ฅ ๐ฆ ⁄2 ๐ฆ ⁄2 ⋅๐ฅ ⋅๐ฅ ๐ฆ ⁄2 ๐ฆ ⁄2 falls ๐ฆ gerade ⋅ ๐ฅ falls ๐ฆ ungerade public static int potenz(int x, int y) { if (y == 0) return 1; int p = potenz(x, y / 2); if (y % 2 == 0) return p * p; return p * p * x; } 13 Rekursive Berechnung der Potenz Berechnung der Potenz ๐ฅ ๐ฆ für zwei ganze Zahlen ๐ฅ und ๐ฆ. Rekursionsgleichung (๐ = ๐ฆ): ๐ ๐ = ๐ ๐⁄2 + Θ 1 ๐ ๐ ๐ ๐ log ๐ ๐ = log 2 1 = 0 ๐∈Θ 1 Also gilt mit Fall 2 des Master-Theorems: ๐ ∈ Θ log ๐ 14 Rekursive Berechnung der Potenz Berechnung der Potenz ๐ฅ ๐ฆ für zwei ganze Zahlen ๐ฅ und ๐ฆ. Wie oft wird potenz aufgerufen? ๐ฆ wird in jedem Aufruf mindestens um die Hälfte verringert. Für ๐ฆ = 2๐ gibt es ๐ + 2 = log 2 ๐ฆ + 2 Aufrufe. public static int potenz(int x, int y) { if (y == 0) return 1; int p = potenz(x, y / 2); if (y % 2 == 0) return p * p; return p * p * x; } 15 Rekursive Berechnung der Potenz Berechnung der Potenz ๐ฅ ๐ฆ für zwei ganze Zahlen ๐ฅ und ๐ฆ. Wie oft wird potenz aufgerufen? ๐ฆ wird in jedem Aufruf mindestens um die Hälfte verringert. Es gibt log 2 ๐ฆ + 2 Aufrufe! public static int potenz(int x, int y) { if (y == 0) return 1; int p = potenz(x, y / 2); if (y % 2 == 0) return p * p; return p * p * x; } 16 Rekursive Berechnung der Potenz Berechnung der Potenz ๐ฅ ๐ฆ für zwei ganze Zahlen ๐ฅ und ๐ฆ. Wie oft wird potenz aufgerufen? ๐ฆ wird in jedem Aufruf mindestens um die Hälfte verringert. Es gibt Θ log ๐ฆ Aufrufe! public static int potenz(int x, int y) { if (y == 0) return 1; int p = potenz(x, y / 2); if (y % 2 == 0) return p * p; return p * p * x; } 17 Übersicht • Berechnung der Potenz für zwei ganze Zahlen • Klausuraufgabe SS 2010 ! • Berechnung der Cosinus-Funktion • Klausuraufgabe WS 2010/2011 ! • Standard- und Referenzdatentypen • Sortieren mit InsertionSort und MergeSort • Anwendung: Zählen von falsch geordneten Paaren • Anpassung der Algorithmen 18 Berechnung der Cosinus-Funktion cos 71.356° = 180° 360° ? 19 Berechnung der Cosinus-Funktion 1 cos ๐ฅ cos ๐ฆ = cos ๐ฅ − ๐ฆ + cos ๐ฅ + ๐ฆ 2 20 Berechnung der Cosinus-Funktion 1 cos ๐ฅ cos ๐ฆ = cos ๐ฅ − ๐ฆ + cos ๐ฅ + ๐ฆ 2 โบ cos ๐ฅ + ๐ฆ = 2cos ๐ฅ cos ๐ฆ − cos ๐ฅ − ๐ฆ ⇒ cos 2๐ฅ = 2cos 2 ๐ฅ −1 ๐ฅ 2 ⇒ cos ๐ฅ = 2cos −1 2 21 Berechnung der Cosinus-Funktion ๐ฅ cos ๐ฅ = 2cos −1 2 2 public class Cosinus { public static void main(String[] args) { for (double i = 0; i <= 360; i += 15) { System.out.println("cos " + i + " = " + cos(i * Math.PI / 180.0)); } } public static double cos(double x) { return 2.0 * cos(x / 2.0) * cos(x / 2.0) - 1; } } 22 Berechnung der Cosinus-Funktion ๐ฅ cos ๐ฅ = 2cos −1 2 2 public class Cosinus { public static void main(String[] args) { for (double i = 0; i <= 360; i += 15) { System.out.println("cos " + i + " = " + cos(i * Math.PI / 180.0)); } } public static double cos(double x) { double cosX2 = cos(x / 2.0); return 2.0 * cosX2 * cosX2 - 1; } } 23 Berechnung der Cosinus-Funktion ๐ฅ cos ๐ฅ = 2cos −1 2 2 Näherung für kleine Winkel (๐ฅ < 0.001): cos ๐ฅ = 1 public static double cos(double x) { if (x < 0.001) return 1; double cosX2 = cos(x / 2.0); return 2.0 * cosX2 * cosX2 - 1; } 180° 360° 24 Berechnung der Cosinus-Funktion ๐ฅ cos ๐ฅ = 2cos −1 2 2 Ausgabe: cos cos cos cos 0.0 = 1.0 15.0 = 1.0 30.0 = 1.0 45.0 = 1.0 โฎ cos 360.0 = 1.0 public static double cos(double x) { if (x < 0.001) return 1; double cosX2 = cos(x / 2.0); return 2.0 * cosX2 * cosX2 - 1; } 25 Berechnung der Cosinus-Funktion ๐ฅ cos ๐ฅ = 2cos −1 2 2 Näherung für kleine Winkel (๐ฅ < 0.001): 1 2 cos ๐ฅ = 1 − ๐ฅ 2 public static double cos(double x) { if (x < 0.001) return 1 – 0.5 * x * x; double cosX2 = cos(x / 2.0); return 2.0 * cosX2 * cosX2 - 1; } 180° 360° 26 Berechnung der Cosinus-Funktion ๐ฅ cos ๐ฅ = 2cos −1 2 2 Näherung für kleine Winkel (๐ฅ < 0.001): 1 2 cos ๐ฅ = 1 − ๐ฅ 2 1,5 1 0,5 0 0 50 100 150 200 250 300 350 400 -0,5 -1 -1,5 27 Berechnung der Cosinus-Funktion ๐ฅ cos ๐ฅ = 2cos −1 2 Achtung: Verwende besser Methode cos der Klasse java.lang.Math 2 28 Übersicht • Berechnung der Potenz für zwei ganze Zahlen • Klausuraufgabe SS 2010 ! • Berechnung der Cosinus-Funktion • Klausuraufgabe WS 2010/2011 ! • Standard- und Referenzdatentypen • Sortieren mit InsertionSort und MergeSort • Anwendung: Zählen von falsch geordneten Paaren • Anpassung der Algorithmen 29 Methoden mit Standarddatentypen Inkrementieren einer Zahl a . public class Zaehler { public static void main(String[] args) { int a = 1; inkrementiere(a); System.out.println("a = " + a); } public static void inkrementiere(int a) { a++; } } Ausgabe: a = 1 30 Methoden mit Standarddatentypen Inkrementieren einer Zahl a . public class Zaehler { public static void main(String[] args) { int a = 1; inkrementiere(a); System.out.println("a = " + a); } public static void inkrementiere(int a) { a++; } } Bei Standarddatentypen wird Wert von Variablen übergeben. 31 Methoden mit Standarddatentypen Inkrementieren einer Zahl a . public class Zaehler { public static void main(String[] args) { int a = 1; a = inkrementiere(a); System.out.println("a = " + a); } public static int inkrementiere(int a) { return a + 1; } } 32 Methoden mit Referenzdatentypen Inkrementieren der Zahlen in einem Feld. public class FeldZaehler { public static void main(String[] args) { int[] A = {1, 3, 2, 4}; inkrementiere(A); for (int i = 0; i < A.length; i++) System.out.println("A" + i + " = " + A[i]); } public static void inkrementiere(int[] A) { for (int i = 0; i < A.length; i++) A[i]++; } } 33 Methoden mit Referenzdatentypen Inkrementieren der Zahlen in einem Feld. public class FeldZaehler { public static void main(String[] args) { int[] A = {1, 3, 2, 4}; inkrementiere(A); for (int i = 0; i < A.length; i++) System.out.println("A" + i + " = " + A[i]); } public static void inkrementiere(int[] a) { for (int i = 0; i < A.length; i++) a[i]++; } } 34 Ausgabe: A0 = 2 A1 = 4 A2 = 3 A3 = 5 Methoden mit Referenzdatentypen Inkrementieren der Zahlen in einem Feld. public class FeldZaehler { public static void main(String[] args) { int[] A = {1, 3, 2, 4}; inkrementiere(A); for (int i = 0; i < A.length; i++) System.out.println("A" + i + " = " + A[i]); } public static void inkrementiere(int[] A) { for (int i = 0; i < A.length; i++) A[i]++; } } 35 Bei Feldern wird Referenz übergeben. Methoden mit Referenzdatentypen Sortieren der Zahlen in einem Feld. public class Sortierverfahren { public static void main(String[] args) { int[] A = {1, 3, 2, 4}; sort(A); for (int i = 0; i < A.length; i++) System.out.println("A" + i + " = " + A[i]); } public static void sort(int[] A) { //TODO: Sortierverfahren Deines Vertrauens } } 36 Übersicht • Berechnung der Potenz für zwei ganze Zahlen • Klausuraufgabe SS 2010 ! • Berechnung der Cosinus-Funktion • Klausuraufgabe WS 2010/2011 ! • Standard- und Referenzdatentypen • Sortieren mit InsertionSort und MergeSort • Anwendung: Zählen von falsch geordneten Paaren • Anpassung der Algorithmen 37 Sortieren mit InsertionSort public static void insertionSort(int[] A) { for(int j = 1; j < A.length; j++) { int key = A[j]; int i = j - 1; while (i >= 0 && A[i] > key) { A[i + 1] = A[i]; i--; InsertionSort(array of int ๐ด) } for ๐ = 2 to ๐ด.๐๐๐๐๐๐ do A[i + 1] = key; } ๐๐๐ = ๐ด ๐ } ๐ =๐ −1 while ๐ > 0 and ๐ด ๐ > ๐๐๐ do ๐ด ๐+1 =๐ด ๐ ๐ = ๐−1 38 ๐ด ๐ + 1 = ๐๐๐ Wohlstände und Fehlstände Sei ๐ด = ๐1 , ๐2 , … , ๐๐ eine Folge natürlicher Zahlen. Wir nennen ein Indexpaar ๐, ๐ mit 0 < ๐ < ๐ ≤ ๐ • genau dann einen Wohlstand von ๐ด, wenn ๐๐ < ๐๐ . • genau dann einen Fehlstand von ๐ด, wenn ๐๐ > ๐๐ . Beispiel: 4,7,1,4,5,6 Wohlstand: 1,2 39 Wohlstände und Fehlstände Sei ๐ด = ๐1 , ๐2 , … , ๐๐ eine Folge natürlicher Zahlen. Wir nennen ein Indexpaar ๐, ๐ mit 0 < ๐ < ๐ ≤ ๐ • genau dann einen Wohlstand von ๐ด, wenn ๐๐ < ๐๐ . • genau dann einen Fehlstand von ๐ด, wenn ๐๐ > ๐๐ . Beispiel: 4,7,1,4,5,6 Fehlstand: 1,3 40 Wohlstände und Fehlstände Sei ๐ด = ๐1 , ๐2 , … , ๐๐ eine Folge natürlicher Zahlen. Wir nennen ein Indexpaar ๐, ๐ mit 0 < ๐ < ๐ ≤ ๐ • genau dann einen Wohlstand von ๐ด, wenn ๐๐ < ๐๐ . • genau dann einen Fehlstand von ๐ด, wenn ๐๐ > ๐๐ . Die Folge ๐, ๐ − 1, … , 1 hat die meisten Fehlstände aller Folgen mit ๐ Zahlen, ๐ ๐−1 nämlich: 2 41 Wohlstände und Fehlstände Sei ๐ด = ๐1 , ๐2 , … , ๐๐ eine Folge natürlicher Zahlen. Wir nennen ein Indexpaar ๐, ๐ mit 0 < ๐ < ๐ ≤ ๐ • genau dann einen Wohlstand von ๐ด, wenn ๐๐ < ๐๐ . • genau dann einen Fehlstand von ๐ด, wenn ๐๐ > ๐๐ . Anzahl Fehlstände + Anzahl Wohlstände = (bei verschiedenen ๐ ๐−1 Elementen in ๐ด) 2 42 Wohlstände und Fehlstände Sei ๐ด = ๐1 , ๐2 , … , ๐๐ eine Folge natürlicher Zahlen. Wir nennen ein Indexpaar ๐, ๐ mit 0 < ๐ < ๐ ≤ ๐ • genau dann einen Wohlstand von ๐ด, wenn ๐๐ < ๐๐ . • genau dann einen Fehlstand von ๐ด, wenn ๐๐ > ๐๐ . Jeder Algorithmus zur Ausgabe aller Fehlstände in ๐จ braucht also im schlechtesten Fall alleine für die Ausgabe ๐ ๐−1 Operationen. 2 43 Wohlstände und Fehlstände Sei ๐ด = ๐1 , ๐2 , … , ๐๐ eine Folge natürlicher Zahlen. Wir nennen ein Indexpaar ๐, ๐ mit 0 < ๐ < ๐ ≤ ๐ • genau dann einen Wohlstand von ๐ด, wenn ๐๐ < ๐๐ . • genau dann einen Fehlstand von ๐ด, wenn ๐๐ > ๐๐ . Idee: Fehlstände zählen, nicht ausgeben 44 Fehlstände zählen mit InsertionSort public static void insertionSort(int[] A) { for(int j = 1; j < A.length; j++) { int key = A[j]; int i = j - 1; while (i >= 0 && A[i] > key) { A[i + 1] = A[i]; i--; } A[i + 1] = key; } } 45 Fehlstände zählen mit InsertionSort //sortiert a und gibt anzahl fehlstaende zurueck public static int insertionSort(int[] A) { int fehlstaende = 0; for(int j = 1; j < A.length; j++) { int key = A[j]; int i = j - 1; while (i >= 0 && A[i] > key) { A[i + 1] = A[i]; i--; fehlstaende++; } A[i + 1] = key; } return fehlstaende; } 46 Fehlstände zählen mit InsertionSort //sortiert a und gibt anzahl fehlstaende zurueck public static int insertionSort(int[] A) { int fehlstaende = 0; for(int j = 1; j < A.length; j++) { int key = A[j]; int i = j - 1; In Java while (i >= 0 && A[i] > key) { A[i + 1] = A[i]; i--; fehlstaende++; } A[i + 1] = key; } return fehlstaende; } j = 4 1 2 5 7 3 6 Sortierter Bereich 47 Fehlstände zählen mit InsertionSort //sortiert a und gibt anzahl fehlstaende zurueck public static int insertionSort(int[] A) { int fehlstaende = 0; for(int j = 1; j < A.length; j++) { int key = A[j]; int i = j - 1; Im Pseudocode! while (i >= 0 && A[i] > key) { A[i + 1] = A[i]; i--; fehlstaende++; } A[i + 1] = key; } return fehlstaende; } ๐ = 5 1 2 5 7 3 6 Sortierter Bereich 48 Fehlstände zählen mit InsertionSort //sortiert a und gibt anzahl fehlstaende zurueck public static int insertionSort(int[] A) { int fehlstaende = 0; for(int j = 1; j < A.length; j++) { int key = A[j]; int i = j - 1; while (i >= 0 && A[i] > key) { Behebt alle A[i + 1] = A[i]; Fehlstände i--; fehlstaende++; ๐, 5 } A[i + 1] = key; } return fehlstaende; } 1 2 5 7 3 6 Sortierter Bereich 49 Fehlstände zählen mit InsertionSort //sortiert a und gibt anzahl fehlstaende zurueck public static int insertionSort(int[] A) { int fehlstaende = 0; for(int j = 1; j < A.length; j++) { int key = A[j]; int i = j - 1; while (i >= 0 && A[i] > key) { Behebt alle A[i + 1] = A[i]; Fehlstände i--; fehlstaende++; ๐, 5 } A[i + 1] = key; } return fehlstaende; } 1 2 3 5 7 6 Sortierter Bereich 50 Fehlstände zählen mit InsertionSort //sortiert a und gibt anzahl fehlstaende zurueck public static int insertionSort(int[] A) { int fehlstaende = 0; Jeder for(int j = 1; j < A.length; j++) { Schleifenint key = A[j]; int i = j - 1; durchlauf while (i >= 0 && A[i] > key) { behebt A[i + 1] = A[i]; i--; einen fehlstaende++; Fehlstand } A[i + 1] = key; } return fehlstaende; } 1 2 3 5 7 6 Sortierter Bereich 51 Fehlstände zählen mit InsertionSort Anzahl Fehlstände ≤ Anzahl Vergleiche bei InsertionSort ≤ Anzahl Fehlstände + ๐ − 1 52 Fehlstände zählen mit MergeSort MergeSort(array of int ๐ด, int โ = 1, int ๐ = ๐ด.๐๐๐๐๐๐) if โ < ๐ then ๐ = โ + ๐ ⁄2 MergeSort(๐ด, โ, ๐) MergeSort(๐ด, ๐ + 1, ๐) Merge (๐ด, โ, ๐, ๐) public static void mergeSort(int[] A, int l, int r) { if (l < r) { int m = (l + r) / 2; mergeSort(A, l, m); mergeSort(A, m + 1, r); merge(A, l, m, r); } 53 } Fehlstände zählen mit MergeSort MergeSort(array of int ๐ด, int โ = 1, int ๐ = ๐ด.๐๐๐๐๐๐) public static void mergeSort(int[] A) { mergeSort(A, 0, A.length - 1); } public static void mergeSort(int[] A, int l, int r) { if (l < r) { int m = (l + r) / 2; mergeSort(A, l, m); mergeSort(A, m + 1, r); merge(A, l, m, r); } 54 } Fehlstände zählen mit MergeSort MergeSort(array of int ๐ด, int โ = 1, int ๐ = ๐ด.๐๐๐๐๐๐) public static void mergeSort(int[] A) { mergeSort(A, 0, A.length - 1); } 2x gleicher Methodenname erlaubt? Ja, solange Signatur verschieden! public static void mergeSort(int[] A, int l, int r) { if (l < r) { int m = (l + r) / 2; mergeSort(A, l, m); mergeSort(A, m + 1, r); merge(A, l, m, r); } 55 } Fehlstände zählen mit MergeSort Merge(array of int ๐ด, int โ, int ๐, int ๐) ๐1 = ๐ − โ + 1 ๐2 = ๐ − ๐ let ๐ฟ 1 … ๐1 + 1 and ๐ [1 … ๐2 + 1] be new arrays of int ๐ฟ 1 … ๐1 = ๐ด[โ … ๐] ๐ 1 … ๐2 = ๐ด[๐ + 1 … ๐] ๐ฟ ๐1 + 1 = ๐ ๐2 + 1 = ∞ ๐=๐=1 for ๐ = โ to ๐ do if ๐ฟ ๐ ≤ ๐ ๐ then ๐ด๐ =๐ฟ ๐ ๐=๐ + 1 else ๐ด[๐] = ๐ [๐] ๐ =๐+1 1 4 7 2 3 6 ๐ ๐ โ 56 Fehlstände zählen mit MergeSort Merge(array of int ๐ด, int โ, int ๐, int ๐) ๐1 = ๐ − โ + 1 ๐2 = ๐ − ๐ let ๐ฟ 1 … ๐1 + 1 and ๐ [1 … ๐2 + 1] be new arrays of int ๐ฟ 1 … ๐1 = ๐ด[โ … ๐] ๐ 1 … ๐2 = ๐ด[๐ + 1 … ๐] ๐ฟ ๐1 + 1 = ๐ ๐2 + 1 = ∞ ๐=๐=1 for ๐ = โ to ๐ do if ๐ฟ ๐ ≤ ๐ ๐ then ๐ด๐ =๐ฟ ๐ ๐=๐ + 1 else ๐ด[๐] = ๐ [๐] ๐ =๐+1 1 4 7 2 3 6 ๐ ๐ โ 1 4 7∞ 2 3 6∞ ๐ ๐ฟ ๐ ๐ 57 Fehlstände zählen mit MergeSort Merge(array of int ๐ด, int โ, int ๐, int ๐) ๐1 = ๐ − โ + 1 ๐2 = ๐ − ๐ let ๐ฟ 1 … ๐1 + 1 and ๐ [1 … ๐2 + 1] be new arrays of int ๐ฟ 1 … ๐1 = ๐ด[โ … ๐] ๐ 1 … ๐2 = ๐ด[๐ + 1 … ๐] ๐ฟ ๐1 + 1 = ๐ ๐2 + 1 = ∞ ๐=๐=1 for ๐ = โ to ๐ do if ๐ฟ ๐ ≤ ๐ ๐ then ๐ด๐ =๐ฟ ๐ ๐=๐ + 1 else ๐ด[๐] = ๐ [๐] ๐ =๐+1 1 4 7∞ ๐ 2 3 6∞ ๐ 58 Fehlstände zählen mit MergeSort Merge(array of int ๐ด, int โ, int ๐, int ๐) ๐1 = ๐ − โ + 1 ๐2 = ๐ − ๐ let ๐ฟ 1 … ๐1 + 1 and ๐ [1 … ๐2 + 1] be new arrays of int ๐ฟ 1 … ๐1 = ๐ด[โ … ๐] ๐ 1 … ๐2 = ๐ด[๐ + 1 … ๐] ๐ฟ ๐1 + 1 = ๐ ๐2 + 1 = ∞ ๐=๐=1 for ๐ = โ to ๐ do if ๐ฟ ๐ ≤ ๐ ๐ then ๐ด๐ =๐ฟ ๐ ๐=๐ + 1 else ๐ด[๐] = ๐ [๐] ๐ =๐+1 1 1 4 7∞ ๐ 2 3 6∞ ๐ 59 Fehlstände zählen mit MergeSort Merge(array of int ๐ด, int โ, int ๐, int ๐) ๐1 = ๐ − โ + 1 ๐2 = ๐ − ๐ let ๐ฟ 1 … ๐1 + 1 and ๐ [1 … ๐2 + 1] be new arrays of int ๐ฟ 1 … ๐1 = ๐ด[โ … ๐] ๐ 1 … ๐2 = ๐ด[๐ + 1 … ๐] ๐ฟ ๐1 + 1 = ๐ ๐2 + 1 = ∞ ๐=๐=1 for ๐ = โ to ๐ do if ๐ฟ ๐ ≤ ๐ ๐ then ๐ด๐ =๐ฟ ๐ ๐=๐ + 1 else ๐ด[๐] = ๐ [๐] ๐ =๐+1 1 2 1 4 7∞ ๐ 2 3 6∞ ๐ 60 Fehlstände zählen mit MergeSort Merge(array of int ๐ด, int โ, int ๐, int ๐) ๐1 = ๐ − โ + 1 ๐2 = ๐ − ๐ let ๐ฟ 1 … ๐1 + 1 and ๐ [1 … ๐2 + 1] be new arrays of int ๐ฟ 1 … ๐1 = ๐ด[โ … ๐] ๐ 1 … ๐2 = ๐ด[๐ + 1 … ๐] ๐ฟ ๐1 + 1 = ๐ ๐2 + 1 = ∞ ๐=๐=1 for ๐ = โ to ๐ do if ๐ฟ ๐ ≤ ๐ ๐ then ๐ด๐ =๐ฟ ๐ ๐=๐ + 1 else ๐ด[๐] = ๐ [๐] Wird von Feld ๐ gewählt, so werden ๐ =๐+1 ๐ – ๐ + 1 Fehlstände beseitigt. 61 1 2 1 4 7∞ 1 ๐ 2 3 6∞ ๐ Fehlstände zählen mit MergeSort ๐=0 for ๐ = โ to ๐ do if ๐ฟ ๐ ≤ ๐ ๐ then ๐ด๐ =๐ฟ ๐ ๐=๐ + 1 else ๐ด[๐] = ๐ [๐] ๐ = ๐ + ๐1 − ๐ + 1 ๐ =๐+1 return ๐ Fehlstände lassen sich mit MergeSort zählen! Wird von Feld ๐ gewählt, so werden ๐1– ๐ + 1 Fehlstände beseitigt. 62 Fehlstände zählen mit MergeSort public static int mergeSort(int[] A, int l, int r) { int fehlstaende = 0; if (l < r) { int m = (l + r) / 2; fehlstaende += mergeSort(A, l, m); fehlstaende += mergeSort(A, m + 1, r); fehlstaende += merge(A, l, m, r); } return fehlstaende; } 63 Schluss Bei Rekursionen • denkt an den Basisfall/Rekursionsabbruch! • vermeidet Mehrfachaufrufe mit gleichem Argument • leitet die Rekursionsgleichungen her! Aufgabe Wohlstände/Fehlstände • passt bekannte Algorithmen an • Ausgabe aller Fehlstände ≠ Ausgabe Anzahl Fehlstände 64