Probleme bei Berechnung der Komplexität

KäseSahne

Mitglied
Hallo,

ich brauche mal wieder eure Hilfe. Es geht um die Berechnung der Laufzeitkomplexität (O-Notation). Ich möchte damit Algorithmen vergleichen.
Meine erste Frage bezieht sich darauf, wie man die Komplexität eines Algorithmus berechnet, der von zwei Parametern abhängig ist. Hier mal ein Beispiel:

Code:
for(int i = 0; i < m; i++){
	for(int j= 0; j < n; j++){
		doSth();
	}
}

Wie man sieht, hängt die Anzahl der Aufrufe von "m" und "n" ab. Die Methode doSth() würde ja m*n-Mal aufgerufen. In welcher Komplexitätsklasse würde sich denn der Algorithmus befinden? Es hängt ja maßgeblich von der Größe von m ab. Ist m <= n, dann müsste die Komplexität quadratisch sein. Im Fall von m > n ist sie kubisch. Was nimmt man denn allg. für die Komplexität dieses Algorithmus an?

Meine zweite Frage betrifft ein weiteres Beispiel. Den Ablauf gebe ich in Pseudocode an:

Code:
int[] spielfeld = new int[m];
Spieler[] spielerAry = new Spieler[n];

erstelle Spieler;
berechne Felder der Spieler;

ArrayList<int[]> zustandsListe = new ArrayList<int[]>();

while(min. ein Spieler deaktiviert wurde){
	while(aktueller Zustand von spielfeld nicht in zustandsListe){
		aktuellen Zustand von spielfeld in zustandsListe schreiben;
		for(Spieler player : spielerAry){
			if(min. ein Feld von player in spielfeld blockiert){
				prüfe, ob player alle blockierten Felder günstiger erledigen kann als die eingetragenen Spieler;
				if(player kann alle Felder günstiger erledigen){
					lösche alle Spieler aus spielfeld, die player blockiert haben;
					Felder von player in spielfeld blockieren;
				}				
			}
		}			
	}
	alle Spieler, die in spielfeld stehen, deaktivieren;
	für jeden aktiven Spieler neue Felder berechnen (diese Felder müssen im Spielfeld noch frei sein);
	zustandsListe zurücksetzen;
}

Es gibt ein "spielfeld", das aus m Feldern besteht. Außerdem gibt es n Spieler. Für jeden Spieler werden zufällig Felder gewählt, die er im "spielfeld" belegen soll (Anzahl zufällig). Des Weiteren gibt es eine "zustandsListe", die an bestimmten Stellen im Algorithmus den Zustand des Spielfelds speichert.

Zu Beginn sind alle Spieler aktiv. Der Algorithmus wird solange ausgeführt, bis kein Spieler mehr deaktiviert wurde (erste while-Schleife). In der zweiten while-Schleife wird geprüft, ob der aktuelle Zustand des "spielfelds" in der "zustandsListe" steht. Ist das nicht der Fall, wird der aktuelle Zustand in die "zustandsListe" geschrieben. Jetzt wird das Spieler-Array durchlaufen. Für jeden aktiven Spieler wird geprüft, ob die Felder, die er im "spielfeld" belegen möchte, frei sind. Wird min. ein Feld von einem anderen Spieler blockiert, wird geprüft, welcher der Spieler dafür am günstigsten ist. Nur wenn der aktuelle Spieler (player) für alle blockierten Felder am günstigsten ist, wird er in das "spielfeld" eingetragen. Die Spieler, die ihn blockiert haben, werden vom "spielfeld" gelöscht.
Das wird so oft wiederholt, bis das "spielfeld" einen bereits bekannten Zustand angenommen hat. Daraufhin werden die Spieler, die jetzt noch im "spielfeld" stehen, deaktiviert, d.h. sie fließen nicht weiter in die Berechnungen mit ein. Für die noch aktiven Spieler werden wieder zufällig Felder gewählt, die sie belegen sollen. Die "zustandsListe" wird zurückgesetzt und alles beginnt von vorne.


