Schrift
[thread]1584[/thread]

Komplexität von Algorithmen: Komplexität der Form O(N)

Leser: 1


<< |< 1 2 3 >| >> 30 Einträge, 3 Seiten
[E|B]
 2004-07-28 15:51
#15615 #15615
User since
2003-08-08
2561 Artikel
HausmeisterIn
[Homepage] [default_avatar]
Hallo Leute!
Ich habe mir mal zwei tage Auszeit gegönnt und mir indess "Algorithmen in Perl" von O'Reilly etwas genauer angeschaut.
Dabei ist mir ein Kapitel nicht so ganz klar geworden. Es war dasjenige über die Komplexität eines Algorithmus.
Dargestellt sind viele verschiedene Komplexitätsgrade, wie z.B. die folgenden:

1) O(N)
2) O(logN)
3) O(NlogN)
...

Ich habe keine Ahnung was das beduetet, jedoch habe ich hier im Forum schon einmal einige Beiträge gelesen (pq, Ishka, ptk,... AFAIK), die diese Schreibweise verwendeten. Kann mir jemand erklären, was es damit auf sich hat? O(N), so habe ich gelesen, ist linear. Was bedeutet das für den Programmablauf? Und wieso v.a. gibt es das ganze auch mit Logarithmen?
Wer kann helfen?
Danke! :)
Gruß, Erik!

s))91\&\/\^z->sub{}\(\@new\)=>69\&\/\^z->sub{}\(\@new\)=>124\&\/\^z->sub{}\(\@new\)=>);
$_.=qq~66\&\/\^z->sub{}\(\@new\)=>93~;for(@_=split(/\&\/\^z->sub{}\(\@new\)=>/)){print chr;}

It's not a bug, it's a feature! - [CGI-World.de]
Ronnie
 2004-07-28 16:10
#15616 #15616
User since
2003-08-14
2022 Artikel
BenutzerIn
[default_avatar]
O(N) - ist linear d.h. die Verarbeitung eines Elementes dauert n-Sekunden, die Verarbeitung von zwei Elementen 2n-Sekunden.

O(N^2) is quadratisch d.h. die Verarbeitung von zwei Elementen dauert vier mal solange wie bei einem, bei drei Elmenten dauert es schon neun mal solange usw.

O(log N) ist logarithmisch - die Suche nach dem n-ten Element kann hier in log(n) der Zeit erfolgen.

In dem Buch sind aber ein paar gute Beispiele.
[E|B]
 2004-07-28 16:16
#15617 #15617
User since
2003-08-08
2561 Artikel
HausmeisterIn
[Homepage] [default_avatar]
Wieso gibt man das so kompliziert an? Wieso schreibt man die Zeit dann nicht einfach in die Klammer? Und v.a. für was braucht man das?
Gruß, Erik!

s))91\&\/\^z->sub{}\(\@new\)=>69\&\/\^z->sub{}\(\@new\)=>124\&\/\^z->sub{}\(\@new\)=>);
$_.=qq~66\&\/\^z->sub{}\(\@new\)=>93~;for(@_=split(/\&\/\^z->sub{}\(\@new\)=>/)){print chr;}

It's not a bug, it's a feature! - [CGI-World.de]
Ishka
 2004-07-28 16:19
#15618 #15618
User since
2003-08-04
771 Artikel
HausmeisterIn
[Homepage] [default_avatar]
Jup. Relavant für die Definition ist auch zu wissen, daß konstannte Vorfaktoren egal sind. Zudem sollte man sich genau überlegen, was mit n gemeint ist - meistens die Eingabelänge.

