Kurs:Algorithmen und Datenstrukturen/Vorlesung/Aufwandsanalyse von iterativen Algorithmen




Aufwandsanalyse von iterativen Algorithmen

Bearbeiten

Auf dieser Seite wird der Aufwand von iterativen Algorithmen analysiert. Als Aufwand wird die Anzahl der durchlaufenen Operationen zur Lösung des Problems bezeichnet ( Zuweisungen, Vergleiche...). Häufig ist der Aufwand abhängig vom Eingabeparameter (Problemgröße). Die Aufwandsklasse sagt, wie der Aufwand in Abhängigkeit von der Problemgröße wächst. Doch wie kann man nun bei beliebigem Java Code die Aufwandsklasse bestimmen?

Aufwand von Programmen ablesen

Bearbeiten
void alg1(int n){
     int m = 2;
     int i;
     int k = n;
     while (n > 0){
         i = k;
         while (i > 0) {
               m = m + i;
               i = i / 2;
         }
         n = n - 1;
    }
}

Die Aufwandsklasse ist  . Die äußere Schleife wird n-mal durchlaufen und die Innere Schleife log n-mal.

void alg1(int n) {
      int m = 1;
      int i = 0;
      while (m < n) {
         while (i < m) 
              i = i + 1;
      m = m + i;
      }
}

Hier ist die Aufwandsklasse O(n+log n). In jedem Durchlauf der äußeren Schleife wird m verdoppelt, d.h. sie läuft log n Mal. Die innere Schleife läuft bis n/2, aber nicht jedes Mal, weil i nur ein Mal auf 0 gesetzt wird. Man könnte als Aufwandsklasse auch O(n) sagen, da der Summand log n nicht ins Gewicht fällt.

Bestandteile iterativer Algorithmen

Bearbeiten

Zum einen haben wir elementare Anweisungen wie Zuweisungen und Vergleiche. Diese haben einen Aufwand von 1.

Des Weiteren haben wir Sequenzen   oder auch   geschrieben. Die obere Grenze ist   und die untere Grenze ist  . Dabei ist   der Aufwand, der bei der Ausführung von   entsteht.

Ein weiterer Bestandteil ist die Selektion.  . Hier ist die obere Grenze   und die untere Grenze  .

Außerdem haben wir Iterationen  . Hierbei ist die obere und die untere Grenze die Anzahl der Schleifendurchläufe,   und die untere Grenze  . Doch wie ist der Aufwand für eine for-Schleife? Ein Beispiel ist  . Die Antwort ist die Abbildung auf eine while-Schleife.

 

while(B) {

      

      

}

Beispiel Sequenz

Bearbeiten
public int berechne(int n) {
  int x = 0;
  x = x + 1;
  return x;
}

Jede Zeile hat den Aufwand  . Wie viele Operationen werden nun durchlaufen? Und ist die Anzahl abhängig vom Eingabeparameter? Der Aufwand ist  

Die Aufwandsklasse ist somit  

Beispiel Schleifen

Bearbeiten
public int berechne(int n) {
  int x = 0;
  for (int i=0; i < n; i++) {
    x = x + 1;
  }
  return x;
}

Die for Schleife hat den Aufwand  . Die Initialisierung und das return haben jeweils den Aufwand  .

Der Gesamtaufwand ist somit  . Somit ist die Aufwandsklasse  .

public int berechne(int n) {
  int x = 0;
  for (int i=0; i < n; i++) {
    for (int j=0; j < n; j++) {
      x = x + 1;
    }
  }
  return x;
}

Hier hat die for-Schleife den Aufwand   und die Initialisierung und das return wieder  . Damit ergibt der sich Gesamtaufwand  . Daraus folgt die Aufwandsklasse  .

Beispiel Selektion

Bearbeiten
public int berechne(int n) {
   if (n % 2 == 0) {
      int x = 0;
      for (int i=0; i < n; i++) {
         x = x + 1;
      }
      return x;
   }else{
      return n;
   }
}

Hier hat die for-Schleife einen Aufwand von  . Die Initialisierung und das return wieder  .

Die obere Grenze ist somit   und die untere Grenze  

Faustregeln

Bearbeiten

Zu den häufig verwendeten Faustregeln gehört, dass wenn wir keine Schleife haben, der Aufwand konstant ist. Eine weitere ist, dass bei einer Schleife immer ein linearer Aufwand vorliegt. Bei zwei geschachtelten Schleifen haben wir immer einen quadratischen Aufwand. Doch die Faustegeln gelten nicht ohne Ausnahmen. Besonders Acht geben muss man bei Aufwandsbestimmungen für Schleifen, bei mehreren Eingabevariablen, bei Funktionsaufrufen und bei Rekursionen.

Aufwandsbestimmung für Schleifen

Bearbeiten
public int berechne(int n) {
  int x = 0;
  for (int i=0; i < 5; i++) {
    x = x + 1;
  }
  return x;
}

Der Schleifenabbruch hängt nicht vom Eingabeparameter ab. Der Aufwand beträgt   somit haben wir die Aufwandsklasse  

public int berechne(int n) {
  int x = 0;
  for (int i=1; i < n; i = 2*i) {
    x = x + 1;
  }
  return x;
}

Hier wächst die Laufvariable nicht linear an.Daher ist der Aufwand   und wir haben die Aufwandsklasse  .

Doch gibt es eine allgemeine Methodik zum Bestimmen des Schleifenaufwands?

for (int i=1; i < n; i=2*i) {
  x = x + 1;
}

Schritt 1: Wie entwickelt sich hier die Laufvariable? Der Startwert i ist 1 und die Veränderung in jedem Schritt ist  . Die Laufvariable entwickelt sich somit wie folgt:

Nach dem 1. Durchlauf  

Nach dem 2. Durchlauf  

Nach dem 3. Durchlauf  

Nach dem k. Durchlauf  

Schritt 2: Nach wie vielen Durchläufen wird die Schleife abgebrochen?

Der Abbruch erfolgt, wenn  

     : 

 

 

Somit erfolgt ein Abbruch nach    ⌉ Durchläufen.

public int berechne(int[] f1, int[] f2) {
   int result = 0;
   for (int i=0; i < f1.length; i++) {
      for (int j=0; j < f2.length; j++) {
         if (f1[i] == f2[j]) result++;
      }
   }
   return result;
}

Hier haben wir nun eine for Schleife mit mehreren Eingabevariablen. Die Problemgrößen sind  .

public int berechne2(int[] f1, int[] f2){
   f2 = mergeSort(f2);
   int result = 0;
   for (int i=0; i < f1.length; i++) {
      if (binarySearch(f2, f1[i])) result++;
   }
   return result;
}

Der Aufwand ist hier  . Somit ist die Aufwandsklasse  .

In diesem Beispiel haben wir wieder mehreren Eingabevariablen. Diese sind die gleichen Problemgrößen  .

public int berechne2(int[] f1, int[] f2){
   int result = 0;
   for (int i=0; i < f1.length; i++) {
      for (int j=0; j < f2.length; j++) {
         if (f1[i] == f2[j]) result++;
      }
   }
   return result;
}

Der Aufwand ist hier wie folgt:  . Somit ist die Aufwandsklasse  .

Literatur

Bearbeiten

Da die Vorlesungsinhalte auf dem Buch Algorithmen und Datenstrukturen: Eine Einführung mit Java von Gunter Saake und Kai-Uwe Sattler aufbauen, empfiehlt sich dieses Buch um das hier vorgestellte Wissen zu vertiefen. Die auf dieser Seite behandelten Inhalte sind in Kapitel 7.3.4 zu finden.