Ich hoffe, dass ihr den Algorithmus halbwegs nachvollziehen konntet. Auch hier ist mein Problem die Berechnung der Komplexität. Ich habe keine Ahnung, wie ich mit den beiden while-Schleifen umgehen soll.

Ich hoffe, dass ihr mir ein paar Tipps geben könnt, wie man an das Problem rangeht.

Vielen Dank im Voraus!
 

dcc

Aktives Mitglied
Es gibt immer: best case, average und worst case Laufzeiten.
:)

Wenn du die Formel hast, dann lässt zum Schluss einfach die Konstanten und Multiplikationen weg.
Ist der Rechner schneller als der vorherige, dann sagt dir eine Multiplikation nix. Konstanten sind so klein dass man sie vernachlässigt.
 
Zuletzt bearbeitet:

KäseSahne

Mitglied
Hallo dcc,

vielen Dank für deine Antwort.
Im ersten Fall gibt es doch kein best case und worst case, oder? Die Methode wird immer n*m mal aufgerufen. Für die Komplexität muss man doch eine Funktion bestimmen, die die Obergrenze darstellt, richtig? Und das hängt doch entscheidend von m ab. Angenommen m wäre 1 und n > 0, dann würde die Methode n mal ausgeführt, also O(n). Sobald aber m > 1 wäre, dann würde ja g(n) nie die Obergrenze darstellen.
Und dann gibt es außerdem die Fälle m > n und m < n.
Würde man immer knallhart sagen, dass m eine Konstante ist und es somit eine Komplexität von O(n) hat?

Im zweiten Fall müsste der best case O(n) betragen. Ist das richtig? Die for-Schleife wird auf alle Fälle mindestens 2 mal ausgeführt, bis es zu einem doppelten Zustand kommen kann. Unter der Annahme, dass die äußerste Schleife beendet wird, wenn alle Spieler inaktiv sind oder alle Felder des Spielfelds belegt sind. Was mir da Probleme bereitet, ist der worst case.
 
Hallo,
Meine erste Frage bezieht sich darauf, wie man die Komplexität eines Algorithmus berechnet, der von zwei Parametern abhängig ist. Hier mal ein Beispiel:

Code:
for(int i = 0; i < m; i++){
	for(int j= 0; j < n; j++){
		doSth();
	}
}

Wie man sieht, hängt die Anzahl der Aufrufe von "m" und "n" ab. Die Methode doSth() würde ja m*n-Mal aufgerufen. In welcher Komplexitätsklasse würde sich denn der Algorithmus befinden? Es hängt ja maßgeblich von der Größe von m ab. Ist m <= n, dann müsste die Komplexität quadratisch sein. Im Fall von m > n ist sie kubisch. Was nimmt man denn allg. für die Komplexität dieses Algorithmus an?
Du beantwortest deine Frage fast schon selber: Die Komplexität ist O(n*m). Wenn du jetzt weisst, dass generell n > m gilt, dann ist die Komplexität quadratisch in n, also O(n^2). Warum sie kubisch sein sollte, sehe ich nicht. Natürlich kann O(n) = O(m^2) gelten, dann könntest du die Laufzeit durch O(m^3) abschätzen, sie wäre dann kubisch in m. Andersherum könntest du sie in diesem Fall aber auch, und das würdest du eher tun, durch O(n^2) oder einen noch geringeren Wert abschätzen.