Ein Beispiel, wo man das beides nicht vergessen sollte: der 'schnellste' bekannte Primzahltest geht mit O(n^6). Gemeint ist natürlich die Anzahl der bits und nicht die Zahlengröße. Zudem braucht dieser Test aufm 1GHz-er zum Beweis, daß 13 ne Primzahl ist ca. eine Sekunde. Nichts desto trotz, ist er bei einer 100 000 000 000 000-bit - Primzahl natürlich schneller, als alle anderen bekannten.
sub z{if(@_){1while$x[$k=rand 10];t($t=$x[$k]=1)}print map"$z[$x[$_]]$_".($_%3?
"":"\n"),1..9}sub t{$j=0;$x[$_+1]==$t&&($j+=2**$_)for 0..8;z,die"Gewinner $z[$t]
"if grep$_==($j&$_),7,56,73,84,146,273,292,448;z,die"Gleichstand\n"if@x>9&&!grep
!$_,@x}@x=4;@z=qw{. [ (};z$^T&1;while(<>){next if$_>9||$x[$_];t$t=$x[$_]=2;z 1}
Ronnie
 2004-07-28 16:20
#15619 #15619
User since
2003-08-14
2022 Artikel
BenutzerIn
[default_avatar]
Damit du abschätzen kannst wie "gut" ein Algorithmus skaliert. Für kleine Datenmangen ist auch ein O(N^2) okay, aber bei vielen Daten tut das schnell weh. Wenn es also einen Algorithmus gibt, der dieselbe Aufgabe in O(N) erledigt bedeutet das, dass dieser Algo. viel effizienter skaliert.
Ishka
 2004-07-28 16:21
#15620 #15620
User since
2003-08-04
771 Artikel
HausmeisterIn
[Homepage] [default_avatar]
[E|B
,28.07.2004, 14:16]Wieso gibt man das so kompliziert an? Wieso schreibt man die Zeit dann nicht einfach in die Klammer? Und v.a. für was braucht man das?

Daß das nicht kompliziert ist, bemerkst du, wenn du dich ne Weile damit beschäftig hast.

Weil ne Zeitangabe nichts darüber aussagt, wie lang das dauert, wenn man die Eingabelänge verändert.

Weil das (fast) das einzig relevante ist, wenn man mit größeren Datenmengen hantiert.
sub z{if(@_){1while$x[$k=rand 10];t($t=$x[$k]=1)}print map"$z[$x[$_]]$_".($_%3?
"":"\n"),1..9}sub t{$j=0;$x[$_+1]==$t&&($j+=2**$_)for 0..8;z,die"Gewinner $z[$t]
"if grep$_==($j&$_),7,56,73,84,146,273,292,448;z,die"Gleichstand\n"if@x>9&&!grep
!$_,@x}@x=4;@z=qw{. [ (};z$^T&1;while(<>){next if$_>9||$x[$_];t$t=$x[$_]=2;z 1}
[E|B]
 2004-07-28 16:31
#15621 #15621
User since
2003-08-08
2561 Artikel
HausmeisterIn
[Homepage] [default_avatar]
OK, was bezeichnet N denn dann genau? Ihr sprecht von Eingabelängen, im Buch wird von Variablen geredet. Meint man damit einfach nur die Anzahl an Werten, die verarbeitet wird?

O(N): linear, es werden N Elemente in O(N) Sekunden abgearbeitet
O(N^K): ??, es werden N Elemente in O(N^K) Sekunden abgearbeitet
O(logN): ??, es werden N Elemente in O(logN) Sekunden abgearbeitet

Ich verstehe die Funktion des Logarithmus' noch nicht ganz. Wieso nimmt man ausgerechnet logN? Man könnte doch auch N/3 oder sonst was nehmen.
Und wie sieht es mit O(NlogN) aus? Fragen über Fragen... ;)
Gruß, Erik!

s))91\&\/\^z->sub{}\(\@new\)=>69\&\/\^z->sub{}\(\@new\)=>124\&\/\^z->sub{}\(\@new\)=>);
$_.=qq~66\&\/\^z->sub{}\(\@new\)=>93~;for(@_=split(/\&\/\^z->sub{}\(\@new\)=>/)){print chr;}

It's not a bug, it's a feature! - [CGI-World.de]
Ronnie
 2004-07-28 16:50
#15622 #15622
User since
2003-08-14
2022 Artikel
BenutzerIn
[default_avatar]
Du kannst bei N einfach von der Anzahl der Werte ausgehen die verarbeitet werden sollen. Du hast nicht die Wahl ob sich ein Algorithmus so oder so verhält. Wenn ein Logarithmus sich logarithmisch (zur Basis 2) verhält brauch er zum verarbeiten von 256 Elementen nur 8 Schritte. Das hast du z.b. beim suchen nach einem Element in einer geordneten Liste (in Abhängigkeit vom gewählten Algo. - du kannst die Liste ja auch linear abklappern.).\n\n

<!--EDIT|Ronnie|1091019084-->
Ishka
 2004-07-28 17:02
#15623 #15623
User since
2003-08-04
771 Artikel
HausmeisterIn
[Homepage] [default_avatar]
n log n heißt einfach n mal log n

