Informatik II - Ãœbung 12

Pascal Schärli

CheapHeap@pascscha.ch

11.12.2020

Nachbesprechung

Sortieren mit Suchbäumen

aufsteigend vorsortiert

absteigend vorsortiert

gut durchmischt

[1, 2, 3, 4, 5, 6, 7]
[4, 3, 6, 7, 1, 2, 5]
[7, 6, 5, 4, 3, 2, 1]

worst case:

\(O(n^2)\)

worst case:

\(O(n^2)\)

best & average case:

\(O(n \cdot log_2(n))\)

Komplexitätsanalyse und O-Notation

// Fragment 6
for (int i=0; i<n; i++)
    for (int j=0; j<n*n; j++)
        for (int k=0; k<j; k++)
            a++;
  • Zeile 2 macht, dass die inneren Loops \(n\)-mal ausgeführt werden.
  • Zeile 3 macht, dass der inneren Loop \(n^2\)-mal ausgeführt wird.
  • Der letzte Loop führt a++ \(j\) mal aus. Da \(j\) von \(0\) bis \(n^2\) geht, hat der innerste Loop auch die Komplexität \(O(n^2)\).
  • Somit hat das gesamte Fragment die Komplexität
    \(O(n*n^2*n^2) = O(n^5)\)

Komplexität

  • \(M_i' = f_i^{-1}(k \cdot f_i(M_i))\)
     
  • \(M_3' = log_2(3 \cdot 2^{M_3}) = log_2(3) + M_3 \neq log_2(3) \cdot M_3\)
     
  • \(M_4' = 2^{3 \cdot log_2(M_4)} = M_4^3  \neq 2^3 \cdot M_4\)

Vorlesung

Heaps

  • Wie in der letzten Serie gesehen hat man bei Suchbäumen das Problem, dass diese entarten könnten.
    • \(\Rightarrow\) Heaps
       
  • Ein Heap ist ein Binärbaum mit den folgenden Eigenschaften:
    1. Alle bis auf die letzte Ebene sind vollständig besetzt
    2. Die letzte Ebene wird von rechts nach links aufgefüllt
    3. Die Elemente sind niveauweise sortier:
      • Max-Heap: Alle Kinder sind kleiner als die Wurzel
      • Min-Heap: Alle Kinder sind grösser als die Wurzel

2

3

5

11

6

Heaps

1

4

5

7

11

6

12

9

3

4

8

5

Element einfügen

  • Um ein Element einzufügen, fügt man es in der Untersten Ebene beim ersten freien Platz ein.
     
  • Dies könnte in einem ungültigen Heap resultieren
     
  • Deshalb wird das Element so lange mit seinem Vorgänger getauscht, bis es grösser als sein Vorgänger ist.

2

Heaps

1

4

5

7

11

6

12

9

3

4

8

5

2

Element einfügen

  • Um ein Element einzufügen, fügt man es in der Untersten Ebene beim ersten freien Platz ein.
     
  • Dies könnte in einem ungültigen Heap resultieren
     
  • Deshalb wird das Element so lange mit seinem Vorgänger getauscht, bis es grösser als sein Vorgänger ist.

Heaps

1

4

5

7

11

6

12

9

3

4

8

5

2

Element einfügen

  • Um ein Element einzufügen, fügt man es in der Untersten Ebene beim ersten freien Platz ein.
     
  • Dies könnte in einem ungültigen Heap resultieren
     
  • Deshalb wird das Element so lange mit seinem Vorgänger getauscht, bis es grösser als sein Vorgänger ist.

Heaps

1

4

5

7

11

6

12

9

3

4

8

5

2

Element einfügen

  • Um ein Element einzufügen, fügt man es in der Untersten Ebene beim ersten freien Platz ein.
     
  • Dies könnte in einem ungültigen Heap resultieren
     
  • Deshalb wird das Element so lange mit seinem Vorgänger getauscht, bis es grösser als sein Vorgänger ist.

Heaps

1

4

5

7

11

6

12

9

3

4

8

5

2

Wurzel entfernen

  • Um die Wurzel zu entfernen ersetzt man die Wurzel mit dem Letzten Element im Stack
     
  • Dies könnte in einem ungültigen Heap resultieren
     
  • Deshalb wird die neue Wurzel so lange mit seinem kleinsten Kind getauscht, bis es kleiner als alle Kinder ist.

1

4

Heaps

1

4

5

7

11

6

12

9

3

4

8

5

2

Wurzel entfernen

  • Um die Wurzel zu entfernen ersetzt man die Wurzel mit dem Letzten Element im Stack
     
  • Dies könnte in einem ungültigen Heap resultieren
     
  • Deshalb wird die neue Wurzel so lange mit seinem kleinsten Kind getauscht, bis es kleiner als alle Kinder ist.

1

4

Heaps

2

4

5

7

11

6

12

9

3

4

8

5

2

Wurzel entfernen

  • Um die Wurzel zu entfernen ersetzt man die Wurzel mit dem Letzten Element im Stack
     
  • Dies könnte in einem ungültigen Heap resultieren
     
  • Deshalb wird die neue Wurzel so lange mit seinem kleinsten Kind getauscht, bis es kleiner als alle Kinder ist.

1

4

Heaps

2

4

5

7

11

6

12

9

3

4

8

5

3

Wurzel entfernen

  • Um die Wurzel zu entfernen ersetzt man die Wurzel mit dem Letzten Element im Stack
     
  • Dies könnte in einem ungültigen Heap resultieren
     
  • Deshalb wird die neue Wurzel so lange mit seinem kleinsten Kind getauscht, bis es kleiner als alle Kinder ist.

1

4

2

4

5

7

11

6

12

9

4

8

5

3

Wurzel entfernen

  • Um die Wurzel zu entfernen ersetzt man die Wurzel mit dem Letzten Element im Stack
     
  • Dies könnte in einem ungültigen Heap resultieren
     
  • Deshalb wird die neue Wurzel so lange mit seinem kleinsten Kind getauscht, bis es kleiner als alle Kinder ist.

1

Heaps

Heap Sort ♥

Heap Sort ♥

  • Wie schon in der Ãœbung 2 gelernt haben, lässt sich ein Binärbaum in einem Array darstellen.
     

  • Somit kann man einen Array ohne zusätzlichen Speicherplatz sortieren:

    • Zuerst erstellen wir eine Heapstruktur im Array

    • Danach können wir immer das grösste bzw kleinste Element aus dem Heap entfernen

Heap Sort ♥

7

3

9

1

2

7

3

9

1

2

unstrukturiert

im heap

sortiert

Heap Sort ♥

7

3

9

1

2

7

3

9

1

2

min heap (nur als visualisierung vom Array)

unstrukturiert

im heap

sortiert

Heap Sort ♥

7

3

9

1

2

7

3

9

1

2

min heap (nur als visualisierung vom Array)

unstrukturiert

im heap

sortiert

Heap Sort ♥

7

3

1

2

7

3

9

1

2

min heap (nur als visualisierung vom Array)

9

unstrukturiert

im heap

sortiert

Heap Sort ♥

7

3

9

1

2

7

3

9

1

2

min heap (nur als visualisierung vom Array)

unstrukturiert

im heap

sortiert

Heap Sort ♥

7

3

9

1

2

7

3

9

1

2

min heap (nur als visualisierung vom Array)

unstrukturiert

im heap

sortiert

Heap Sort ♥

7

3

9

1

2

7

3

9

1

2

min heap (nur als visualisierung vom Array)

unstrukturiert

im heap

sortiert

Heap Sort ♥

unstrukturiert

im heap

sortiert

7

3

9

1

2

7

3

9

1

2

min heap (nur als visualisierung vom Array)

Heap Sort ♥

7

3

9

1

2

7

3

9

1

2

min heap (nur als visualisierung vom Array)

unstrukturiert

im heap

sortiert

Heap Sort ♥

7

3

9

1

2

7

3

9

1

2

min heap (nur als visualisierung vom Array)

unstrukturiert

im heap

sortiert

Heap Sort ♥

7

3

9

2

7

3

9

1

2

min heap (nur als visualisierung vom Array)

unstrukturiert

im heap

sortiert

1

Heap Sort ♥

7

3

9

2

7

3

9

1

2

min heap (nur als visualisierung vom Array)

unstrukturiert

im heap

sortiert

Heap Sort ♥

7

3

9

2

7

3

9

1

2

min heap (nur als visualisierung vom Array)

unstrukturiert

im heap

sortiert

Heap Sort ♥

7

3

9

2

7

3

9

1

2

min heap (nur als visualisierung vom Array)

unstrukturiert

im heap

sortiert

Heap Sort ♥

7

3

9

7

3

9

1

2

min heap (nur als visualisierung vom Array)

unstrukturiert

im heap

sortiert

Heap Sort ♥

7

9

7

3

9

1

2

min heap (nur als visualisierung vom Array)

unstrukturiert

im heap

sortiert

Heap Sort ♥

7

9

7

3

9

1

2

min heap (nur als visualisierung vom Array)

unstrukturiert

im heap

sortiert

Heap Sort ♥

9

7

3

9

1

2

min heap (nur als visualisierung vom Array)

unstrukturiert

im heap

sortiert

Parallel processing

  • Wenn man verschiedene Tasks parallel Ausführt, kann die Laufzeit von Programmen reduziert werden.
     
  • Um dies zu ermöglichen gibt es zwei Varianten:
    • parallele Prozesse
    • parallele Threads

Parallel processing

  • Parallele Prozesse:
    • Laufen in einem anderen Kontext
    • Keinen Zugriff auf Variablen von anderen Prozessen
       
  • Parallele Threads:
    • Laufen im selben Kontext
    • Können auf Variablen von anderen Threads im selben Kontext zugreifen
    • Schnelleres Task-Switching
    • Daten können geteilt werden
    • Kann aber zu Problemen in der Synchronisation geben, wenn man Daten mit anderen Threads teilt

Multithreading - start

 public class Main {
     public static void main(String[] args) {
         for (int i = 0; i < 5; i++){
             new Worker().start();
         }
         System.out.println("Done!");
     }
 }
public class Worker extends Thread {
    static int j = 0;
    int k;
    
    @Override
    public void run() {
        for (int i = 0; i < 4000000; i++) {
            j++;
            k++;
        }
        System.out.println("k: " + k + " j:" + j);
    }
}
Done!
k: 4‘000‘000, j: 3‘752‘884
k: 4‘000‘000, j: 10‘806‘936
k: 4‘000‘000, j: 7‘307‘897
k: 4‘000‘000, j: 5‘322‘116
k: 4‘000‘000, j: 4‘366‘084
  • Mit ".start()" Kann man einen Thread starten. Dieser wird dann im Hintergrund ausgeführt, das heisst es wird nicht gewartet bis die Funktion fertig ist, sondern das Programm geht direkt weiter.
  • Die "run" Funktion vom Thread wird ausgeführt wenn ".start()" aufgerufen wird.

Multithreading - synchronized

 public class Main {
     public static void main(String[] args) {
         for (int i = 0; i < 5; i++){
             new Worker().start();
         }
         System.out.println("Done!");
     }
 }
public class Worker extends Thread {
    static int j = 0;
    int k;
    static Object lock = new Object();
    
    @Override
    public void run() {
        for (int i = 0; i < 4000000; i++) {
            synchronized(lock){
              j++;
              k++;            
            }
        }
        System.out.println("k: " + k + " j:" + j);
    }
}
Done!
k: 4‘000‘000, j: 15‘786‘100
k: 4‘000‘000, j: 18‘432‘690
k: 4‘000‘000, j: 19‘344‘207
k: 4‘000‘000, j: 19‘408‘717
k: 4‘000‘000, j: 20‘000‘000
  • Mit "synchronized" kann man gewisse Programmabschnitte synchronisieren
     
  • Man braucht ein geteiltes Objekt (hier "lock") als Schloss
     
  • Es kann immer nur ein Thread gleichzeitig im synchronisierten Bereich sein.

Multithreading - join

public static void main(String[] args) {
    Worker workers[] = new Worker[5];
    for (int i = 0; i < 5; i++) {
        workers[i] = new Worker();
        workers[i].start();
    }
    for (int i = 0; i < 5; i++) {
        try {
            workers[i].join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    System.out.println("Done!");
}
k: 4‘000‘000, j: 15‘786‘100
k: 4‘000‘000, j: 18‘432‘690
k: 4‘000‘000, j: 19‘344‘207
k: 4‘000‘000, j: 19‘408‘717
k: 4‘000‘000, j: 20‘000‘000
Done!
  • Mit "join" kann man warten bis ein Thread fertig ist.
     
  • So ist es mehrere Threads zu starten und dann zu warten bis alle fertig sind.

Vorbesprechung

Heapsort Textaufgaben

  1. Wie viel Elemente sind in einem Heap der Höhe h mindestens/maximal?
     
  2. Repräsentiert ein sortiertes Array einen gültigen Heap?
    Ist die Array Repräsentation eines Heaps immer sortiert?
     
  3. Heapsort von Hand

Heapsort Programmieren

  • Implementiert Heapsort (min Max-Heap)
  • Teilt den Algorithmus in Teilprobleme auf:
    1. Heap aufbau
    2. Heap abbau
  • Verwendet dazu Hilfsfunktionen um beim einfügen/entfernen von Elementen zu helfen:
    1. raise: Element so weit wie nötig nach oben wandern lassen
      • Ist Element schon am richtigen Platz?
      • sonst swap mit parent und raise an der neuen Position rekursiv ausführen
    2. sink:Element so weit wie nötig nach unten wandern lassen
      • Ist Element schon am richtigen Platz?
      • Sonst swap mit dem grösseren Kind und sink an der neuen Position rekursiv ausführen
    3. swap, father, leftChild, rightChild

Parallelisiertes Mergesort

  public Worker(MergeSort sort, int[] items, int threadCount, int begin, int end) {
    this.sort = sort;
    this.items = items;
    this.threadCount = threadCount;
    this.begin = begin;
    this.end = end;
  }

  @Override
  public void run() {
    if(threadCount <= 1)
      // Call Mergesort function from Exercise 10
    else {
      // 1. Divde array into two parts
      // 2. Create a new worker for left half
      // 3. Create a new worker for right half
      // 4. Wait for both workers to finish
      // 5. Merge results of both workers and store it in sortedItems
    }
  }
  
  public int[] getResult() {
    return sortedItems;
  }

Rekursives Problemlösen

  • Findet eine rekursive Formel: \(f(n) = g(f(n-1))\)
     
  • Gute Ãœbung für Rekursives Problemlösen, jedoch nicht so relevant wie die ersten Aufgaben.
  • Wir haben n Rechtecke gegeben. Wie viele Rechtecke kann man mit diesen n Rechtecken als Bauklötze bauen?
  • Beispiel \(n = 4\): 8

Reversi

Viel Spass, schöne Weinachten, gute Lernphase, bleibt gesund!

Ich freue mich euch am Reversi Tournier und am PVK nochmals zu treffen.