Wichtig ist, dass die Abschätzung für alle Fälle gelten muss, denn O ist eine asymptotisch obere Schranke. Eine Worst Case Abschätzung: Mag es auch nur einen Fall geben, wo die Laufzeit > O(n^2) ist, ist die Abschätzung O(n^2) falsch. (Als kluger Algorithmenbastler würdest du für diesen Fall dann eine Sonderbehandlung programmieren und könntest dann die Abschätzung O(n^2) vornehmen). Beispielsweise gibt es viele NP-schwere Probleme, die für fast jede Eingabe polynomiell gelöst werden können, aber für eine geringe Anzahl eben doch eine nicht polynomielle Laufzeit haben. Das Rucksackproblem ist dafür ein klassisches Beispiel, es ist nur deshalb NP-vollständig, weil die Größenunterschiede zwischen den Objekten exponentiell sein können, was insgesamt zu einer superpolynomiellen (also nicht mehr polynomiellen) Laufzeit führt.
Deshalb ist z. B. auch die Aussage, dass deine Programme eine Laufzeit O(2^n) haben völlig korrekt, aber sinnfrei. Ziel ist es immer eine obere Schranke zu finden, die so knapp wie möglich über dem Maximalwert liegt.

Das heißt, in deinem Beispiel gehst du erstmal von O(m*n) aus und guckst dann weiter, ob du m oder n näher einschränken kannst. Z. B. könnte m eine Konstante sein oder durch eine unheimlich große Konstante abschätzbar sein (z. B. m ist egal für welche Eingabe geringer als 10^112338912112), dann wäre die Laufzeit O(n). Oder du kannst zeigen, dass m <= log n ist, dann wäre deine Abschätzung O(n*log n). Und das kann in realen Anwendung den Unterschied zwischen nutzbar und viel zu lang bedeuten. Setze einfach mal große Zahlen für m und n ein, sehe diese als Anzahl der Rechenschritte und guck dir den Unterschied an. Deshalb ist es auch so relevant die Laufzeitkomplexität auch nur minimal zu drücken: Jede geringfügige Verringerung in der Abschätzung von m kann für große Eingaben einen drastischen Unterschied machen. Das ist auch der Grund, warum Konstanten und seien sie auch unfassbar groß, ignoriert werden: Es gibt immer den Punkt, wenn man die Problemgröße erhöht, wo die Konstanten keine signifikante Rolle mehr spielen.

Meine zweite Frage betrifft ein weiteres Beispiel. Den Ablauf gebe ich in Pseudocode an:

Code:
while(min. ein Spieler deaktiviert wurde){
	while(aktueller Zustand von spielfeld nicht in zustandsListe){
		aktuellen Zustand von spielfeld in zustandsListe schreiben;
		for(Spieler player : spielerAry){
			...			
			}
		}			
	}
}
Ich durchschaue dein Programm nicht, aber du kannst immer so vorgehen: Du hast ja schon selber festgestellt, dass die Zahl der Schleifendurchläufe multipliziert werden muss. Und genau so gehst du jetzt auch hier vor: Du betrachtest jede Schleife einzeln und schätzt nach oben ab, wie oft sie maximal durchlaufen wird. Diese Werte multiplizierst du und hast im Grunde deine Laufzeit. Die Kunst ist natürlich jetzt nicht ein Ergebnis O(n*m*l*k) zu haben, sondern die einzelnen Werte zueinander in Beziehung zu setzen, also z. B. zu merken: m < log n, l = Konstant und O(k) = O(n), denn dann hast du als Ergebnis O(n^2 * log n). Wenn du vor oder nach der Schleife noch Berechnungen hast und du weißt, dass die in jedem Fall eine geringere Komplexität haben, dann fallen sie weg. Warum? Ganz einfach, du könntest das Programm insgesamt dann durch O(2 * n^2*log n) abschätzen, hättest also nur eine Konstante mehr und die fällt weg. Mit ein bisschen Übung wirst du dir so ein Programm nehmen und direkt die relevanten Teile extrahieren. In diesem Fall wohl nur die Schleifen und auch dort sehen: was ist konstant und fällt weg und wie lassen sich die einzelnen Durchläufe durch eine oder zwei Variablen m und n abschätzen.
 

KäseSahne