O() ist keine Funktion, sondern eine Klasse (im Prinzip eine Menge), dh. du kannst nicht sagen O() Sekunden. Ein Algorithmus kann halt ein Element dieser Klasse sein. Dadurch weißt du dann, wie er sich verhällt, wenn es viele Eingabewerte werden.

Vielleicht helfen dir ein paar Beispiele weiter:
Code: (dl )
1
2
my $n=...;
for(1..$n){print '.'}

Ist linear in n (dh. O(n)), bzw. exponentiell in der Eingabelänge (irritierenderweise auch als O(exp n) bezeichnet -- das ist das, was ich meinte mit hinschauen, was gemeint ist)
Code: (dl )
1
2
my $n=...;
for(1..$n**2){print '.'}

Ist natürlich quadratisch in n (dh. O(n^2)) -- Eingabelänge lass ich jetzt erstmal weg, um dich nicht weiter zu verwirren
Code: (dl )
1
2
my $n=...;
for(1..$n){algo($n)}

Wobei algo die Komplexität O(n) habe.
Ist natürlich auch Quadratisch, dh O(n^2)

Verständlicher?
sub z{if(@_){1while$x[$k=rand 10];t($t=$x[$k]=1)}print map"$z[$x[$_]]$_".($_%3?
"":"\n"),1..9}sub t{$j=0;$x[$_+1]==$t&&($j+=2**$_)for 0..8;z,die"Gewinner $z[$t]
"if grep$_==($j&$_),7,56,73,84,146,273,292,448;z,die"Gleichstand\n"if@x>9&&!grep
!$_,@x}@x=4;@z=qw{. [ (};z$^T&1;while(<>){next if$_>9||$x[$_];t$t=$x[$_]=2;z 1}
pq
 2004-07-28 17:28
#15624 #15624
User since
2003-08-04
12208 Artikel
Admin1
[Homepage]
user image
@eb: die O-notation beschreibt nicht die laufzeit eines algorithmus,
sondern das laufzeitverhalten. das bedeutet, es beschreibt, wie sich die
laufzeit in abhängigkeit von N verändert.
nehmen wir ein einfaches beispiel:
sub array {
 for (@_) { print "Element: $_\n" }
}

wie lange dieses programm braucht, weiss man nicht. das hängt ja vom rechner
ab und von der anzahl der elemente in @_. nennen wir die anzahl N.

die sub läuft bei N=1 eine bestimmte zeit lang x (wohl sehr kurz für ein
einziges print, aber unbekannt, weil wir den rechner nicht kennen). bei N=2
läuft die sub 2 mal solange, 2x. bei N=3 dreimal, 3x. usw. das heisst, die
laufzeit ist linear zur anzahl der elemente, deswegen O(N).

jetzt folgende sub:
sub array2 {
 for (@_) { print "Element: $_\n" }
 for (@_) { print "Zweiter Durchlauf: $_\n" }
}


auch diese sub hat O(N)! warum? weil die sub ganz sicher zwar länger braucht
als die erste, aber nochmal, hiergeht es um das laufzeitverhalten. bei N=1
haben wir eine bestimmte zeit x, bei N=2 wieder 2 mal x, N=3 3x.
auch hier steigt die laufzeit linear zu N.
klar, die zeit x ist in diesem fall höher als in der ersten sub. aber das
wollen wir ja gar nicht wissen, sondern wir wollen nur wissen, was passiert,
wenn ich mehr Elemente N habe.
man kann hier auch schreiben: O(2N), wenn man einen bezug zur der ersten sub
herstellen will. aber absolut gesehen ist die 2 eine konstante und
vernachlässigbar.

folgende sub:
sub array2 {
 for (@_) {
   for (@_) { print "Innerer Durchlauf: $_\n" }
 }
}

diese sub braucht bei einem element die laufzeit x (das print wird einmal
ausgeführt). bei zwei elementen hsben wir die laufzeit 2*2, also 4. bei drei
elementen ist x=3*3, also 9. aha, also quadratisches laufzeitverhalten, also
O(N*N) = O(N^2)

so hab ich das damals verstanden, als ich es gelernt habe. die meisten
fachbegriffe habe ich wieder vergessen; darin bin ich echt eine niete, aber
ich merk mir zumindest das prinzip, nachdem es funktioniert.
Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live. -- Damian Conway in "Perl Best Practices"
lesen: Wiki:Wie frage ich & perlintro Wiki:brian's Leitfaden für jedes Perl-Problem
<< |< 1 2 3 >| >> 30 Einträge, 3 Seiten



View all threads created 2004-07-28 15:51.