Big O (n ^ 2 + n) / 2 büyüme hızına sahip bir algoritma hakkında soru


16

Bu soruyu soruyorum çünkü büyük O gösterimi ile ilgili bir konu hakkında kafam karıştı.

Frank Carrano'nun Java ile Veri Yapıları ve Soyutlamalar kitabını kullanıyorum . "Algoritmaların Verimliliği" bölümünde aşağıdaki algoritmayı gösterir:

int sum = 0, i = 1, j = 1
for (i = 1 to n) {
    for (j = 1 to i)
        sum = sum + 1
}

Başlangıçta bir büyüme oranına sahip olarak algoritması anlatılmaktadır (n 2  + n) / 2 . Hangi bakmak sezgisel görünüyor.

Bununla birlikte, o zaman ifade edilmektedir (n 2  + n) / 2 davranır gibi N 2 , n büyüktür. Aynı paragrafta (n 2  + n) / 2'nin de n 2 / 2'ye benzer şekilde davrandığını belirtmektedir . Bunu yukarıdaki algoritmayı O (n 2 ) olarak sınıflandırmak için kullanır .

O olsun (n 2  + N) / 2 ile benzerdir , n 2 / 2 akıllı için yüzdesi, n, bir fark yoktur. Ne alamadım neden (n 2  + n) / 2 ve n 2 benzer, ne zaman , n büyüktür.

Örneğin, n = 1.000.000 ise :

(n^2 + n) / 2 =  500000500000 (5.000005e+11)
(n^2) / 2     =  500000000000 (5e+11)
(n^2)         = 1000000000000 (1e+12)

Bu sonuncusu hiç de benzer değil. Aslında, oldukça açık bir şekilde, orta olanın iki katı . Peki Frank Carrano benzer olduklarını nasıl söyleyebilir? Ayrıca, algoritma O (n 2 ) olarak nasıl sınıflandırılır . Bu iç döngüye baktığımda n 2 + n / 2 olduğunu söyleyebilirim


Eğer ilgileniyorsanız ben yürütme ağaç diyagramı kontrol ile üç iç içe döngü için bir cevap vermişti İç içe döngüler ile ilgili bir bulmaca
Grijesh Chauhan



1
temel olarak fikir, nbüyüdükçe, hem 'n ^ 2' işlevleri hem de işleviniz benzer şekilde davranır, büyüme hızlarında sabit bir farklılık vardır. Karmaşık bir ifadeniz varsa, daha hızlı büyüyen fonksiyon hakimdir.
AK_

1
@MichaelT: Bunun bu sorunun bir kopyası olduğunu sanmıyorum, çünkü diğeri sadece yanlış sayma meselesi. Bu, daha küçük terimlerin (özellikle sabit çarpanlar ve düşük dereceli polinomlar) neden göz ardı edildiği hakkında daha ince bir sorudur. Buradaki soru soran, görünüşe göre diğer soruda ortaya çıkan konuyu zaten biliyor ve bu soru için yeterli bir cevap bu cevabı cevaplamayacak.
sdenham

Yanıtlar:


38

Bir algoritmanın Big-O karmaşıklığını hesaplarken, gösterilen şey, algoritmayı çalıştırdığınız öğelerin sayısı arttığında yürütme süresindeki artışa en büyük katkıyı sağlayan faktördür.

Karmaşıklığı olan bir algoritmanız varsa (n^2 + n)/2ve öğe sayısını ikiye katlarsanız, sabit 2yürütme süresindeki artışı etkilemez, terim nyürütme süresinde iki katına neden olur ve terim yürütmede n^2dört kat artışa neden olur saati.
As n^2terimi büyük katkısı olan, Big-O karmaşıklığı olduğunu O(n^2).


2
Bunu beğendim, biraz daha netleşiyor.
Andrew S

7
Bu çok el dalgalı. Doğru olabilir ya da yanlış olabilir. Eğer az miktarda matematik alabiliyorsanız aşağıdaki cevaplardan birine bakınız.
usr

3
Bu akıl yürütme çok belirsiz: Bu O(n * log n) = O(n), doğru olmadığı sonucuna varabileceğimiz anlamına gelir .
cfh

