Edit: Hauptrevision in Revision 3.
Da ich noch nie eine Klasse unterrichtet habe, glaube ich nicht, dass ich überzeugend behaupten kann, was wir unterrichten sollen. Trotzdem, hier sind meine Gedanken dazu.
Es gibt natürliche Beispiele, bei denen der beschriebene „Limit-Trick“ nicht angewendet werden kann. Angenommen, Sie implementieren einen „Vektor variabler Länge“ (wie Vektor <T> in C ++), indem Sie ein Array fester Länge mit doppelter Größe verwenden (dh jedes Mal, wenn Sie die Größe des Arrays überschreiten möchten, tun Sie dies Ordnen Sie das doppelt so große Array neu zu und kopieren Sie alle Elemente. Die Größe S ( n ) des Arrays, wenn wir n Elemente im Vektor speichern, ist die kleinste Potenz von 2 größer oder gleich n . Wir wollen sagen, dass S ( n ) = O ( n ) ist, aber die Verwendung des als Definition geschriebenen „Limit-Tricks“ würde uns dies nicht erlauben, weil S ( n)) / n schwingt dicht im Bereich [1,2). Gleiches gilt für Ω () und Θ ().
Wenn wir diese Notationen verwenden, um die Komplexität eines Algorithmus zu beschreiben, denke ich, dass Ihre Definition von Ω () manchmal unbequem ist (obwohl ich denke, dass diese Definition üblich ist). Es ist bequemer, f ( n ) = Ω ( g ( n )) genau dann zu definieren, wenn limsup f ( n ) / g ( n )> 0 ist. Dies liegt daran, dass einige Probleme für unendlich viele Werte von n (trivial sind. wie das perfekte Bearbeitungsproblem in einem Graphen mit einer ungeraden Anzahl n von Eckpunkten). Gleiches gilt für Θ () und ω ().
Daher finde ich persönlich, dass die folgenden Definitionen am bequemsten sind, um die Komplexität eines Algorithmus zu beschreiben: für Funktionen f , g : ℕ → ℝ > 0 ,
- f ( n ) = o ( g ( n )) genau dann, wenn limsup f ( n ) / g ( n ) = 0. (Dies ist äquivalent zu lim f ( n ) / g ( n ) = 0.)
- f ( n ) = O ( g ( n )) genau dann, wenn limsup f ( n ) / g ( n ) <∞ ist.
- f ( n ) = Θ ( g ( n )) genau dann, wenn 0 <limsup f ( n ) / g ( n ) <∞ ist.
- f ( n ) = Ω ( g ( n )) genau dann, wenn limsup f ( n ) / g ( n )> 0. (Dies ist äquivalent zu dem, dass f ( n ) nicht o ( g ( n )) ist.)
- f ( n ) = ω ( g ( n )) genau dann, wenn limsup f ( n ) / g ( n ) = ∞ ist. (Dies ist äquivalent dazu, dass f ( n ) nicht O ( g ( n )) ist.)
oder äquivalent,
- f ( n ) = o ( g ( n )) , wenn und nur wenn für jeden c > 0 ist , für ausreichend großen n , f ( n ) ≤ c ⋅ g ( n ).
- f ( n ) = O ( g ( n )) , wenn und nur wenn für einige c > 0 ist , für ausreichend große n , f ( n ) ≤ c ⋅ g ( n ).
- f ( n ) = Θ ( g ( n )) genau dann, wenn f ( n ) = O ( g ( n )) und f ( n ) = Ω ( g ( n )).
- f ( n ) = Ω ( g ( n )) genau dann, wenn für einige d > 0, für unendlich viele n , f ( n ) ≥ d ⋅ g ( n ).
- f ( n ) = ω ( g ( n )) genau dann, wenn für jedes d > 0, für unendlich viele n , f ( n ) ≥ d ⋅ g ( n ).
Aber ich weiß nicht, ob dies eine gängige Praxis ist oder nicht. Ich weiß auch nicht, ob es für den Unterricht geeignet ist. Das Problem ist, dass wir manchmal Ω () stattdessen durch liminf definieren möchten (wie Sie es in der ersten Definition getan haben). Wenn wir zum Beispiel sagen: "Die Fehlerwahrscheinlichkeit dieses randomisierten Algorithmus ist 2 - Ω ( n ) ", meinen wir nicht, dass die Fehlerwahrscheinlichkeit nur für unendlich viele n exponentiell klein ist !