Mitglied
Vielen Dank für deine sehr ausführliche Antwort, Alex.
Der Grund, weshalb ich gedacht habe, dass die Komplexität kubisch ist, ist der Fall, wenn m > n ist. Ich kann leider nicht pauschal sagen, dass m < n immer gilt, da das vom Benutzer abhängig ist. Ich kann nur sicher sagen, dass m > 0 sein muss.

Kurz etwas zum Zweck des ersten Algorithmus: Dieser Algorithmus ist ein heuristischer Algorithmus zur Lösung eines Tourenplanungsproblems. Der Benutzer kann mit m angeben, wie oft versucht werden soll, die Lösung zu verbessern.

Der zweite Algorithmus bezieht sich auch auf ein Tourenplanungsproblem. Ich habe versucht, ihn grob mit dem Pseudocode auf einer anderen Ebene zu erklären, das ist mir wohl nicht wirklich gelungen :(.

Entschuldigung, wenn ich mich etwas blöd anstelle, aber Komplexitätsberechnung war nie wirklich mein Fall.
 
Vielen Dank für deine sehr ausführliche Antwort, Alex.
Der Grund, weshalb ich gedacht habe, dass die Komplexität kubisch ist, ist der Fall, wenn m > n ist. Ich kann leider nicht pauschal sagen, dass m < n immer gilt, da das vom Benutzer abhängig ist. Ich kann nur sicher sagen, dass m > 0 sein muss.

Kurz etwas zum Zweck des ersten Algorithmus: Dieser Algorithmus ist ein heuristischer Algorithmus zur Lösung eines Tourenplanungsproblems. Der Benutzer kann mit m angeben, wie oft versucht werden soll, die Lösung zu verbessern.
Dann kannst du nicht mehr über die Laufzeit des Algorithmus aussagen, als dass sie O(m*n) entspricht. Quadratisch oder kubisch bezieht sich auf eine einzelne Eingabe. Wenn du hier zwei Eingabewerte hast, die du auch nicht in einen Zusammenhang stellen kannst, dann kannst du auch keine weitergehende Aussage treffen. Denn warum sollte der Nutzer nicht 2^n als Wert eingeben, dann wäre die Laufzeit exponentiell in n.
 

Highchiller

Bekanntes Mitglied
Ein kleiner Tipp noch am Rande. Wenn du dir nicht sicher sein solltest ob eine Funktion f auch in O(g) liegt, hilft dir sicherlich die mathematische Definition weiter. Die findest du ganz übersichtlich bei Wikipedia: Landau-Symbole.

Wenn du dich mit den mathematischen Notationen auskennst kannst du einfach überprüfen ob f in O(g) liegt indem du es in die Definition einsetzt und rechnest.

Auf die Art kannst du dann auch ganz leicht beweisen das zum Beispiel 2n auch in O(n) liegt. Genauso wie 2+n auch in O(n) liegt. Und so weiter.
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
A Probleme bei der Berechnung von Pi! Java Problem Allgemeine Java-Themen 2
C Probleme beim Erstellen eines runnable-jar files Allgemeine Java-Themen 1
S Umstellung von File auf Path - Probleme mit Stream Allgemeine Java-Themen 5
C Probleme mit javax.mail.Session Allgemeine Java-Themen 8
M tomcat probleme Allgemeine Java-Themen 1
N Division macht Probleme Allgemeine Java-Themen 14
B Java Reflection Probleme beim wehcselseitigen Referenzieren zweier Klassen/Objekte Allgemeine Java-Themen 14
MarvinsDepression Probleme mit relativem Dateipfad Allgemeine Java-Themen 1
G Geotools Probleme nach PC-Wechsel Allgemeine Java-Themen 6
nibe1501 GUI Probleme Allgemeine Java-Themen 16
C Probleme mit dem WindowBuilder Allgemeine Java-Themen 3
P Selenium . Probleme ein Iron Icon Element anzusprechen Allgemeine Java-Themen 2
B Compiler-Fehler Probleme beim Kompilieren mit Jsoup Allgemeine Java-Themen 8
K VisualVM Profiling Remote Probleme Allgemeine Java-Themen 1
O Leerzeichen und Umlaute im Pfad einer Java Applikation machen Probleme Allgemeine Java-Themen 13
M Probleme bei Eclipse wenn ich entpacke Allgemeine Java-Themen 15
D Regex Probleme Allgemeine Java-Themen 2
M Probleme jar datei. Allgemeine Java-Themen 2
L Vererbung Verständnis Probleme Vererbung Allgemeine Java-Themen 2
Dann07 Probleme mit OpenAL Allgemeine Java-Themen 0
V Threads Probleme beim Aufrufen von Methoden einer anderen Klasse (Threads) Allgemeine Java-Themen 14
V Compiler-Fehler Online Compiler Probleme Allgemeine Java-Themen 4
M Probleme mit Negamax-Algorithmus Allgemeine Java-Themen 29
M Probleme mit BigDecimal Allgemeine Java-Themen 1
T Probleme mit NumberFormat Allgemeine Java-Themen 5
J Probleme exe-Start mit Task Scheduler Allgemeine Java-Themen 1
B Input/Output Probleme beim Ausführen von Shell-Befehlen mit Java Allgemeine Java-Themen 28
J Probleme beim einbinden von Zip4j library Allgemeine Java-Themen 6
F Variablen Palindromzahl (Probleme mit Methode) Allgemeine Java-Themen 9
K Data Konverter - Probleme mit Byte[] Kodierung Allgemeine Java-Themen 3
T Probleme mit dem Pfad zum Propertie file Allgemeine Java-Themen 7
H Swing HashMap zu Tabelle macht mir Probleme Allgemeine Java-Themen 4
Neoline Interpreter-Fehler Probleme mit Arrays.toString Allgemeine Java-Themen 7
F SQLite mit Java / Probleme beim INSERT Befehl Allgemeine Java-Themen 4
J Erste Schritte Probleme mit der Hauptklasse Allgemeine Java-Themen 14
J Tetris Probleme bei Klassen Allgemeine Java-Themen 14
J MinMax VierGewinnt Probleme Allgemeine Java-Themen 22
J Probleme mit CodeCoverage und Lombok Equals Allgemeine Java-Themen 1
S Eclipse Probleme beim Implementieren / Ausführen von jUnit 5-Test Suites Allgemeine Java-Themen 14
R Snake Probleme Allgemeine Java-Themen 2
A Probleme beim Verstehen einer Aufgabenstellung Allgemeine Java-Themen 11
RalleYTN 3D Objekt Translation basierend auf Rotation (Probleme mit Z Rotation) Allgemeine Java-Themen 0
Bluedaishi Druck Probleme mit PDF dateien Allgemeine Java-Themen 4
G Ant Probleme bei einer Installation die Apache ant+ivy verwendet Allgemeine Java-Themen 14
E TableView Probleme Allgemeine Java-Themen 7
perlenfischer1984 Probleme beim Mocken Allgemeine Java-Themen 6
S Kaffemaschine Programmierung Probleme Allgemeine Java-Themen 2
K Threads Runtime und Process Probleme Allgemeine Java-Themen 3
S Probleme mit unterschiedlichen Java-Versionen (Mac OS X 10.11) Allgemeine Java-Themen 0
S Event Handling keyPressed()-Probleme Allgemeine Java-Themen 2
VfL_Freak Große und seltsame Probleme nach Java-Update auf V1.8.0_91 Allgemeine Java-Themen 3
P Probleme mit Grafik (Java) Allgemeine Java-Themen 6
R probleme beim starten von jar unter linux Allgemeine Java-Themen 2
H Probleme mit DAY_OF_WEEK Allgemeine Java-Themen 4
Arif Probleme mit NullPointerException Allgemeine Java-Themen 2
E Probleme mit nextInt() und Exception Allgemeine Java-Themen 35
Streeber Probleme mit AWT-EventQueue: ArrayList Elemente hinzufügen Allgemeine Java-Themen 1
D Performance-Probleme mit Joda-Time Allgemeine Java-Themen 3
M Probleme beim rechnen, bei Zahlen mit führenden Nullen. Allgemeine Java-Themen 7
RalleYTN Probleme mit Encrypting Allgemeine Java-Themen 10
M Probleme mit Schriftarten PDFBox Allgemeine Java-Themen 3
J Probleme mit der Java-Runtime Allgemeine Java-Themen 10
G Probleme mit BufferedWriter und URL Allgemeine Java-Themen 4
S Probleme mit meinem MacBook Pro DRINGEND HILFE erbeten! Allgemeine Java-Themen 17
Androbin Interpreter-Fehler Probleme mit Rekursion - StackOverflowError Allgemeine Java-Themen 8
E JCuda-0.6.5 Probleme beim ausführen der Datei Allgemeine Java-Themen 0
M Runtime.exec() verursacht auf manchen Systemen Probleme - Ursache unklar Allgemeine Java-Themen 2
W JNDI - LDAP - Probleme beim editieren von Usern Allgemeine Java-Themen 0
R DBUnit Performance Probleme Allgemeine Java-Themen 0
S Probleme mit Collection Allgemeine Java-Themen 7
L Probleme mit Jar Allgemeine Java-Themen 6
N Zahlensysteme umrechnen; Probleme beim Umwandeln Allgemeine Java-Themen 4
K OOP OOP Gui Spiel + Vererbungen Probleme durch Nichtwissen!! Allgemeine Java-Themen 1
F Java Native/Shared Library (.so) laden macht Probleme Allgemeine Java-Themen 3
J Synchronized Probleme Allgemeine Java-Themen 7
J Java Progressbar & Download Probleme Allgemeine Java-Themen 10
S Probleme mit dem filechooser Allgemeine Java-Themen 1
J Comperator Probleme Allgemeine Java-Themen 4
A Probleme beim auslesen von Quelltext (HTML) Allgemeine Java-Themen 5
S Probleme mit Webappplikation Allgemeine Java-Themen 5
L Plötzlich Probleme mit der JVM :( Allgemeine Java-Themen 6
S starke performance probleme des forums Allgemeine Java-Themen 10
R JRE Ablaufdatum seit 7u10 - Probleme bei selbst ausgelieferter JRE bekannt? Allgemeine Java-Themen 3
H Reg Exp Probleme Allgemeine Java-Themen 5
M Classpath Probleme bei JAR Generierung Allgemeine Java-Themen 2
S Probleme mit JAVA-Installation Allgemeine Java-Themen 3
D Probleme bei for-Schleife Allgemeine Java-Themen 4
R Probleme mit Javadoc Allgemeine Java-Themen 2
G Gson Probleme Allgemeine Java-Themen 2
P KI für TicTacToe programmieren > Probleme Allgemeine Java-Themen 2
M Google App Engine macht Probleme Allgemeine Java-Themen 4
H Probleme mit finally-Block und close() Allgemeine Java-Themen 4
F 2d array probleme Allgemeine Java-Themen 2
M 3D-Grafik Probleme beim drehen von Objekten Allgemeine Java-Themen 9
T Interface Probleme Allgemeine Java-Themen 8
C Eclipse Probleme bei selbst erstelltem Algorithmus Allgemeine Java-Themen 2
M Probleme mit String in Label übergeben. Allgemeine Java-Themen 6
H MediaManager Fragen/Probleme Allgemeine Java-Themen 6
U Probleme mit Kopiervorgang Allgemeine Java-Themen 3
S Probleme beim Auslesen einer Liste Allgemeine Java-Themen 8

Ähnliche Java Themen

Neue Themen


Oben