Bu en kesin cevap ya da anlamsal olarak doğru olmayabilir, ama burada önemli olan, beni merkezi noktayı anlamaya başlamamış olması ve bence bu yazarın amacı idi. Ayrıntılar genellikle temel ilkelerden uzaklaşabileceği için kasıtlı olarak belirsizdir. Ağaçlar için ahşabı görmek önemlidir.
Andrew S

Bart gerçekten faktörlerden değil terimlerden bahsediyordu. Bunu anlayarak, bunu sonuçlandıramayız O(n * log n) = O(n). Bence bu, tanımın ardındaki mantığın iyi bir açıklamasını veriyor.
Mark Foskey

10

Tanım şu ki

f(n) = O(g(n))

bazı sabit C> 0 varsa, tüm n için n_0'dan büyükse,

|f(n)| <= C * |g(n)|

Bu, C sabitinin 2 olması gereken f (n) = n ^ 2 ve g (n) = 1/2 n ^ 2 için açıkça doğrudur. F (n) = n ^ için de doğru olduğunu görmek kolaydır. 2 ve g (n) = 1/2 (n ^ 2 + n).


4
"Bazı sabit C> 0 varsa, forr all n" olmalıdır "C, n_0 sabitlerinden çıkarsa, tüm n> n_0 için"
Taemyr

@Taemyr: İşlev gsıfır olmadığı sürece , bu ifadeyi sonlu çok sayıda ilk n_0 değeri için doğru yapmak için C sabitini her zaman artırabileceğiniz için aslında gerekli değildir.
cfh

Hayır, fonksiyonlara baktığımız sürece sınırlı sayıda potansiyel n_0 değeri yoktur.
Taemyr

@Taemyr: n_0 sonlu bir sayıdır. C = max {f (i) / g (i): i = 1, ..., n_0} 'ı seçin ve ardından kolayca kontrol edebileceğiniz için ifade her zaman ilk n_0 değerlerini tutacaktır.
cfh

CS'de bu daha az endişe vericidir, çünkü n genellikle girdi boyutu ve dolayısıyla gizli. Bu durumda n_0 = 1 çalışacak şekilde C seçilebilir. Ancak biçimsel tanım, bazı eşik değerlerden daha büyüktür ve tanımın uygulanmasında bir sürü nitpick'i kaldırır.
Taemyr

6

Karmaşıklık hakkında konuşurken, yalnızca öğe sayısına ( n) dayalı zaman faktörü değişiklikleriyle ilgileniyorsunuz .

Bu nedenle, herhangi bir sabit faktörü kaldırabilirsiniz ( 2burada olduğu gibi ).

Bu seni bırakıyor O(n^2 + n).

Şimdi, makul büyüklükte bir nürün için, yani n * n, sadece önemli ölçüde daha büyük olacak n, bu kısmı da atlamanıza izin vermenizin nedeni, sizi gerçekten son bir karmaşıklıkla bırakıyor O(n^2).

Doğru, küçük sayılar için önemli bir fark olacak, ancak bu daha marjinal nhale gelir.


Farkın marjinal olması için n'nin ne kadar büyük olması gerekir? Ayrıca, / 2 neden kaldırıldı, varlığı değeri yarıya indirdi?
Andrew S

6
@AndrewS Çünkü Büyük O Notasyonu büyüme hakkında konuşuyor. 2'ye bölmek, ölçütler ve zaman damgaları bağlamının dışındadır, çünkü sonuçta büyüme oranını değiştirmez. Bununla birlikte, en büyük bileşen bunu yapar ve böylece tek tuttuğunuz şey budur.
Neil

2
@Niel, parlak çok net. Keşke kitaplar böyle koyarsa. Bazen yazarlar, sadece ölümlülerin işlevsel bilgilerine sahip olmadıklarını ve bu nedenle açık ve önemli noktalara işaret etmediklerini unutduklarını çok fazla bildiklerini, bunun yerine bazı resmi matematiksel açıklamalara gömdüklerini veya ima edildiğine inanarak hepsini atladıklarını düşünüyorum.
Andrew S

Keşke bu cevabı bir kereden fazla iptal edebilsem! @Neil, Big O kitaplarını yazıyor olmalısın.
Tersosauros

3

"(N² + n) / 2 n büyük olduğunda n² gibi davranmaz" değil, n arttıkça (n² + n) / 2 n² gibi büyür .

