Algorithmen und Datenstrukturen Wintersemester 2012/13 8. Vorlesung Algorithmen in Java Jan-Henrik Haunert Lehrstuhl für Informatik I Übersicht Berechnung der Potenz für zwei ganze Zahlen Klausuraufgabe SS 2010! Klausuraufgabe WS 2010/2011! Standard- und Referenzdatentypen Sortieren mit InsertionSort und MergeSort Anwendung: Zählen von falsch geordneten Paaren Anpassung der Algorithmen Iterative Berechnung der Potenz Berechnung der Potenz für zwei ganze Zahlen und. public class Potenz { 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); Iterative Berechnung der Potenz Berechnung der Potenz für zwei ganze Zahlen und. public class Potenz { int x = 3; int y = 4; Besser: Potenzberechnung in eigener Methode System.out.println(x + " hoch " + y + " ist " + potenz(x,y)); Iterative Berechnung der Potenz Berechnung der Potenz für zwei ganze Zahlen und. public class Potenz { int x = 3; int y = 4; System.out.println(x + " hoch " + y + " ist " + potenz(x,y)); int potenz = 1; for (int i = 0; i < y; i++) { //wird y-mal ausgefuehrt potenz *= x; return potenz; Berechnung der Potenz für zwei ganze Zahlen und. public class Potenz { int x = 3; int y = 4; System.out.println(x + " hoch " + y + " ist " + potenz(x,y)); return x * potenz(x, y - 1); An Basisfall denken! =
Berechnung der Potenz für zwei ganze Zahlen und. public class Potenz { int x = 3; int y = 4; System.out.println(x + " hoch " + y + " ist " + potenz(x,y)); return x * potenz(x, y - 1); Wie oft wird potenz aufgerufen? = +1 -mal Berechnung der Potenz für zwei ganze Zahlen und. Geht es besser? = = falls gerade falls ungerade int p = potenz(x, y / 2) * potenz(x, y / 2); if (y % 2 == 0) return p; return p * x; Berechnung der Potenz für zwei ganze Zahlen und. Rekursionsgleichung: = 2 2 +Θ 1 log = log 2=1 z.b. für =0,5 Also gilt mit Fall 1 des Master-Theorems: Θ Berechnung der Potenz für zwei ganze Zahlen und. Geht es besser? = = falls gerade falls ungerade int p = potenz(x, y / 2); if (y % 2 == 0) return p * p; return p * p * x; Berechnung der Potenz für zwei ganze Zahlen und. Rekursionsgleichung ( = ): = 2 +Θ 1 log = log 1=0 Θ 1 Also gilt mit Fall 2 des Master-Theorems: Θ log 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 Aufrufe. int p = potenz(x, y / 2); if (y % 2 == 0) return p * p; return p * p * x;
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 Aufrufe! int p = potenz(x, y / 2); if (y % 2 == 0) return p * p; return p * p * x; Berechnung der Potenz für zwei ganze Zahlen und. Wie oft wird potenz aufgerufen? wird in jedem Aufruf mindestens um die Hälfte verringert. Θ log Es gibt Aufrufe! int p = potenz(x, y / 2); if (y % 2 == 0) return p * p; return p * p * x; cos 71.356 =? 180 360 cos cos = 1 2 cos + cos + cos = 2cos 2 1 cos = 2cos 2 1 cos + = 2cos cos cos cos 2 = 2cos 1 cos = 2cos 2 1 public class Cosinus { 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; public class Cosinus { 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 cosx = cos(x / 2.0); return 2.0 * cosx * cosx - 1;
cos = 2cos 2 1 cos = 2cos 2 1 cos = 2cos 2 1 Näherung für kleine Winkel ( < 0.001): cos = 1 Ausgabe: cos 0.0 = 1.0 cos 15.0 = 1.0 cos 30.0 = 1.0 cos 45.0 = 1.0 cos 360.0 = 1.0 Näherung für kleine Winkel ( < 0.001): cos = 1 public static double cos(double x) { if (x < 0.001) return 1; double cosx = cos(x / 2.0); return 2.0 * cosx * cosx - 1; 180 360 public static double cos(double x) { if (x < 0.001) return 1; double cosx = cos(x / 2.0); return 2.0 * cosx * cosx - 1; public static double cos(double x) { if (x < 0.001) return 1 0.5 * x * x; double cosx = cos(x / 2.0); return 2.0 * cosx * cosx - 1; 180 360 cos = 2cos 2 1 Näherung für kleine Winkel ( < 0.001): cos = 1 1,5 1 0,5 0 0 50 100 150 200 250 300 350 400-0,5-1 cos = 2cos 2 1 Achtung: Verwende besser Methode cos der Klasse java.lang.math Methoden mit Standarddatentypen Inkrementieren einer Zahl a. public class Zaehler { int a = 1; inkrementiere(a); System.out.println("a = " + a); public static void inkrementiere(int a) { a++; Ausgabe: a = 1-1,5
Methoden mit Standarddatentypen Inkrementieren einer Zahl a. public class Zaehler { int a = 1; inkrementiere(a); System.out.println("a = " + a); public static void inkrementiere(int a) { a++; Bei Standarddatentypen wird Wert von Variablen übergeben. Methoden mit Standarddatentypen Inkrementieren einer Zahl a. public class Zaehler { int a = 1; a = inkrementiere(a); System.out.println("a = " + a); public static int inkrementiere(int a) { return a + 1; Methoden mit Referenzdatentypen Inkrementieren der Zahlen in einem Feld. public class FeldZaehler { 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]++; Methoden mit Referenzdatentypen Inkrementieren der Zahlen in einem Feld. public class FeldZaehler { int[] A = {1, 3, 2, 4; inkrementiere(a); Ausgabe: for (int i = 0; i < A.length; i++) A0 = 2 System.out.println("A" + i + " = " + A[i]); A1 = 4 public static void inkrementiere(int[] a) { for (int i = 0; i < A.length; i++) A2 a[i]++; = 3 A3 = 5 Methoden mit Referenzdatentypen Inkrementieren der Zahlen in einem Feld. public class FeldZaehler { 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]++; Bei Feldern wird Referenz übergeben. Methoden mit Referenzdatentypen Sortieren der Zahlen in einem Feld. public class Sortierverfahren { 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
Sortieren mit InsertionSort public static void insertionsort(int[] A) { InsertionSort(array of int ) for =2 to.h do = = 1 while >0 and +1 = = 1 +1 = > do Beispiel: Wohlstände und Fehlstände Sei =,,, eine Folge natürlicher Zahlen. Wir nennen ein Indexpaar, mit 0 << genau dann einen Wohlstand von, wenn <. genau dann einen Fehlstand von, wenn >. 4,7,1,4,5,6 Wohlstand: 1,2 Beispiel: Wohlstände und Fehlstände Sei =,,, eine Folge natürlicher Zahlen. Wir nennen ein Indexpaar, mit 0 << genau dann einen Wohlstand von, wenn <. genau dann einen Fehlstand von, wenn >. 4,7,1,4,5,6 Fehlstand: 1,3 Wohlstände und Fehlstände Sei =,,, 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, nämlich: 1 2 Wohlstände und Fehlstände Sei =,,, 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 = 1 2 (bei verschiedenen Elementen in ) Wohlstände und Fehlstände Sei =,,, 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
Wohlstände und Fehlstände Sei =,,, 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 public static void insertionsort(int[] A) { 1 2 5 7 3 6 Sortierter Bereich j = 4 = 5 1 2 5 7 3 6 Sortierter Bereich
1 2 5 7 3 6 Sortierter Bereich Behebt alle Fehlstände, 5 1 2 3 5 7 6 Sortierter Bereich Behebt alle Fehlstände, 5 1 2 3 5 7 6 Sortierter Bereich Jeder Schleifendurchlauf behebt einen Fehlstand Anzahl Fehlstände Anzahl Vergleiche bei InsertionSort Anzahl Fehlstände + 1 MergeSort(array of int, int l =1, int =.h) if l < then = l+ 2 MergeSort(, l, ) MergeSort(, + 1, ) Merge (, l,, ) 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); MergeSort(array of int, int l =1, int =.h) 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);
Merge(array of int, int l, int, int ) = l+1 = let 1 +1 and [1 +1] be new arrays of int 1 =[l ] 1 =[ +1 ] +1 = +1 = ==1 for =l to do if then = = + 1 [] = [] =+1 1 4 7 2 3 6 l 1 4 7 2 3 6 Merge(array of int, int l, int, int ) = l+1 = let 1 +1 and [1 +1] be new arrays of int 1 =[l ] 1 =[ +1 ] +1 = +1 = ==1 for =l to do if then = = + 1 [] = [] =+1 1 4 7 2 3 6 Merge(array of int, int l, int, int ) = l+1 = let 1 +1 and [1 +1] be new arrays of int 1 =[l ] 1 =[ +1 ] +1 = +1 = ==1 for =l to do if then = = + 1 [] = [] =+1 1 1 4 7 2 3 6 Merge(array of int, int l, int, int ) = l+1 = let 1 +1 and [1 +1] be new arrays of int 1 =[l ] 1 =[ +1 ] +1 = +1 = ==1 for =l to do if then = = + 1 [] = [] =+1 1 2 1 4 7 2 3 6 Merge(array of int, int l, int, int ) = l+1 = let 1 +1 and [1 +1] be new arrays of int 1 =[l ] 1 =[ +1 ] +1 = +1 = ==1 for =l to do if then = = + 1 [] = [] =+1 1 2 3 1 4 7 2 3 6 Merge(array of int, int l, int, int ) = l+1 = let 1 +1 and [1 +1] be new arrays of int 1 =[l ] 1 =[ +1 ] +1 = +1 = ==1 for =l to do if then = = + 1 [] = [] =+1 1 2 3 4 1 4 7 2 3 6
Merge(array of int, int l, int, int ) = l+1 = let 1 +1 and [1 +1] be new arrays of int 1 =[l ] 1 =[ +1 ] +1 = +1 = ==1 for =l to do if then = = + 1 [] = [] =+1 1 2 3 4 6 1 4 7 2 3 6 Merge(array of int, int l, int, int ) = l+1 = let 1 +1 and [1 +1] be new arrays of int 1 =[l ] 1 =[ +1 ] +1 = +1 = ==1 for =l to do if then = = + 1 [] = [] =+1 1 2 3 4 6 7 1 4 7 2 3 6 Merge(array of int, int l, int, int ) = l+1 = let 1 +1 and [1 +1] be new arrays of int 1 =[l ] 1 =[ +1 ] +1 = +1 = ==1 for =l to do if then = = + 1 [] = [] =+1 1 4 7 2 3 6 Merge(array of int, int l, int, int ) = l+1 = let 1 +1 and [1 +1] be new arrays of int 1 =[l ] 1 =[ +1 ] +1 = +1 = ==1 for =l to do if then = = + 1 [] = [] =+1 1 1 4 7 2 3 6 Merge(array of int, int l, int, int ) = l+1 = let 1 +1 and [1 +1] be new arrays of int 1 =[l ] 1 =[ +1 ] +1 = +1 = ==1 for =l to do if then = = + 1 [] = [] =+1 1 2 1 4 7 2 3 6 Merge(array of int, int l, int, int ) = l+1 = let 1 +1 and [1 +1] be new arrays of int 1 =[l ] 1 =[ +1 ] +1 = +1 = ==1 for =l to do if then = = + 1 [] = [] =+1 1 2 1 4 7 2 3 6 Wird von Feld gewählt, so werden 1 +1 Fehlstände beseitigt.
=0 for =l to do if then = = + 1 [] = [] =+ +1 =+1 return Fehlstände lassen sich mit MergeSort zählen! Wird von Feld gewählt, so werden 1 +1 Fehlstände beseitigt. 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); 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