Örneğin, n 1.000'den 1.000.000'a yükseldikçe

(n² + n) / 2  increases from  500500 to  500000500000
(n²) / 2      increases from  500000 to  500000000000
(n²)          increases from 1000000 to 1000000000000

Benzer şekilde, n 1.000.000'dan 1.000.000.000'a yükseldikçe

(n² + n) / 2  increases from  500000500000 to  500000000500000000
(n²) / 2      increases from  500000000000 to  500000000000000000
(n²)          increases from 1000000000000 to 1000000000000000000

Benzer şekilde büyürler, yani Büyük O Notasyonu budur.

Eğer varsa (n² + n) / 2 ve Wolfram Alpha üzerinde n² / 2 çizmek , onlar ediyoruz zor = 100 n tarafından ayırt etmek o kadar benzerdir. Eğer varsa Wolfram Alpha üzerinde her üç çizmek , sen 2 sabit bir katsayı ile ayrılmış iki satır görüyoruz.


Bu iyi, benim için çok açık. Cevabınız için teşekkürler.
Andrew S

2

Görünüşe göre büyük O gösterimini biraz daha çalıştırmanız gerekiyor. Bu gösterimin ne kadar uygun olduğu, burada işlevlerin eşitliğini göstermek için kullanılmayan eşit bir işaretin kullanılması nedeniyle çok yanıltıcıdır.

Bildiğiniz gibi, bu gösterim fonksiyonların asimptotik bir karşılaştırmasını ifade eder ve f = O (g) yazmak , f (n) ' nin n sonsuza kadar g (n) kadar hızlı büyüdüğü anlamına gelir . Bunu çevirmenin basit bir yolu, f / g işlevinin sınırlı olduğunu söylemektir . Ama elbette, g'nin sıfır olduğu yerlere dikkat etmeliyiz ve neredeyse her yerde okuyabileceğiniz daha sağlam bir tanımla sonuçlanıyoruz .

Bu gösterimler hesaplama için çok uygun görünüyor - bu yüzden çok yaygın - ama orada gördüğümüz eşit işaret işlevlerin eşitliğini göstermediği için dikkatle ele alınmalıdır . Bu hemen hemen söyleyerek gibidir 2 = 5 mod 3 anlamına gelmez 2 = 5 Eğer cebir meraklı iseniz ve, aslında bir eşitlik modülo şey olarak büyük Ç gösterimini anlayabilir.

Şimdi, özel sorunuza geri dönmek için, birkaç sayısal değeri hesaplamak ve karşılaştırmak tamamen işe yaramaz: ne kadar büyük bir milyon olsa da, asimtotik davranışı hesaba katmaz. F (n) = n (n-1) / 2 ve g (n) = n² fonksiyonlarının oranını çizmek daha yararlı olacaktır - ancak bu özel durumda f (n) / g (n) den küçük 1/2 ise 0> n anlamına gelir f = o (g) .

Gösterim konusundaki anlayışınızı geliştirmek için,

  • Benzer bir şeye dayanan bulanık bir izlenim değil, temiz bir tanımla çalışın - sadece deneyimlediğiniz gibi, bulanık bir izlenim iyi çalışmıyor.

  • Örnekleri ayrıntılı olarak incelemek için biraz zaman ayırın. Bir hafta içinde beş örnek kadar az çalışıyorsanız, güveninizi arttırmanız yeterli olacaktır. Bu kesinlikle değecek bir çabadır.


Cebirsel yan not ise bir bütün fonksiyonların cebir Ν → Ν ve sınırlı olan fonksiyonların altcebirine bir fonksiyonu göz önüne alındığında, f ait fonksiyonların grubu O (f) ' a, C arasında -submodule A büyük olduğuna, ve hesaplama kuralları O gösterimi, A'nın bu alt modüllerde nasıl çalıştığını açıklar . Dolayısıyla, gördüğümüz eşitlik C'nin A-alt modüllerinin bir eşitliğidir , bu sadece başka bir tür modüldür.


1
Bu Wikipedia makalesini ilk küçük parçadan sonra takip etmek zordur. Başarılı matematikçiler için başarılı matematikçiler tarafından yazılmıştır ve ansiklopedik bir makaleden bekleyebileceğim giriş metni değildir. Tüm iyi olsa fikir için teşekkürler.
Andrew S

Wikipedia metnindeki seviyeyi abartırsınız! :) Çok iyi yazılmış değil, kesinlikle. Graham, Knuth ve Patashnik, CS'deki öğrenciler için güzel bir “Beton Matematik” kitabı yazdı. “Bilgisayar Programlama Sanatı” nı veya 50'lerde yazılmış bir sayı teorisi kitabını (Hardy ve Wright, Rose) genellikle lise öğrencisi seviyelerini hedef aldıkları için deneyebilirsiniz. Tam bir kitap okumak zorunda değilsiniz, birini seçerseniz, sadece asimptotik kısmı! Ama ne kadar anlamanız gerektiğine karar vermeden önce. :)
Michael Le Barbier Grünewald

1

Bence büyük O gösteriminin ne anlama geldiğini yanlış anlıyorsunuz.

O (N ^ 2) gördüğünüzde bu temel olarak şu anlama gelir: sorun 10 kat daha büyük olduğunda, çözülme süresi şu şekilde olacaktır: 10 ^ 2 = 100 kat daha büyük.

Denkleminizde 1000 ve 10000'i delelim: 1000: (1000 ^ 2 + 1000) / 2 = 500500 10000: (10000 ^ 2 + 10000) / 2 = 50005000

50005000/500500 = 99,91

N, 10 kat daha büyükken, çözümler 100 kat daha büyük oldu. Bu nedenle: O (N ^ 2)


1

n ise 1,000,000daha sonra

(n^2 + n) / 2  =  500000500000  (5.00001E+11)
(n^2) / 2      =  500000000000  (5E+11)
(n^2)          = 1000000000000  (1E+12)

1000000000000.00 nedir?

Karmaşıklık bize gerçek dünya maliyetini tahmin etmenin bir yolunu verirken (zaman karmaşıklığı veya alan karmaşıklığı hakkında konuşup konuşmamaya bağlı olarak saniye veya bayt) bize birkaç saniye veya başka bir belirli birim vermez.

Bize bir dereceye kadar orantı verir.

Bir algoritmanın n² kez bir şey yapması gerekiyorsa, her bir yinelemenin ne kadar sürdüğü c'nin bir değeri için n² × c sürecektir.

Bir algoritmanın n² ÷ 2 kez bir şey yapması gerekiyorsa, her yinelemenin iki katı uzunluğunda bir c değeri için n² × c sürecektir.

Her iki durumda da, geçen zaman n² ile orantılıdır.

Şimdi, bu sabit faktörler görmezden gelebileceğimiz bir şey değildir; gerçekten de O (n²) karmaşıklığına sahip bir algoritmanın O (n) karmaşıklığına sahip bir algoritmadan daha iyi olduğu durumunuz olabilir, çünkü az sayıda öğe üzerinde çalışıyorsak, consant faktörlerinin etkisi daha büyüktür ve diğer endişeleri boğabilir . (Gerçekten de, O (n!) Bile yeterince düşük n değerleri için O (1) ile aynıdır).

Ama karmaşıklığın bize anlattığı şey bunlar değil.

Uygulamada, bir algoritmanın performansını iyileştirmenin birkaç farklı yolu vardır:

  1. Her yinelemenin verimliliğini artırın: O (n²) hala n² × c saniyede çalışır, ancak c daha küçüktür.
  2. Görülen vaka sayısını azaltın: O (n²) hala n² × c saniye içinde çalışır, ancak n daha küçüktür.
  3. Algoritmayı aynı sonuçlara, ancak daha düşük karmaşıklığa sahip bir algoritma ile değiştirin: Örneğin, O (n²) bir şeyi O (n log n) bir şeye repalce edebilirsek ve n² × c₀ saniyeden (n log n) × c₁ saniyeye değiştirebilirsek .

Ya da başka bir şekilde bakmak için f(n)×csaniyeler alıyoruz ve belirli bir verimin getirisini azaltarak c, azaltarak nveya azaltarak performansı artırabilirsiniz .fn

Birincisi, bir döngü içindeki bazı mikro seçimlerle veya daha iyi bir donanım kullanarak yapabiliriz. Her zaman bir gelişme sağlayacaktır.

İkincisi, belki de her şey incelenmeden önce algoritmadan kısa devre yapabileceğimiz veya önemli olmayacak bazı verileri filtreleyebileceğimiz bir durumu belirleyerek yapabiliriz. Bunu yapmanın maliyeti kazançtan ağır basarsa bir iyileşme sağlamaz, ancak genellikle ilk durumdan daha büyük bir gelişme olacaktır, özellikle de büyük bir n ile.

Üçüncüsü, tamamen farklı bir algoritma kullanarak yapabiliriz. Klasik bir örnek, bir kabarcık türünü bir çabuk sıralama ile değiştirmek olabilir. Düşük sayıda element ile işleri daha da kötüleştirebiliriz (c₁ c₀'den büyükse), ancak genellikle en büyük kazancı sağlar, özellikle çok büyük n.

Pratik kullanımda, karmaşıklık ölçütleri algoritmalar arasındaki farkları tam olarak sorgulamamıza izin verir, çünkü n veya c'yi azaltmanın nasıl yardımcı olacağı konusunu göz ardı ederler, incelemeye konsantre olurlar. f()


"O (n!), Yeterince düşük n değerleri için O (1) ile aynı" dır. " nYeterince düşük tutulduğunda Big-O önemli değil" diye açıklamanın daha iyi bir yolu olmalı .
Ben Voigt

@BenVoigt Henüz okuduğum zamankiyle aynı retorik etkiye sahip biriyle karşılaşmadım; aslen benim değil, onu üreten veya başka birinden almış olan Eric Lippert'den çaldım. Tabii ki "π, for küçük değerleri için 3 ve daha eski olan 3 büyük değerleri" gibi şakalara atıfta bulunur.
Jon Hanna

0

Sabit faktör

Büyük O gösteriminin amacı, O (fonksiyon (n)) her zaman C * fonksiyonundan (n) daha büyük olacak şekilde keyfi olarak büyük bir sabit faktör seçebilmenizdir. A algoritması B algoritmasından milyar kat daha yavaşsa, n keyfi olarak büyüdüğünde bu fark artmadığı sürece aynı O karmaşıklığına sahiptirler.

Kavramı göstermek için 1000000'lük sabit bir faktör olduğunu varsayalım - gerekli olandan bir milyon kat daha büyük, ancak bu alakasız olarak değerlendirildikleri noktayı gösteriyor.

(n ^ 2 + n) / 2 "," O (n ^ 2) içine sığar, çünkü herhangi bir n için, ne kadar büyük olursa olsun, (n ^ 2 + n) / 2 <1000000 * n ^ 2.

(n ^ 2 + n) / 2 daha küçük bir kümeye uymaz, örneğin O (n) çünkü bazı değerler için (n ^ 2 + n) / 2> 1000000 * n.

Sabit faktörler keyfi olarak büyük olabilir - n yıllık çalışma süresine sahip bir algoritmanın çalışma süresi n * log (n) mikrosaniye olan bir algoritmadan "daha iyi" olan O (n) karmaşıklığı vardır.


0

Big-O, bir algoritmanın "ne kadar karmaşık" olduğuyla ilgilidir. İki algoritmaları var ve biri alırsa n^2*kçalıştırmak için saniye ve diğer alır n^2*jçalıştırmak için saniye, o zaman bir daha iyidir hangi iddia edebilir ve etkilemeye denemek için bazı ilginç optimizasyonlar yapmak mümkün olabilir kveya jancak her ikisi bu algoritmalar, n*mçalıştırmak için kullanılan bir algoritmaya kıyasla çok yavaştır . Sabitleri ne kadar küçük yaptığınız önemli değildir kveya jyeterince büyük bir girdi için n*malgoritma moldukça büyük olsa bile her zaman kazanacaktır .

İlk iki algoritmayı O(n^2), ikinci algoritmayı çağırıyoruz O(n). Dünyayı güzel bir algoritma sınıfına böler . Big-O tamamen bununla ilgilidir. Araçları otomobillere, kamyonlara ve otobüslere vb. Bölmek gibi ... Otomobiller arasında çok fazla varyasyon var ve bir Prius'un Chevy Volt'tan daha iyi olup olmadığını tartışmak için tüm gün geçirebilirsiniz, ancak günün sonunda 12 kişiyi bir araya getirmeniz gerekiyorsa, bu oldukça anlamsız bir tartışma. :)

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.