Mümkün olduğunca az biçimsel tanımlamayı ve basit matematiği tercih ederim.
Mümkün olduğunca az biçimsel tanımlamayı ve basit matematiği tercih ederim.
Yanıtlar:
Hızlı not, bu Büyük O gösterimini (bir üst sınır olan) Theta gösterimi "Θ" (iki taraflı bir sınır) ile karıştırmaktadır. Deneyimlerime göre, bu aslında akademik olmayan ortamlardaki tartışmaların tipik bir örneğidir. Ortaya çıkan karışıklıktan dolayı özür dileriz.
Big O karmaşıklığı bu grafikle görselleştirilebilir:
Big-O notasyonu için verebileceğim en basit tanım şudur:
Big-O notasyonu bir algoritmanın karmaşıklığının göreceli bir temsilidir.
Bu cümlede bazı önemli ve kasıtlı olarak seçilmiş kelimeler vardır:
- göreli: sadece elmaları elmalarla karşılaştırabilirsiniz. Aritmetik çarpma yapmak için bir algoritmayı, tamsayıların bir listesini sıralayan bir algoritma ile karşılaştıramazsınız. Ancak aritmetik işlemler yapmak için iki algoritmanın karşılaştırılması (bir çarpma, bir toplama) size anlamlı bir şey söyleyecektir;
- gösterimi: Big-O (en basit haliyle) algoritmalar arasındaki tek bir değişkenle karşılaştırmayı azaltır. Bu değişken gözlemlere veya varsayımlara göre seçilir. Örneğin, sıralama algoritmaları tipik olarak karşılaştırma işlemlerine dayanarak karşılaştırılır (göreli sıralarını belirlemek için iki düğümü karşılaştırmak). Bu karşılaştırmanın pahalı olduğunu varsayar. Peki ya karşılaştırma ucuz ancak takas pahalıysa? Karşılaştırmayı değiştirir; ve
- karmaşıklık: 10.000 öğeyi sıralamak bir saniyemi alırsa, bir milyon sıralamam ne kadar sürer? Bu durumda karmaşıklık, başka bir şey için göreceli bir önlemdir.
Geri kalanını okuyun ve gerisini okuduğunuzda tekrar okuyun.
Düşünebileceğim en büyük Big-O örneği aritmetik yapmaktır. İki sayı alın (123456 ve 789012). Okulda öğrendiğimiz temel aritmetik işlemler şunlardı:
- ilave;
- çıkarma;
- çarpma işlemi; ve
- bölünme.
Bunların her biri bir işlem veya bir sorundur. Bunları çözme yöntemine algoritma denir .
Ekleme en basit olanıdır. Sayıları yukarı (sağa) sıralar ve sonuçta o eklemenin son sayısını yazarak bir sütuna rakamlar eklersiniz. Bu sayının 'onlarca' kısmı bir sonraki sütuna taşınır.
Bu sayıların eklenmesinin bu algoritmada en pahalı işlem olduğunu varsayalım. Bu iki sayıyı bir araya getirmek için 6 haneyi bir araya getirmemiz (ve muhtemelen bir 7'i taşımamız) nedenidir. Eğer birlikte iki adet 100 haneli sayı eklersek, 100 ekleme yapmak zorundayız. İki adet 10.000 basamaklı sayı eklersek, 10.000 ekleme yapmamız gerekir.
Deseni görüyor musunuz? Karmaşıklığı (işlemlerin sayısını olmak üzere) basamak sayısı ile doğru orantılıdır , n daha çok sayıda. Buna O (n) veya doğrusal karmaşıklık diyoruz .
Çıkarma benzerdir (ancak taşımak yerine ödünç almanız gerekebilir).
Çarpma farklıdır. Sayıları sıralarsınız, en alttaki rakamı ilk basamağa alırsınız ve sırayla en üst rakamdaki her bir rakamla çarparak her basamakta devam edersiniz. Bu yüzden 6 haneli iki sayımızı çarpmak için 36 çarpma yapmalıyız. Son sonucu almak için 10 veya 11 sütun eklememiz gerekebilir.
100 basamaklı iki sayımız varsa, 10.000 çarpma ve 200 ekleme yapmamız gerekir. İki bir milyon basamaklı sayı için bir trilyon (10 12 ) çarpma ve iki milyon ekleme yapmamız gerekir .
Algoritma n kare ile ölçeklendiğinde , bu O (n 2 ) veya kuadratik karmaşıklıktır . Başka bir önemli kavramı tanıtmak için iyi bir zaman:
Biz sadece karmaşıklığın en önemli kısmını önemsiyoruz.
Zeki, operasyon sayısını şu şekilde ifade edebileceğimizi fark etmiş olabilir: n 2 + 2n. Ancak, iki milyon milyon basamaklı örneğimizden gördüğünüz gibi, ikinci terim (2n) önemsiz hale gelir (bu aşamaya göre toplam işlemlerin% 0.0002'sini oluşturur).
Burada en kötü senaryoyu aldığımızı fark edebiliriz. 6 basamaklı sayıları çarparken, bunlardan birinde 4 basamak ve diğerinde 6 basamak varsa, o zaman sadece 24 çarpımımız vardır. Yine de, bu 'n' için en kötü durum senaryosunu hesaplıyoruz, yani her ikisi de 6 haneli sayılar. Bu nedenle Big-O notasyonu bir algoritmanın En Kötü senaryosu ile ilgilidir.
Aklıma gelen en iyi örnek, normalde Beyaz Sayfalar veya benzeri olarak adlandırılan telefon rehberi, ancak ülkeden ülkeye değişiyor. Ama insanları soyadına göre listeleyen ve daha sonra baş harfleri veya ad, muhtemelen adres ve sonra telefon numaralarından bahsedenlerden bahsediyorum.
Şimdi bir bilgisayara 1.000.000 ad içeren bir telefon rehberinde "John Smith" için telefon numarasını aramasını istiyor olsaydınız ne yapardınız? S'nin ne kadar başladığını tahmin edebileceğinizi göz ardı ederek (yapamayacağınızı varsayalım), ne yapardınız?
Tipik bir uygulama 500.000 almak, ortada açılmaya olabilir inci ve "Smith" ile karşılaştırın. "Smith, John" olursa, gerçekten şanslıyız. Çok daha büyük olasılıkla, "John Smith" bu addan önce veya sonra olacaktır. Eğer öyleyse, telefon rehberinin son yarısını ikiye böleriz ve tekrar ederiz. Daha önce ise, telefon rehberinin ilk yarısını ikiye böleriz ve tekrarlarız. Ve bunun gibi.
Buna ikili arama denir ve bunu fark edip etmediğinizi programlamak için her gün kullanılır.
Yani milyonlarca isimden oluşan bir telefon rehberinde bir isim bulmak istiyorsanız, bunu en fazla 20 kez yaparak herhangi bir isim bulabilirsiniz. Arama algoritmalarını karşılaştırırken bu karşılaştırmanın 'n' olduğuna karar veriyoruz.
- 3 isimden oluşan bir telefon rehberi için 2 karşılaştırma yapılır (en fazla).
- 7 için en fazla 3 alır.
- 15 kişi için 4 alır.
- ...
- 1.000.000 için 20 alır.
Şaşırtıcı derecede iyi, değil mi?
Big-O terimleriyle bu, O (log n) veya logaritmik karmaşıklıktır . Şimdi söz konusu logaritma ln (taban e), log 10 , log 2 veya başka bir baz olabilir. Hala O (log n ) ve O ( 2n 2 ) ve O (100n 2 ) hala O (n 2 ) olduğu önemli değil.
Bu noktada Big O'nun algoritmalı üç vakayı belirlemek için kullanılabileceğini açıklamakta fayda var:
- En İyi Durum: Telefon rehberi aramasında en iyi durum, adı bir karşılaştırmada bulmamızdır. Bu O (1) veya sabit karmaşıklıktır ;
- Beklenen Durum: Yukarıda tartışıldığı gibi bu O (log n); ve
- En Kötü Durum: Bu aynı zamanda O (log n).
Normalde en iyi durumu umursamıyoruz. Beklenen ve en kötü durumla ilgileniyoruz. Bazen bunlardan biri veya diğeri daha önemli olabilir.
Telefon rehberine geri dön.
Telefon numaranız varsa ve bir isim bulmak istiyorsanız ne olur? Polisin ters telefon rehberi var, ancak bu tür aramalar kamuoyuna reddediliyor. Yoksa öyle mi? Teknik olarak, sıradan bir telefon rehberindeki bir numarayı geriye doğru arayabilirsiniz. Nasıl?
İlk addan başlar ve sayıyı karşılaştırırsınız. Eğer bu bir maçsa, harika, değilse, bir sonrakine geçersiniz. Telefon rehberi olduğu için bu şekilde yapmak zorunda sırasız (telefon numarası oldu Neyse yoluyla).
Telefon numarası verilen bir adı bulmak için (geriye doğru arama):
- En İyi Durum: O (1);
- Beklenen Durum: O (n) (500.000 için); ve
- En Kötü Durum: O (n) (1.000.000 için).
Bu bilgisayar biliminde oldukça ünlü bir sorundur ve bir sözü hak etmektedir. Bu problemde N kasabanız var. Bu kasabaların her biri belirli bir mesafedeki bir yolla 1 veya daha fazla kasabaya bağlıdır. Gezgin Satıcı sorunu, her şehri ziyaret eden en kısa turu bulmaktır.
Kulağa basit mi geliyor? Tekrar düşün.
Tüm çiftler arasında yollar bulunan 3 A, B ve C kasabanız varsa o zaman gidebilirsiniz:
- A → B → C
- A → C → B
- B → C → A
- B → A → C
- C → A → B
- C → B → A
Aslında bundan daha azı var, çünkü bunlardan bazıları eşdeğerdir (A → B → C ve C → B → A eşdeğerdir, çünkü aynı yolları tam tersi kullandıkları için).
Gerçekte, 3 olasılık vardır.
- Bunu 4 kasabaya götürün ve 12 olasılıkınız var.
- 5 ile 60.
- 6, 360 olur.
Bu, faktöriyel adı verilen matematiksel bir işlemin bir fonksiyonudur . Temelde:
- 5! = 5 × 4 × 3 × 2 × 1 = 120
- 6! = 6 × 5 × 4 × 3 × 2 × 1 = 720
- 7! = 7 × 6 × 5 × 4 × 3 × 2 × 1 = 5040
- ...
- 25! = 25 × 24 ×… × 2 × 1 = 15,511,210,043,330,985,984,000,000
- ...
- 50! = 50 × 49 ×… × 2 × 1 = 3.04140932 × 10 64
Gezgin Satıcı probleminin Big-O'su O (n!) Veya faktöriyel veya kombinatoryal karmaşıklıktır .
200 kasabaya ulaştığınızda, evrendeki sorunu geleneksel bilgisayarlarla çözmek için yeterli zaman kalmıyor.
Düşünmek için bir şey.
Ben hızlı bir bahsetmek istediğim bir başka nokta bir karmaşıklığı olan herhangi algoritma olmasıdır O (n bir ) olduğu söylenir polinom karmaşıklığını veya çözülebilir olduğu polinom zamanda .
O (n), O (n 2 ) vb. Hepsi polinom zamanıdır. Bazı problemler polinom zamanında çözülemez. Bu nedenle dünyada bazı şeyler kullanılır. Açık Anahtarlı Kriptografi bunun en iyi örneğidir. Çok büyük bir sayının iki ana faktörünü bulmak hesaplama açısından zordur. Değilse, kullandığımız ortak anahtar sistemlerini kullanamazdık.
Her neyse, Big O'nun (umarım düz İngilizce) açıklamam için bu kadar.
Bir algoritmanın giriş boyutuna göre nasıl ölçeklendiğini gösterir.
O (n 2 ) : İkinci dereceden karmaşıklık olarak bilinir
Maddelerin sayısının 10 kat arttığına, ancak sürenin 10 2 kat arttığına dikkat edin . Temel olarak, n = 10 ve O, böylece (n 2 ) bize ölçeklendirme faktörü N verir 2 10 2 .
O (n) : Doğrusal karmaşıklık olarak bilinir
Bu kez öğe sayısı 10 kat artar ve zaman da artar. n = 10 ve dolayısıyla O (n) 'nin ölçeklendirme faktörü 10'dur.
O (1) : Sabit karmaşıklık olarak bilinir
Maddelerin sayısı hala 10 kat artmaktadır, ancak O (1) 'in ölçeklendirme faktörü her zaman 1'dir.
O (log n) : Logaritmik karmaşıklık olarak bilinir
Hesaplama sayısı yalnızca giriş değerinin bir kaydı ile arttırılır. Bu durumda, her bir hesaplamanın 1 saniye sürdüğü varsayılarak, girdinin günlüğü n
gereken süredir, dolayısıyla log n
.
Bunun özü bu. Matematiği azaltırlar, böylece tam olarak n 2 ya da söyledikleri her şey olmayabilir , ancak bu ölçeklemenin baskın faktörü olacaktır.
Big-O notasyonu ("asimptotik büyüme" notasyonu olarak da adlandırılır), başlangıç noktasında sabit faktörleri ve şeyleri göz ardı ettiğinizde işlevlerin "nasıl" göründüğüdür . Bunu, şeyin nasıl ölçeklendiği hakkında konuşmak için kullanırız .
temeller
"yeterince" büyük girdiler için ...
f(x) ∈ O(upperbound)
f
"daha hızlı büyümez" anlamına gelirupperbound
f(x) ∈ Ɵ(justlikethis)
f
"aynen büyür" demekjustlikethis
f(x) ∈ Ω(lowerbound)
f
"daha yavaş büyümez" anlamına gelirlowerbound
big-O notasyonu sabit faktörleri umursamaz: fonksiyonun 9x²
"aynen büyümek" olduğu söylenir 10x²
. Big-O asimptotik notasyon da asimptotik olmayan şeyleri ("orijinine yakın şeyler" veya "problem boyutu küçük olduğunda ne olur") önemsemez : fonksiyonun 10x²
"tam olarak büyüdüğü" söylenir 10x² - x + 2
.
Neden denklemin küçük kısımlarını görmezden gelmek istersiniz? Çünkü daha büyük ve daha büyük ölçekleri düşündüğünüzde denklemin büyük bölümleri tarafından tamamen cüce olurlar; katkıları cüce ve önemsiz hale gelir. (Örnek bölüme bakın.)
Başka bir deyişle, sonsuza giderken oranla ilgilidir . Gerçek zamanı ile bölerseniz, O(...)
büyük giriş sınırında sabit bir faktör elde edersiniz. Sezgisel olarak bu mantıklı: Birini diğerini elde etmek için çarpabilirseniz, işlevler birbirini "ölçeklendirir". İşte o zaman ...
actualAlgorithmTime(N) ∈ O(bound(N))
e.g. "time to mergesort N elements
is O(N log(N))"
... bu , "yeterince büyük" sorun boyutları N için (başlangıç noktasına yakın şeyleri görmezden gelirsek), bazı sabitler (örneğin 2.5, tamamen oluşturulmuş) olduğu anlamına gelir:
actualAlgorithmTime(N) e.g. "mergesort_duration(N) "
────────────────────── < constant ───────────────────── < 2.5
bound(N) N log(N)
Sabit birçok seçenek var; genellikle "en iyi" seçim algoritmanın "sabit faktörü" olarak bilinir ... ancak çoğunlukla en büyük olmayan terimleri görmezden gelir gibi yok sayarız (neden genellikle önemli olmadıklarına dair Sabit Faktörler bölümüne bakın). Ayrıca "diyerek bağlı olarak yukarıdaki denklemin düşünebiliriz , geçen süre kabaca daha kötü olamaz kötü durum senaryosunda N*log(N)
(sabit faktörü biz çok umurumda değil) 2.5 kat içinde, " .
Genel O(...)
olarak, en faydalı olanıdır, çünkü genellikle en kötü durum davranışını önemsiyoruz. f(x)
İşlemci veya bellek kullanımı gibi "kötü" bir şeyi temsil ediyorsa , " f(x) ∈ O(upperbound)
" " upperbound
işlemci / bellek kullanımının en kötü senaryosu demektir" anlamına gelir .
Uygulamalar
Tamamen matematiksel bir yapı olarak, big-O notasyonu işlem süresi ve hafızasından bahsetmekle sınırlı değildir. Ölçeklemenin anlamlı olduğu her şeyin asimptotiklerini tartışmak için kullanabilirsiniz, örneğin:
N
bir partideki insanlar arasındaki olası el sıkışmalarının sayısı ( Ɵ(N²)
özellikle N(N-1)/2
, ama önemli olan "ölçeklendirilmesi" N²
)Misal
Yukarıdaki el sıkışma örneği için, bir odadaki herkes herkesin elini sıkar. Bu örnekte #handshakes ∈ Ɵ(N²)
,. Neden?
Biraz yedekleyin: tokalaşma sayısı tam olarak n-select-2'dir veya N*(N-1)/2
(N kişisinin her biri diğer N-1'lerin ellerini sallar, ancak bu çift sayılan tokalaşma sayısı 2'ye bölünür):
Bununla birlikte, çok sayıda insan için, doğrusal terim N
gölgede bırakılır ve orana etkili bir şekilde 0 katkıda bulunur (grafikte: diyagonal üzerindeki boş kutuların toplam kutulara oranı azaldıkça, katılımcı sayısı arttıkça). Bu nedenle ölçekleme davranışı order N²
ya da el sıkışmalarının sayısı "N² gibi büyür".
#handshakes(N)
────────────── ≈ 1/2
N²
Grafiğin diyagonalindeki boş kutular (N * (N-1) / 2 onay işaretleri) orada olmasa bile (N 2 onay işaretleri asimptotik olarak).
("sade İngilizce" den geçici kazı) :) Bunu kendinize kanıtlamak isterseniz, bunu birden çok terime bölmek için basit bir cebir yapabilirsiniz ( lim
"sınırında kabul edilen" anlamına gelir) görmedim, sadece "ve N gerçekten çok büyük" için gösterimi):
N²/2 - N/2 (N²)/2 N/2 1/2
lim ────────── = lim ( ────── - ─── ) = lim ─── = 1/2
N→∞ N² N→∞ N² N² N→∞ 1
┕━━━┙
this is 0 in the limit of N→∞:
graph it, or plug in a really large number for N
tl; dr: tokalaşma 'gibi görünüyor' sayısı x² çok büyük değerleri için, biz olsaydı oran # yazmak için bu el sıkışma / x² ihtiyacımız yok aslında tam olarak x² tokalaşma bile görünmeyen keyfi olarak büyük bir süre için.
örneğin x = 1 milyon, oran # el sıkışma / x²: 0.499999 ...
Yapı Sezgisi
Bu, aşağıdaki gibi açıklamalar yapmamızı sağlar ...
"Yeterince büyük giriş boyutu = N, sabit faktör ne olursa olsun , giriş boyutunu ikiye katlarsam ...
N → (2N) = 2 ( N )
N² → (2N) ² = 4 ( N² )
cN³ → c (2N) ³ = 8 ( cN³ )
c günlüğü (N) → c günlüğü (2N) = (c günlüğü (2)) + ( c günlüğü (N) ) = (sabit miktar) + ( c günlüğü (N) )
c * 1 → c * 1
temelde doğrusal olarak adlandırmaya istekli olabileceğiniz O (N 1.000001 ) değerinden daha az
2 N → 2 2N = (4 N ) ............ başka bir yol koymak ... 2 N → 2 N + 1 = 2 N 2 1 = 2 2 N
[Matematiksel olarak eğimli olanlar için, fareyi küçük sidenotlar için spoiler üzerine getirebilirsiniz]
( https://stackoverflow.com/a/487292/711085 adresine verilen krediyle )
(teknik olarak sabit faktör bazı daha ezoterik örneklerde önemli olabilir, ancak yukarıdaki şeyleri (örneğin log (N) 'de) öyle olmayacak şekilde ifade ettim)
Bunlar, programcıların ve uygulamalı bilgisayar bilimcilerinin referans noktaları olarak kullandığı ekmek ve tereyağı büyüme emirleridir. Bunları her zaman görüyorlar. (Teknik olarak "Girdi'yi ikiye katlamak O ()N) algoritmasını 1.414 kat daha yavaş yapar" düşünürken, bunu "bu logaritmikten daha kötü ama lineerden daha iyi" olarak düşünmek daha iyidir.)
Sabit faktörler
Genellikle, belirli sabit faktörlerin ne olduğu umurumda değildir, çünkü işlevin büyüme şeklini etkilemezler. Örneğin, iki algoritmanın O(N)
tamamlanması zaman alabilir , ancak biri diğerinin iki katı kadar yavaş olabilir. Optimizasyon zor iş olduğu için faktör çok büyük olmadığı sürece genellikle çok fazla umursamıyoruz ( Optimizasyon erken ne zaman? ); ayrıca daha iyi bir big-O ile bir algoritma seçme eylemi genellikle performansı büyüklük sıralarına göre artıracaktır.
Bazı asimptotik olarak üstün algoritmalar (örn. Karşılaştırma olmayan bir O(N log(log(N)))
sıralama), o kadar büyük bir sabit faktöre (ör. 100000*N log(log(N))
) Veya O(N log(log(N)))
bir gizli ile nispeten büyük olan ek yüke sahip olabilirler, + 100*N
"büyük veriler" üzerinde bile nadiren kullanılmaya değerdirler.
Neden O (N) bazen yapabileceğinizin en iyisi, yani neden veri yapılarına ihtiyacımız var?
O(N)
tüm verilerinizi okumanız gerekiyorsa algoritmalar bir anlamda "en iyi" algoritmalardır. Okuma çok hareket verilerinin bir demet bir olduğunu O(N)
çalışma. Belleğe yüklemek genellikle O(N)
(veya donanım desteğiniz varsa daha hızlıdır veya verileri zaten okuduysanız hiç vakit kaybetmez). Bununla birlikte, her veri parçasına (hatta diğer her veri parçasına) dokunur veya hatta bakarsanız , algoritmanız O(N)
bu görünümü gerçekleştirmek için zaman alacaktır . Gerçek algoritmanız ne kadar sürerse sürsün, en azından O(N)
o zaman tüm verilere bakarak harcadığı için olacaktır .
Aynısı yazma eylemi için de söylenebilir . N şeyi basan tüm algoritmalar N zaman alacaktır, çünkü çıktı en azından bu kadar uzundur (örneğin, bir N oyun kartının setinin tüm faktörlerini basmak (yeniden düzenleme yolları) faktöryeldir:) O(N!)
.
Bu, veri yapılarının kullanımını motive eder : bir veri yapısı, verileri yalnızca bir kez (genellikle O(N)
zaman) okumayı ve ayrıca küçük tutmaya çalıştığımız bazı rastgele önişlemleri (örn. O(N)
Veya O(N log(N))
veya O(N²)
) gerektirir. Daha sonra, veri yapısının değiştirilmesi (ekleme / silme / vb.) Ve veriler üzerinde sorgulama yapılması O(1)
veya gibi çok az zaman alır O(log(N))
. Daha sonra çok sayıda sorgu yapmaya devam edin! Genel olarak, vaktinden önce ne kadar çok iş yapmaya istekli olursanız, daha sonra daha az iş yapmanız gerekir.
Örneğin, milyonlarca yol segmentinin enlem ve boylam koordinatlarına sahip olduğunuzu ve tüm sokak kavşaklarını bulmak istediğinizi varsayalım.
O(N)
çalışma yöntemini sadece bir kez yapmak zorunda kalmazsınız, ancak bunu birçok kez yapmak istiyorsanız (bu durumda, N
her segment için bir kez), biz O(N²)
iş yapmak zorundayım , ya da 1000000² = 1000000000000 işlemleri. İyi değil (modern bir bilgisayar saniyede yaklaşık bir milyar işlem yapabilir).O(N)
zamanında işleyerek küçük bir maliyet öderiz . Daha sonra, bir şeyi anahtarıyla aramak ortalama olarak sabit bir zaman alır (bu durumda, anahtarımız bir ızgaraya yuvarlanmış enlem ve boylam koordinatlarıdır; sadece 9 olan bitişik ızgara alanlarını araştırıyoruz, sabit).O(N²)
yönetilebilir bir hale geldi O(N)
ve tek yapmamız gereken bir karma tablo yapmak için küçük bir maliyet ödemekti.Hikayenin ahlakı: bir veri yapısı operasyonları hızlandırmamızı sağlar. Dahası, gelişmiş veri yapıları, işlemleri inanılmaz derecede akıllı yollarla birleştirmenize, geciktirmenize ve hatta göz ardı etmenize izin verebilir. Farklı sorunların farklı analojileri olacaktır, ancak hepsi verileri önem verdiğimiz veya yapıyı yapay olarak empoze ettiğimiz bir yapıyı sömürecek şekilde düzenlemeyi içerecektir. Önceden çalışıyoruz (temel olarak planlama ve organize etme) ve şimdi tekrarlanan görevler çok daha kolay!
Pratik örnek: kodlama sırasında büyüme düzenlerini görselleştirmek
Asimtotik gösterim, özünde, programlamadan oldukça ayrıdır. Asimptotik gösterim, şeylerin birçok farklı alanda nasıl ölçeklendiğini ve kullanılabileceğini düşünmek için matematiksel bir çerçevedir. Yani ... kodlamaya asimptotik gösterimi böyle uygularsınız .
Temel bilgiler: A boyutundaki bir koleksiyondaki (dizi, küme, haritanın tüm anahtarları vb.) Her öğeyle etkileşime girdiğimizde veya bir A döngüsünün A yinelemelerini gerçekleştirdiğimizde, bu A boyutunun çarpma faktörüdür Neden "çarpımsal faktör" diyorum? - çünkü döngüler ve fonksiyonlar (neredeyse tanım gereği) çarpımsal çalışma süresine sahiptir: yineleme sayısı, döngüde yapılan çalışma sayısı (veya fonksiyonlar için: işlev, işlevde yapılan çalışma sayısı). (Döngüleri atlamak veya döngüden erken çıkmak veya işlevdeki kontrol akışını çok yaygın olan argümanlara dayalı olarak değiştirmek gibi fantezi bir şey yapmazsak geçerlidir.) İşte eşlik eden sahte kodla birlikte görselleştirme tekniklerine bazı örnekler.
(burada, x
s sabit zamanlı çalışma birimlerini, işlemci talimatlarını, tercüman opcodeslerini, her neyse) temsil eder.
for(i=0; i<A; i++) // A * ...
some O(1) operation // 1
--> A*1 --> O(A) time
visualization:
|<------ A ------->|
1 2 3 4 5 x x ... x
other languages, multiplying orders of growth:
javascript, O(A) time and space
someListOfSizeA.map((x,i) => [x,i])
python, O(rows*cols) time and space
[[r*c for c in range(cols)] for r in range(rows)]
Örnek 2:
for every x in listOfSizeA: // A * (...
some O(1) operation // 1
some O(B) operation // B
for every y in listOfSizeC: // C * (...
some O(1) operation // 1))
--> O(A*(1 + B + C))
O(A*(B+C)) (1 is dwarfed)
visualization:
|<------ A ------->|
1 x x x x x x ... x
2 x x x x x x ... x ^
3 x x x x x x ... x |
4 x x x x x x ... x |
5 x x x x x x ... x B <-- A*B
x x x x x x x ... x |
................... |
x x x x x x x ... x v
x x x x x x x ... x ^
x x x x x x x ... x |
x x x x x x x ... x |
x x x x x x x ... x C <-- A*C
x x x x x x x ... x |
................... |
x x x x x x x ... x v
Örnek 3:
function nSquaredFunction(n) {
total = 0
for i in 1..n: // N *
for j in 1..n: // N *
total += i*k // 1
return total
}
// O(n^2)
function nCubedFunction(a) {
for i in 1..n: // A *
print(nSquaredFunction(a)) // A^2
}
// O(a^3)
Biraz karmaşık bir şey yaparsak, neler olduğunu görsel olarak hayal edebileceksiniz:
for x in range(A):
for y in range(1..x):
simpleOperation(x*y)
x x x x x x x x x x |
x x x x x x x x x |
x x x x x x x x |
x x x x x x x |
x x x x x x |
x x x x x |
x x x x |
x x x |
x x |
x___________________|
Burada, çizebileceğiniz en küçük ana hat önemlidir; bir üçgen iki boyutlu bir şekildir (0.5 A ^ 2), tıpkı bir kare iki boyutlu bir şekildedir (A ^ 2); buradaki ikisinin sabit faktörü, ikisi arasındaki asimptotik oranda kalır, ancak onu tüm faktörler gibi görmezden geliriz ... (Bu tekniğe girmediğim bazı talihsiz nüanslar var; sizi yanlış yönlendirebilir.)
Tabii ki bu döngülerin ve işlevlerin kötü olduğu anlamına gelmez; aksine modern programlama dillerinin yapı taşlarıdır ve biz onları seviyoruz. Ancak, döngüler, fonksiyonlar ve koşullarla birlikte verilerimizin (kontrol akışı, vb.) Dokuma yöntemimizin programımızın zaman ve mekan kullanımını taklit ettiğini görebiliriz! Zaman ve mekan kullanımı bir sorun haline gelirse, büyüme düzenini bir şekilde azaltmak için akıllılığa başvurduğumuz ve düşünmediğimiz kolay bir algoritma veya veri yapısı bulduğumuz zamandır. Bununla birlikte, bu görselleştirme teknikleri (her zaman işe yaramasalar da) size en kötü çalışma zamanında naif bir tahmin verebilir.
İşte görsel olarak tanıyabileceğimiz başka bir şey:
<----------------------------- N ----------------------------->
x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x
x x x x x x x x x x x x x x x x
x x x x x x x x
x x x x
x x
x
Bunu yeniden düzenleyebilir ve bunun O (N) olduğunu görebiliriz:
<----------------------------- N ----------------------------->
x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x
x x x x x x x x x x x x x x x x|x x x x x x x x|x x x x|x x|x
Veya O (N * log (N)) toplam süresi için verilerin log (N) geçişlerini yaparsınız:
<----------------------------- N ----------------------------->
^ x x x x x x x x x x x x x x x x|x x x x x x x x x x x x x x x x
| x x x x x x x x|x x x x x x x x|x x x x x x x x|x x x x x x x x
lgN x x x x|x x x x|x x x x|x x x x|x x x x|x x x x|x x x x|x x x x
| x x|x x|x x|x x|x x|x x|x x|x x|x x|x x|x x|x x|x x|x x|x x|x x
v x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x
İlgisiz ama tekrar bahsetmeye değer: Bir karma (örn. Sözlük / karma arama) yaparsak, bu O (1) faktörüdür. Oldukça hızlı.
[myDictionary.has(x) for x in listOfSizeA]
\----- O(1) ------/
--> A*1 --> O(A)
Biz böyle bir özyinelemeli fonksiyonu ya böl ve fethet algoritması ile olduğu gibi çok karmaşık bir şey, yaparsanız, kullanabileceğiniz Usta Teoremi (genellikle çalışır) veya saçma durumlarda Akra-Bazzi Teoremi (hemen hemen her zaman çalışır) yukarı bakmak Wikipedia'da algoritmanızın çalışma süresi.
Ancak, programcılar böyle düşünmez, çünkü nihayetinde algoritma sezgisi sadece ikinci doğa olur. Verimsiz bir şeyi kodlamaya başlayacaksınız ve hemen "Çok verimsiz bir şey mi yapıyorum ? " Diye düşüneceksiniz . Cevabınız "evet" ise ve bunun gerçekten önemli olduğunu öngörüyorsanız, bir adım geriye gidip işleri daha hızlı yürütmek için çeşitli hileler düşünebilirsiniz (cevap neredeyse her zaman "hashtable kullanın", nadiren "ağaç kullanın", ve çok nadiren biraz daha karmaşık bir şey).
İtfa edilmiş ve ortalama-vaka karmaşıklığı
"İtfa edilmiş" ve / veya "ortalama durum" kavramı da vardır (bunların farklı olduğuna dikkat edin).
Ortalama Durum : Bu, işlevin kendisinden ziyade, bir işlevin beklenen değeri için big-O gösterimini kullanmaktan başka bir şey değildir. Tüm girdilerin eşit derecede olası olduğunu düşündüğünüz olağan durumda, ortalama durum yalnızca çalışma süresinin ortalamasıdır. Örneğin quicksort ile, en kötü durum O(N^2)
bazı gerçekten kötü girdiler için olsa da , ortalama durum olağandır O(N log(N))
(gerçekten kötü girdilerin sayısı çok küçüktür, bu nedenle bunları ortalama durumda fark etmiyoruz).
İtfa Edilen En Kötü Durum : Bazı veri yapılarının en kötü durum karmaşıklığı büyük olabilir, ancak bu işlemlerin çoğunu yaparsanız, yaptığınız ortalama iş miktarının en kötü durumdan daha iyi olacağını garanti eder. Örneğin, normalde sabit O(1)
zaman alan bir veri yapınız olabilir . Bununla birlikte, bazen O(N)
rastgele bir işlem için 'hıçkırır' ve zaman alır , çünkü belki de bazı defter tutma veya çöp toplama veya benzeri bir şey yapması gerekir ... ama hıçkırırsa, N için tekrar hıçkırık olmayacağına söz verir. daha fazla işlem. En kötü durum maliyeti hala O(N)
operasyon başına ama itfa edilmiş maliyet birçok ishal üzerinden olduğunu O(N)/N
=O(1)
işlem başına. Büyük operasyonlar yeterince nadir olduğu için, çok sayıda ara sıra çalışmanın, işin geri kalanıyla sabit bir faktör olarak karıştığı düşünülebilir. İşin, asimptotik olarak kaybolacağı yeterince fazla çağrı üzerinden "itfa edildiğini" söylüyoruz.
İtfa edilmiş analizin analojisi:
Araba sürüyorsun. Bazen, benzin istasyonuna gitmek için 10 dakika harcamanız ve ardından tankı gazla doldurmak için 1 dakika harcamanız gerekir. Bunu arabanızla her yere gittiğinizde (benzin istasyonuna 10 dakika harcayın, bir galonun bir kısmını doldurmak için birkaç saniye harcayın) çok verimsiz olurdu. Ancak, tankı birkaç günde bir doldurursanız, benzin istasyonuna gitmek için harcanan 11 dakika, yeterince fazla sayıda yolculuk sırasında "itfa edilir", görmezden gelebilir ve tüm seyahatlerinizin% 5 daha uzun olduğunu iddia edebilirsiniz.
Ortalama ve itfa edilmiş en kötü durum arasındaki karşılaştırma:
Yine de, bir saldırgan hakkında makul bir endişeniz varsa, amortisman ve ortalama durumun yanı sıra endişelenmeniz gereken birçok algoritmik saldırı vektörü daha vardır.)
Hem ortalama durum hem de amortisman, ölçeklendirme düşünülerek ve tasarlanarak düşünülerek inanılmaz derecede faydalı araçlardır.
( Bu alt konu ile ilgileniyorsanız, ortalama vaka ile itfa edilmiş analiz arasındaki farka bakın.)
Çok boyutlu big-O
Çoğu zaman, insanlar işte birden fazla değişken olduğunu fark etmezler. Örneğin, bir dize arama algoritmasında, algoritmanız zaman alabilir O([length of text] + [length of query])
, yani iki değişkente doğrusaldır O(N+M)
. Diğer daha saf algoritmalar O([length of text]*[length of query])
veya olabilir O(N*M)
. Birden çok değişkeni yok saymak, algoritma analizinde gördüğüm en yaygın gözetimlerden biridir ve bir algoritma tasarlarken size engel olabilir.
Tüm hikaye
Büyük O'nun hikayenin tamamı olmadığını unutmayın. Bazı algoritmaları önbellek kullanarak, önbelleksiz hale getirerek, disk yerine RAM ile çalışarak, paralelleştirme kullanarak veya vaktinden önce çalışarak darboğazlardan kaçınarak önemli ölçüde hızlandırabilirsiniz - bu teknikler genellikle büyüme sırasından bağımsızdır "big-O" notasyonu, buna rağmen paralel algoritmaların big-O notasyonundaki çekirdeklerin sayısını sıkça göreceksiniz.
Ayrıca, programınızın gizli kısıtlamaları nedeniyle, asimtotik davranışı gerçekten önemsemeyeceğinizi unutmayın. Sınırlı sayıda değerle çalışıyor olabilirsiniz, örneğin:
O(N log(N))
sıralıyorsanız , hızlı hızlı sıralama kullanmak istemezsiniz ; küçük girdilerde iyi performans gösteren ekleme sıralama özelliğini kullanmak istersiniz. Bu durumlar genellikle, sorunu yinelemeli sıralama, hızlı Fourier dönüşümleri veya matris çarpımı gibi daha küçük ve daha küçük alt sorunlara böldüğünüz böl ve fethet algoritmalarında ortaya çıkar.Pratikte, aynı veya benzer asimtotik performansa sahip algoritmalar arasında bile, göreceli değerleri aslında aşağıdakiler gibi başka şeylerle de yönlendirilebilir: diğer performans faktörleri (hızlı sıralama ve birleştirme her ikisi de O(N log(N))
, ancak hızlı sıralama CPU önbelleklerinden yararlanır); uygulama kolaylığı gibi performans dışı hususlar; bir kütüphanenin mevcut olup olmadığı ve kütüphanenin ne kadar saygın ve sürdürüldüğü.
Programlar ayrıca 500MHz bilgisayarda 2GHz bilgisayara karşı daha yavaş çalışacaktır. Bunu gerçekten kaynak sınırlarının bir parçası olarak görmüyoruz, çünkü ölçeklendirmeyi gerçek saniyede değil, makine kaynakları (örneğin saat döngüsü başına) açısından düşünüyoruz. Ancak, öykünme altında çalışıp çalışmadığınız veya derleyicinin kodu optimize edip etmediği gibi performansı 'gizlice' etkileyebilecek benzer şeyler vardır. Bunlar bazı temel işlemlerin daha uzun sürmesini (hatta göreceli olarak), hatta bazı işlemleri asemptolojik olarak (hatta göreceli olarak) hızlandırmasını veya yavaşlatmasını sağlayabilir. Etki, farklı uygulama ve / veya çevre arasında küçük veya büyük olabilir. Bu ekstra işi yapmak için dilleri veya makineleri değiştiriyor musunuz? Bu yüzlerce başka nedene bağlıdır (gereklilik, beceriler, iş arkadaşları, programcı verimliliği,
Yukarıdaki konular, hangi programlama dilinin kullanıldığı seçiminin etkisi gibi, neredeyse hiçbir zaman sabit faktörün bir parçası olarak kabul edilmez (ne de olmamalıdır); yine de bunlardan haberdar olunmalıdır çünkü bazen (nadiren de olsa) bazı şeyleri etkileyebilirler. Örneğin, cpython'da, yerel öncelik kuyruğu uygulaması asimptotik olarak optimal değildir ( ekleme veya bulma-dk seçiminiz O(log(N))
yerine O(1)
); başka bir uygulama kullanıyor musunuz? Muhtemelen hayır, çünkü C uygulaması muhtemelen daha hızlıdır ve muhtemelen başka yerlerde benzer sorunlar vardır. Ödünleşmeler var; bazen önemli, bazen de önemli değil.
( değiştir : "Açık İngilizce" açıklaması burada sona eriyor.)
Matematik eklentisi
Tamlık için, big-O notasyonunun kesin tanımı şöyledir: f(x) ∈ O(g(x))
"f, const * g ile asimptotik olarak üst sınırdadır" anlamına gelir: x'in sonlu değerinin altındaki her şeyi göz ardı ederek, böyle bir sabit vardır |f(x)| ≤ const * |g(x)|
. (: Gibi diğer semboller aşağıda sunulmuştur O
vasıtasıyla ≤, Ω
.: Araçları ≥ küçük varyantları bulunmaktadır o
aracı <, ve ω
araçlar.>) f(x) ∈ Ɵ(g(x))
Araçları hem f(x) ∈ O(g(x))
ve f(x) ∈ Ω(g(x))
(üst ve g-sınırlanmış alt): m bazı sabitler örneğin vardır her zaman const1*g(x)
ve arasındaki "bant" içinde yatar const2*g(x)
. Yapabileceğiniz en güçlü asimtotik ifadedir ve kabaca eşdeğerdir.==
. (Maalesef, netlik uğruna, mutlak değer sembollerinden bahsetmeyi şimdiye kadar ertelemeyi seçtim; özellikle de hiçbir zaman bilgisayar bilimi bağlamında negatif değerler görmediğim için.)
İnsanlar genellikle = O(...)
daha doğru 'comp-sci' gösterimidir ve kullanımı tamamen meşrudur; "f = O (...)" okunur "f düzendir ... / f xxx ile sınırlıdır ..." ve "f, asimptotikleri ... olan bir ifadedir." Bana daha titiz kullanmam öğretildi ∈ O(...)
. ∈
"bir öğedir" anlamına gelir (hala eskisi gibi okunur). Bu özel durumda, O(N²)
{gibi öğeleri içerir 2 N²
, 3 N²
, 1/2 N²
, 2 N² + log(N)
, - N² + N^1.9
, ...} ve sonsuz büyük, ama yine de bir dizi bu.
O ve Ω simetrik değildir (n = O (n²), ancak n² O (n) değildir), ancak Ɵ simetriktir ve (bu ilişkilerin tümü geçişli ve dönüşlü olduğu için) Ɵ, bu nedenle simetrik ve geçişli ve refleksiftir ve bu nedenle tüm fonksiyonların setini denklik sınıflarına ayırır . Eşdeğerlik sınıfı, aynı olduğunu düşündüğümüz bir grup şeydir. Yani, aklınıza gelebilecek herhangi bir fonksiyon göz önüne alındığında, sınıfın kanonik / benzersiz bir 'asimtotik temsilcisi' bulabilirsiniz (genellikle sınırı alarak ... sanırım ); tıpkı tüm tam sayıları olasılıklar veya eşitler olarak gruplayabileceğiniz gibi, tüm işlevleri Ɵ ile x-ish, log (x) ^ 2-ish, vb. olarak gruplayabilirsiniz ... temelde daha küçük terimleri görmezden gelebilirsiniz (ancak bazen sıkışmış olabilirsiniz) kendilerine ayrı sınıflar olan daha karmaşık işlevler).
=
Notasyonu daha yaygın biri olabilir ve hatta dünyaca ünlü bilgisayar bilim adamları tarafından kağıtlar kullanılır. Ek olarak, sıradan bir ortamda insanların ne O(...)
zaman kastedildikleri söylenecektir Ɵ(...)
; bu teknik olarak doğrudur, çünkü şeyler Ɵ(exactlyThis)
kümesi bir alt kümedir O(noGreaterThanThis)
... ve yazmak daha kolaydır. ;-)
DÜZENLEME: Hızlı not, bu büyük olasılıkla Büyük O gösterimini (üst sınır olan) Theta notasyonuyla (hem üst hem de alt sınır) karıştırmaktadır. Deneyimlerime göre bu aslında akademik olmayan ortamlardaki tartışmaların tipik bir örneğidir. Ortaya çıkan karışıklıktan dolayı özür dileriz.
Bir cümleyle: İşinizin büyüklüğü arttıkça, işi tamamlamak ne kadar sürer?
Açıkçası bu sadece girdi olarak "boyut" ve çıktı olarak "alınan zaman" kullanmaktadır - bellek kullanımı hakkında konuşmak istiyorsanız aynı fikir geçerlidir.
Burada kurutmak istediğimiz N tişörtlerimiz var. Biz edeceğiz varsayalım (yani insan etkileşimi önemsiz) o kuruma pozisyonunda onları almak için inanılmaz derecede hızlı. Gerçek hayatta durum böyle değil elbette ...
Dışarıda bir yıkama hattı kullanmak: sonsuz büyüklükte bir arka bahçeye sahip olduğunuzu varsayarsak, yıkama O (1) sürede kurur. Ne kadar çok olursanız olun, aynı güneş ve temiz hava elde edilir, bu nedenle boyut kuruma süresini etkilemez.
Çamaşır kurutma makinesi kullanma: Her yüke 10 gömlek koyarsınız ve bir saat sonra yapılır. (Buradaki gerçek sayıları dikkate almayın - önemsizdirler.) Yani 50 gömlek kurutmak 10 gömlek kurutmanın yaklaşık 5 katını alır .
Her şeyi bir havalandırma dolabına koymak: Her şeyi büyük bir kazığa koyar ve genel sıcaklığın yapmasına izin verirsek, orta gömleklerin kuruması uzun zaman alacaktır. Ayrıntıyı tahmin etmek istemiyorum, ama bunun en azından O (N ^ 2) olduğundan şüpheleniyorum - yıkama yükünü arttırdıkça, kurutma süresi daha hızlı artar.
"Büyük O" gösterimde önemli özelliklerinden biri, tam o gelmez daha hızlı bir boyut için olacak algoritma demek. Bir çift diziye (dize, tamsayı) karşı bir karma (dize anahtarı, tamsayı değeri) alın. Bir dizeye dayalı olarak karma veya anahtardaki bir öğeyi bulmak daha mı hızlı? (yani dizi için, "dize bölümünün verilen anahtarla eşleştiği ilk öğeyi bulun.") Hashtables genellikle amortismana tabi tutulur (ortalama olarak ~ = "") O (1) - bir kez ayarlandıktan sonra, 100.000 tabloda 1000.000 giriş tablosunda olduğu gibi bir giriş bulmak için kullanılır. Bir dizideki bir öğeyi (dizin yerine içeriğe dayalı olarak) bulmak doğrusaldır, yani O (N) - ortalama olarak, girişlerin yarısına bakmanız gerekir.
Bu, aramalar için bir diziden daha hızlı bir hashtable yapar mı? Şart değil. Çok küçük bir giriş koleksiyonunuz varsa, bir dizi daha hızlı olabilir - sadece baktığınızın hash kodunu hesaplamak için gereken zamandaki tüm dizeleri kontrol edebilirsiniz. Ancak veri seti büyüdükçe, hashtable sonunda diziyi yener.
Büyük O, girdiler büyük olduğunda bir fonksiyonun, örneğin bir programın çalışma zamanının büyüme davranışı üzerindeki bir üst limiti tanımlar.
Örnekler:
O (n): Giriş boyutunu iki katına çıkarsam çalışma zamanı iki katına çıkar
O (n 2 ): Giriş boyutu çalışma zamanını dört katına çıkarır
O (log n): Giriş boyutu iki katına çıkarsa, çalışma zamanı bir kat artar
O (2 n ): Giriş boyutu bir artarsa, çalışma zamanı iki katına çıkar
Giriş boyutu genellikle girişi temsil etmek için gereken bit cinsinden alandır.
Büyük O gösterimi en çok programcılar tarafından girdi hesaplamasının boyutunun bir fonksiyonu olarak ifade edilen bir hesaplamanın (algoritmanın) ne kadar sürede tamamlanacağının yaklaşık bir ölçüsü olarak kullanılır.
Big O, girdi sayısı arttıkça iki algoritmanın ne kadar iyi ölçekleneceğini karşılaştırmak için yararlıdır.
Daha kesin olarak Büyük O gösterimi , bir fonksiyonun asimptotik davranışını ifade etmek için kullanılır. Bu, işlevin sonsuza yaklaşırken nasıl davrandığı anlamına gelir.
Çoğu durumda bir algoritmanın "O" değeri aşağıdaki durumlardan birine girer:
Big O, girdi boyutu sonsuza doğru arttıkça bir fonksiyonun büyüme eğrisine anlamlı bir şekilde katkıda bulunmayan faktörleri göz ardı eder. Bu, işleve eklenen veya işlevle çarpılan sabitlerin basitçe yok sayıldığı anlamına gelir.
Big O, "Kodumu çalıştırmak için ne kadar zaman / alan gerekir?"
Sıklıkla O (n), O (n 2 ), O (nlogn) ve benzerlerini görebilirsiniz, tüm bunlar sadece göstermenin yollarıdır; Bir algoritma nasıl değişir?
O (n) Büyük O'nun n olduğu anlamına gelir ve şimdi "n nedir !?" Peki "n" elementlerin miktarıdır. Bir Dizideki Bir Öğeyi aramak istediğiniz görüntüleme. Her bir öğeye ve "Doğru eleman / öğe misiniz?" en kötü durumda, öğe son endekste, yani listede öğeler olduğu kadar çok zaman aldı, yani genel olmak gerekirse, "oh hey, n adil bir miktar değerdir!" diyoruz. .
Böylece "n 2 " nin ne anlama geldiğini anlayabilirsiniz , ancak daha da spesifik olmak gerekirse, sıralama algoritmalarının basit, en basit olduğu düşüncesiyle oynayın; BubbleSort. Bu algoritmanın, her bir öğe için tüm listeye bakması gerekir.
Listem
Buradaki akış:
Bu O n 2'dir, çünkü listedeki tüm öğelere "n" öğe bakmanız gerekir. Her bir öğe için, tüm öğelere bir kez daha bakarsınız, karşılaştırma için bu da "n" dir, bu nedenle her öğe için n * n = n 2 anlamına gelen "n" kez bakarsınız
Umarım istediğin kadar basittir.
Ama unutma, Big O kendini zaman ve mekan olarak ortaya çıkarmanın bir yoludur.
Big O, bir algoritmanın temel ölçeklendirme doğasını tanımlar.
Big O'nun belirli bir algoritma hakkında size söylemediği birçok bilgi var. Kemiğe kesilir ve sadece bir algoritmanın ölçekleme doğası, özellikle bir algoritmanın kaynak kullanımının (düşünme süresi veya bellek) "girdi boyutu" na yanıt olarak nasıl ölçeklendiği hakkında bilgi verir.
Bir buhar motoru ve bir roket arasındaki farkı düşünün. Bunlar sadece aynı şeyin farklı çeşitleri değildir (örneğin, bir Prius motoru ve Lamborghini motoruna karşı), ancak özünde dramatik olarak farklı türde itiş sistemleri vardır. Bir buhar motoru bir oyuncak roketten daha hızlı olabilir, ancak hiçbir buhar pistonu motoru yörüngesel bir fırlatma aracının hızlarına ulaşamaz. Bunun nedeni, bu sistemlerin belirli bir hıza ("girdi boyutu") ulaşmak için gereken yakıt ("kaynak kullanımı") ilişkisine göre farklı ölçeklendirme özelliklerine sahip olmasıdır.
Bu neden bu kadar önemli? Çünkü yazılım, bir trilyona kadar faktörlerle boyut olarak farklılık gösterebilecek problemlerle ilgilenir. Bir an için düşünün. Ay'a gitmek için gereken hız ile insan yürüyüş hızı arasındaki oran 10.000: 1'den azdır ve bu, giriş boyutları yazılımının karşılaşabileceği aralığa kıyasla kesinlikle küçüktür. Yazılım, girdi boyutlarında astronomik bir aralıkla karşılaşabileceğinden, bir algoritmanın Big O karmaşıklığı potansiyeli vardır, temel ölçekleme doğası, herhangi bir uygulama detayını gölgede bırakmadır.
Standart sıralama örneğini ele alalım. Kabarcık sıralama O (n 2 ) iken, birleştirme sıralama O (n log n) 'dir. Diyelim ki iki sıralama uygulamanız var, birleştirme sıralama kullanan kabarcık uygulaması ve birleştirme-sıralama kullanan B uygulaması ve diyelim ki yaklaşık 30 elemanlık giriş boyutları için A uygulaması, sıralamadaki B uygulamasından 1.000 kat daha hızlı. Asla 30'dan fazla elemanı sıralamak zorunda kalmazsanız, bu giriş boyutlarında çok daha hızlı olduğu için A uygulamasını tercih etmeniz gerektiği açıktır. Bununla birlikte, on milyon öğeyi sıralamanız gerekebileceğini fark ederseniz, beklediğiniz şey B uygulamasının, bu durumda, tamamen her algoritmanın ölçekleme şekli nedeniyle, A uygulamasından binlerce kat daha hızlı olmasıdır.
İşte Big-O'nun yaygın çeşitlerini açıklarken kullanacağım sade İngiliz kanadı
Her durumda, listede daha yüksek olan algoritmaları listede daha düşük olanlara tercih edin. Bununla birlikte, daha pahalı bir karmaşıklık sınıfına geçmenin maliyeti önemli ölçüde değişir.
O (1):
Büyüme yok. Sorun ne kadar büyük olursa olsun, aynı zamanda çözebilirsiniz. Bu, yayın menzilinde bulunan insan sayısına bakılmaksızın, belirli bir mesafeden yayın yapmak için aynı miktarda enerji gerektiren yerlerde yayın yapmaya biraz benzer.
O (log n ):
Bu karmaşıklık O (1) ile aynıdır, ancak sadece biraz daha kötüdür. Tüm pratik amaçlar için, bunu çok büyük bir sabit ölçeklendirme olarak düşünebilirsiniz. 1 bin ila 1 milyar maddeyi işlemek arasındaki iş farkı sadece altı faktördür.
O ( n ):
Sorunu çözmenin maliyeti sorunun boyutu ile orantılıdır. Sorununuz iki katına çıkarsa, çözümün maliyeti iki katına çıkar. Çoğu problemin veri girişi, disk okumaları veya ağ trafiği gibi bir şekilde bilgisayara taranması gerektiğinden, bu genellikle uygun bir ölçeklendirme faktörüdür.
O ( n log n ):
Bu karmaşıklık O ( n ) ' ye çok benzer . Tüm pratik amaçlar için, ikisi eşdeğerdir. Bu karmaşıklık seviyesi genellikle ölçeklenebilir olarak kabul edilir. Varsayımları değiştirerek bazı O ( n log n ) algoritmaları O ( n ) algoritmalarına dönüştürülebilir. Örneğin, anahtarların boyutunu sınırlamak O ( n log n ) ' den O ( n )' ye sıralamayı azaltır .
O ( n 2 ):
Bir kare olarak büyür, burada n bir karenin kenarının uzunluğudur. Bu, ağdaki herkesin ağdaki herkesi tanıyabileceği "ağ etkisi" ile aynı büyüme hızıdır. Büyüme pahalıdır. Çoğu ölçeklenebilir çözüm, önemli jimnastik yapmadan bu karmaşıklık düzeyine sahip algoritmaları kullanamaz. Bu genellikle diğer tüm polinom karmaşıklıkları - O ( n k ) için de geçerlidir.
O (2 n ):
Ölçeklenmez. Önemsiz boyutta bir sorunu çözme umudunuz yok. Nelerden kaçınacağını bilmek ve uzmanların O ( n k ) cinsinden yaklaşık algoritmaları bulmak için kullanışlıdır .
Big O, bir algoritmanın girdisinin boyutuna göre ne kadar zaman / alan kullandığının bir ölçüsüdür.
Bir algoritma O (n) ise, zaman / boşluk girdisiyle aynı oranda artacaktır.
Bir algoritma O (n 2 ) ise zaman / boşluk, girdi karesi hızında artar.
ve bunun gibi.
Big O'nun basit İngilizce açıklaması nedir? Mümkün olduğunca az resmi tanım ve basit matematik ile.
Big-O Notasyonu İhtiyacının Basit Bir İngilizce Açıklaması :
Programladığımızda, bir sorunu çözmeye çalışıyoruz. Kodladığımız şeye algoritma denir. Büyük O gösterimi, algoritmalarımızın en kötü durum performansını standart bir şekilde karşılaştırmamızı sağlar. Donanım özellikleri zaman içinde değişiklik gösterir ve donanımdaki geliştirmeler, algoritmaların çalıştırılması için gereken süreyi azaltabilir. Ancak donanımı değiştirmek, algoritmamızın hala aynı olduğu için algoritmamızın zaman içinde daha iyi veya iyileştirilmiş olduğu anlamına gelmez. Bu nedenle, farklı algoritmaları karşılaştırmamıza izin vermek, birinin daha iyi olup olmadığını belirlemek için Big O gösterimini kullanıyoruz.
Büyük O Notasyonunun Ne Olduğuna Dair Basit Bir İngilizce Açıklaması :
Tüm algoritmalar aynı sürede çalışmaz ve girişte n olarak adlandıracağımız öğe sayısına bağlı olarak değişebilir . Buna dayanarak, kötü durum analizini veya çalışma süresinin üst sınırını n gittikçe büyüttüğünü düşünüyoruz. N'nin ne olduğunun farkında olmalıyız , çünkü Büyük O gösterimlerinin çoğu buna referans veriyor.
Yazılım programlarının hızını ölçmek çok zordur ve denediğimizde, cevaplar çok karmaşık olabilir ve istisnalar ve özel durumlar ile doldurulabilir. Bu büyük bir sorundur, çünkü hangisinin "en hızlı" olduğunu bulmak için iki farklı programı birbiriyle karşılaştırmak istediğimizde tüm bu istisnalar ve özel durumlar dikkat dağıtıcı ve yararsızdır.
Tüm bu yararsız karmaşıklığın bir sonucu olarak, insanlar mümkün olan en küçük ve en az karmaşık (matematiksel) ifadeleri kullanarak yazılım programlarının hızını tarif etmeye çalışırlar. Bu ifadeler çok kaba yaklaşımlardır: Her ne kadar biraz şansla, bir yazılım parçasının hızlı mı yoksa yavaş mı olduğunun “özünü” yakalarlar.
Yaklaşımlar oldukları için, ifadede "O" (Big Oh) harfini okuyucuyu kaba bir aşırı basitleştirme yaptığımızı bildirmek için bir kural olarak kullanıyoruz. (Ve kimsenin yanlışlıkla ifadenin herhangi bir şekilde doğru olduğunu düşünmediğinden emin olmak için).
"Oh" kelimesini "veya" yaklaşık "düzeninde" anlam "olarak okursanız, çok fazla yanlış gitmezsiniz. (Bence Büyük-Oh'un seçimi mizah teşebbüsü olabilir).
Bu "Big-Oh" ifadelerinin yapmaya çalıştığı tek şey, yazılımın işlemesi gereken veri miktarını artırdığımız için yazılımın ne kadar yavaşladığını açıklamaktır. İşlenmesi gereken veri miktarını iki katına çıkarırsak, yazılımın çalışmasını bitirmek için iki kat daha uzun sürmesi gerekir mi? On kat daha uzun mu? Uygulamada, karşılaşacağınız ve endişelenmeniz gereken çok sınırlı sayıda büyük-Oh ifadesi vardır:
İyi:
O(1)
Sabit : Girdi ne kadar büyük olursa olsun programın çalışması aynı zaman alır.O(log n)
Logaritmik : Programın çalışma süresi, girdinin boyutunda büyük artışlarla bile sadece yavaşça artar.Kötü:
O(n)
Doğrusal : Programın çalışma süresi, girdinin boyutuyla orantılı olarak artar.O(n^k)
Polinom : - Girişin boyutu arttıkça işlem süresi - polinom fonksiyonu olarak - daha hızlı ve daha hızlı büyür.... ve çirkin:
O(k^n)
Üstel Program çalışma süresi, sorunun boyutundaki ılımlı artışlarla bile çok hızlı bir şekilde artar - yalnızca küçük veri kümelerini üstel algoritmalarla işlemek pratiktir.O(n!)
Faktöriyel Programın çalışma süresi, en küçük ve en önemsiz görünen veri kümelerinden başka bir şey beklemeyi göze alabileceğinizden daha uzun olacaktır.O(n log n)
ki bu iyi sayılır.
Basit bir cevap şöyle olabilir:
Big O, bu algoritma için mümkün olan en kötü zamanı / alanı temsil eder. Algoritma asla bu sınırın üzerinde daha fazla yer / zaman almayacaktır. Büyük O, uç durumda zaman / mekan karmaşıklığını temsil eder.
Tamam, 2 sentim.
Big-O, program tarafından tüketilen kaynağın artış oranı , wrt problem örneği boyutu
Kaynak: Toplam CPU süresi olabilir, maksimum RAM alanı olabilir. Varsayılan olarak CPU zamanı anlamına gelir.
Sorunun "Toplamı bul" olduğunu söyleyin,
int Sum(int*arr,int size){
int sum=0;
while(size-->0)
sum+=arr[size];
return sum;
}
problem-örnek = {5,10,15} ==> problem-örnek-boyut = 3, döngü içi yineleme = 3
problem-örnek = {5,10,15,20,25} ==> problem-örnek-boyutu = 5 döngü içi yineleme = 5
"N" boyutu için program, dizideki "n" yineleme hızında büyüyor. Dolayısıyla Big-O, N, O (n) olarak ifade edilir.
Sorunun "Kombinasyonu Bul" olduğunu söyleyin,
void Combination(int*arr,int size)
{ int outer=size,inner=size;
while(outer -->0) {
inner=size;
while(inner -->0)
cout<<arr[outer]<<"-"<<arr[inner]<<endl;
}
}
problem-örnek = {5,10,15} ==> problem-örnek-boyut = 3, toplam yineleme = 3 * 3 = 9
problem-örnek = {5,10,15,20,25} ==> problem-örnek-boyutu = 5, toplam yineleme = 5 * 5 = 25
"N" boyutunun girilmesi için program, dizideki "n * n" yineleme hızında büyüyor. Bu nedenle büyük O, N 2 O (n olarak ifade 2 )
Büyük O gösterimi, bir algoritmanın üst sınırını boşluk veya çalışma süresi cinsinden tanımlamanın bir yoludur. N, problemdeki elemanların sayısıdır (yani bir dizinin büyüklüğü, bir ağaçtaki düğüm sayısı, vb.) Çalışma zamanını n büyüdükçe tanımlamakla ilgileniyoruz.
Bazı algoritmaların O (f (n)) olduğunu söylediğimizde, bu algoritmanın çalışma süresinin (veya gereken alanın) her zaman bazı sabit zamanlardan f (n) daha düşük olduğunu söylüyoruz.
İkili aramanın O (logn) çalışma süresine sahip olduğunu söylemek, log (n) 'yi her zaman ikili aramanın çalışma süresinden daha büyük olacak şekilde çoğaltabileceğiniz bazı sabit c var olduğunu söylemektir. Bu durumda her zaman sabit bir günlük (n) karşılaştırma faktörüne sahip olursunuz.
Başka bir deyişle, g (n) algoritmanızın çalışma süresi olduğu zaman, g (n) = O (f (n)) olduğunda g (n) <= c * f (n) n> k olduğunda, burada c ve k bazı sabitlerdir.
" Big O'nun basit İngilizce açıklaması nedir? Mümkün olduğunca az resmi tanım ve basit matematik ile. "
Böyle güzel ve basit bir soru en azından bir öğrencinin özel ders sırasında alabileceği gibi eşit derecede kısa bir cevabı hak ediyor gibi görünüyor.
Büyük O gösterimi, bir algoritmanın yalnızca girdi veri miktarı ** açısından ne kadar süre * çalışabileceğini anlatır .
(Harika, içinde * birimi içermeyen zaman anlamında!)
(** insanlar, çünkü önemli olan her zaman daha çok istiyorum , ister canlı bugün veya yarın)
Peki, eğer yapılıyorsa Big O notasyonu hakkında bu kadar harika olan nedir?
Pratik olarak, Büyük O analizidir kadar faydalı ve önemli Büyük O algoritmanın özerinde odağı koyar çünkü kendi karmaşıklığı ve tamamen görmezden sadece bir orantı sabiti benzeri bir JavaScript motoru, bir CPU hızı, Internet bağlantısı ve bir şey Model T kadar gülünç modası geçmiş olan tüm bu şeyler . Big O, performansa yalnızca günümüzde veya gelecekte yaşayan insanlar için eşit derecede önemli olduğu şekilde odaklanır.
Big O notasyonu ayrıca, bilgisayar programcılığının / mühendisliğinin en önemli prensibine doğrudan odaklanır, tüm iyi programcılara düşünmeye ve hayal kurmaya devam etmeleri için ilham veren gerçek: teknolojinin yavaş ilerlemesinin ötesinde sonuçlar elde etmenin tek yolu daha iyi bir icat yapmaktır. algoritması .
Algoritma örneği (Java):
// given a list of integers L, and an integer K
public boolean simple_search(List<Integer> L, Integer K)
{
// for each integer i in list L
for (Integer i : L)
{
// if i is equal to K
if (i == K)
{
return true;
}
}
return false;
}
Algoritma açıklaması:
Bu algoritma bir liste arar, bir öğe öer, bir anahtar arar,
Listedeki her öğeyi yineleyerek, eğer anahtar buysa True döndürür,
Döngü anahtarı bulmadan tamamlandıysa False değerini döndürün.
Big-O notasyonu Karmaşıklığın üst sınırını temsil eder (Zaman, Mekan, ..)
Zaman Karmaşıklığında Big-O'yu bulmak için:
En kötü durumun ne kadar zaman harcadığını (giriş boyutuna göre) hesaplayın:
En Kötü Durum: Anahtar listede yok.
Zaman (En Kötü Durum) = 4n + 1
Zaman: O (4n + 1) = O (n) | Big-O'da sabitler ihmal edilir
O (n) ~ Doğrusal
Best-Case'in karmaşıklığını temsil eden Big-Omega da var:
En İyi Durum: anahtar ilk öğedir.
Zaman (En İyi Durum) = 4
Zaman: Ω (4) = O (1) ~ Anında \ Sabit
C
daha iyi olurdu
Büyük O
f (x) = O ( g (x)) x bir a gittiğinde (örneğin, a = + ∞) şu şekilde bir k fonksiyonu olduğu anlamına gelir :
f (x) = k (x) g (x)
k, a'nın bazı mahallelerinde sınırlıdır (a = + ∞ ise, her x> N, | k (x) | <M) için N ve M sayıları olduğu anlamına gelir .
Başka bir deyişle, düz İngilizce: f (x) = O ( g (x)), x → a, a mahallesinde f'nin g ürününe ayrışması anlamına gelir. ve bazı sınırlı fonksiyonlara .
Küçük o
Bu arada, burada küçük o tanımını karşılaştırmak için.
f (x) = o ( g (x)) x, k fonksiyonunun olduğu bir araca gittiğinde:
f (x) = k (x) g (x)
x, a'ya gittiğinde k (x) 0 olur.
Örnekler
x → 0 olduğunda sin x = O (x).
sin x = O (1) x → + ∞ olduğunda,
x → 0 olduğunda x 2 + x = O (x),
x → + ∞ olduğunda x 2 + x = O (x 2 ),
x → + ∞ olduğunda ln (x) = o (x) = O (x).
Dikkat!Eşittir işareti "=" olan gösterimde "sahte eşitlik" kullanılır: o (g (x)) = O (g (x)) olduğu doğrudur, ancak O (g (x)) = o (g (x)). Benzer şekilde, x → + ∞ olduğunda "ln (x) = o (x) yazmak iyidir, ancak" o (x) = ln (x) "formülü anlamsızdır.
Daha fazla örnek
O (1) = O (n) = O (n 2 , n + → ∞ (ama başka bir yol, eşitlik "sahte")),
N → + ∞ olduğunda O (n) + O (n 2 ) = O (n 2 )
N → + ∞ olduğunda O (O (n 2 )) = O (n 2 )
N → + ∞ olduğunda O (n 2 ) O (n 3 ) = O (n 5 )
İşte Wikipedia makalesi: https://en.wikipedia.org/wiki/Big_O_notation
Büyük O gösterimi, "n" adını vereceğimiz, rastgele sayıda giriş parametresi verildiğinde bir algoritmanın ne kadar hızlı çalışacağını açıklamanın bir yoludur. Farklı makineler farklı hızlarda çalıştığı için bilgisayar biliminde kullanışlıdır ve sadece bir algoritmanın 5 saniye sürdüğünü söylemek size çok şey anlatmaz çünkü 4.5 Ghz sekiz çekirdekli işlemciye sahip bir sistem çalıştırırken, çalışıyor olabilirim algoritmaya bakılmaksızın daha uzun sürebilen 15 yıllık 800 Mhz'lik bir sistem. Dolayısıyla, bir algoritmanın zaman açısından ne kadar hızlı çalıştığını belirtmek yerine, giriş parametresi sayısı veya "n" açısından ne kadar hızlı çalıştığını söylüyoruz. Algoritmaları bu şekilde tarif ederek, bilgisayarın hızını hesaba katmak zorunda kalmadan algoritmaların hızlarını karşılaştırabiliriz.
Konuya daha fazla katkıda bulunduğumdan emin değilim ama yine de paylaşacağımı düşündüm: Bir keresinde buldum bu blog yazısını Big O hakkında bazı oldukça yararlı (ancak temel) açıklamalar ve örnekler :
Örneklerle bu, kaplumbağa kabuğu benzeri kafatasımın temel temellerini almamıza yardımcı oldu, bu yüzden doğru yönde ilerlemenin 10 dakikalık bir okuma olduğunu düşünüyorum.
Büyük O hakkında bilmeniz gereken her şeyi bilmek ister misiniz? Ben de.
Yani büyük O'dan bahsetmek için, içinde sadece bir vuruş olan kelimeler kullanacağım. Kelime başına bir ses. Küçük kelimeler hızlıdır. Bu kelimeleri biliyorsunuz, ben de. Tek bir sesle kelimeleri kullanacağız. Küçükler. Eminim kullanacağımız tüm kelimeleri bileceksiniz!
Şimdi, sen ve ben işten bahsedelim. Çoğu zaman işten hoşlanmam. İşi sever misin? Yaptığınız durum bu olabilir, ama emin değilim.
İşe gitmeyi sevmiyorum. İş yerinde zaman geçirmekten hoşlanmıyorum. Yolum olsaydı, sadece oynamak ve eğlenceli şeyler yapmak isterdim. Benim gibi mi hissediyorsun?
Şimdi zaman zaman işe gitmem gerekiyor. Acı ama gerçek. Yani, işteyken bir kuralım var: Daha az iş yapmaya çalışıyorum. Mümkün olduğu kadar hiçbir işe yakın. Sonra oynamaya gidiyorum!
İşte büyük haber: büyük O iş yapmama yardım edebilir! Büyük O'yu bilirsem daha fazla oynayabilirim. Daha az iş, daha fazla oyun! Bu büyük O'nun bana yardım etmesine yardımcı oluyor.
Şimdi biraz işim var. Bu listeye sahibim: bir, iki, üç, dört, beş, altı. Bu listedeki her şeyi eklemeliyim.
Vay canına, işten nefret ediyorum. Ama ah, bunu yapmak zorundayım. İşte gidiyorum.
Bir artı iki üç… artı üç altı ... ve dört ... bilmiyorum. Kayboldum. Kafamda yapmak benim için çok zor. Bu tür işleri umursamıyorum.
Bu yüzden işi yapmayalım. Sen ve ben sadece ne kadar zor olduğunu düşünelim. Altı sayı eklemek için ne kadar iş yapmam gerekir?
İyi, görelim bakalım. Bir ve iki eklemeli ve sonra üçe eklemeliyim, sonra da dörde eklemeliyim… Sonuçta, altı eklemeyi sayıyorum. Bunu çözmek için altı ekleme yapmam gerekiyor.
Bu matematiğin ne kadar zor olduğunu anlatmak için büyük O geliyor.
Big O diyor ki: Bunu çözmek için altı ekleme yapmalıyız. Bir ek, her şey için bir ila altı. Altı küçük iş parçası ... her iş biti bir ek.
Şimdi onları eklemek için çalışma yapmayacağım. Ama ne kadar zor olacağını biliyorum. Altı ek olurdu.
Oh hayır, şimdi daha çok işim var. Sheesh. Kim böyle şeyler yapar ?!
Şimdi benden bir ila on eklememi istiyorlar! Neden bunu yapayım? Bire altı eklemek istemedim. Bir ila on eklemek… iyi… bu daha da zor olurdu!
Ne kadar zor olurdu? Ne kadar daha fazla iş yapmam gerekir? Daha fazla veya daha az adıma ihtiyacım var mı?
Sanırım on ek yapmalıydım… her şey için bir ila on arasında bir tane. On altıdan fazla. Bir ila on, bir ila altı eklemek için çok daha fazla çalışmalıyım!
Şu anda eklemek istemiyorum. Sadece bu kadar eklemenin ne kadar zor olabileceğini düşünmek istiyorum. Ve umarım, olabildiğince çabuk oynamak.
Bir ila altı eklemek için, bu biraz iş. Ama görüyorsunuz, bir ila on eklemek için, bu daha fazla iş mi?
Big O senin arkadaţýn ve benim. Big O ne kadar iş yapmamız gerektiğini düşünmemize yardımcı olur, böylece plan yapabiliriz. Ve eğer büyük O ile arkadaşsak, o kadar zor olmayan işleri seçmemize yardımcı olabilir!
Şimdi yeni işler yapmalıyız. Oh hayır. Bu işten hiç hoşlanmıyorum.
Yeni iş: bir şeyden n'ye her şeyi ekleyin.
Bekle! N nedir? Bunu özledim mi? Bana n'in ne olduğunu söylemezsen birinden n'ye nasıl ekleyebilirim?
N'nin ne olduğunu bilmiyorum. Bana söylenmedi. Sen? Hayır? Oh iyi. Bu yüzden işi yapamayız. Whew.
Ama şimdi işi yapmayacak olsak da, n'yi bilseydik ne kadar zor olacağını tahmin edebiliriz. N şey eklememiz gerekecek, değil mi? Elbette!
Şimdi burada büyük O geliyor ve bize bu çalışmanın ne kadar zor olduğunu anlatacak. Diyor ki: Her şeyi bire bir, birer birer eklemek O (n). Tüm bunları eklemek için, [n defa eklemem gerektiğini biliyorum.] [1] Bu büyük O! Bize bir tür iş yapmanın ne kadar zor olduğunu anlatıyor.
Bana göre büyük O'yu büyük, yavaş, patron gibi düşünüyorum. İş düşünüyor, ama yapmıyor. "Bu iş hızlı." Diyebilir. Veya "O iş çok yavaş ve zor!" Diyebilir. Ama işi yapmıyor. Sadece işe bakar ve sonra bize ne kadar zaman alabileceğini söyler.
Büyük O'yu çok önemsiyorum. Neden? Çalışmayı sevmiyorum! Kimse çalışmayı sevmez. Bu yüzden hepimiz büyük O'yu seviyoruz! Bize ne kadar hızlı çalışabileceğimizi anlatıyor. İşin ne kadar zor olduğunu düşünmemize yardımcı oluyor.
Ah, daha çok iş. Şimdi işi yapmayalım. Ama adım adım bunu yapmak için bir plan yapalım.
Bize on kartlık bir deste verdiler. Hepsi karışık: yedi, dört, iki, altı… hiç de düz değil. Ve şimdi ... bizim işimiz onları sıralamak.
Ergh. Bu çok iş gibi geliyor!
Bu desteyi nasıl sıralayabiliriz? Bir planım var.
Her kart çiftine, çiftler halinde, desteden, ilkten sonuncuya bakacağım. Bir çiftteki ilk kart büyükse ve bu çiftteki bir sonraki kart küçükse, onları takas ederim. Else, bir sonraki çifte gidiyorum, vb. ... ve yakında güverte bitti.
Deste bittiğinde şunu soruyorum: bu geçişte kartları değiştirdim mi? Eğer öyleyse, hepsini bir kez daha yukarıdan yapmalıyım.
Bir noktada, bir zamanda, takas olmayacak ve bizim güverte türümüz yapılacaktı. Çok fazla iş!
Peki, bu kurallara göre kartları sıralamak için ne kadar iş olurdu?
On kartım var. Ve çoğu zaman - yani, eğer çok fazla şansım yoksa - tüm desteyi on defaya kadar geçmeliyim, destede her seferinde on kart takasla.
Big O, yardım et!
Big O içeri giriyor ve şöyle diyor: n kart destesi için, bu şekilde sıralamak O (N kare) zamanda yapılacaktır.
Neden n kare diyor?
Biliyorsunuz, n kare n kere n. Şimdi anladım: n kart kontrol edildi, desteden n kere olabilir. Bu, her biri n basamaklı iki döngüdür. Bu yapılacak çok iş n kare. Kesinlikle çok iş var!
Şimdi büyük O, O (n kare) çalışmasını alacağını söylediğinde, burun üzerinde n kare eklediği anlamına gelmez. Bazı durumlarda biraz daha az olabilir. Ancak en kötü durumda, güverteyi sıralamak için n kare çalışma adımına yakın olacak.
İşte burada büyük O bizim dostumuzdur.
Big O bunu işaret ediyor: n büyüdükçe, kartları sıraladığımızda, iş sadece eski şeyler eklemek işinden çok daha zor oluyor. Bunu nasıl biliyoruz?
Eğer n gerçekten büyürse, n veya n karesine ne ekleyebileceğimiz umurumda değildir.
Büyük n için, n kare n'den daha büyüktür.
Big O bize bir şeyleri sıralamanın bir şeyleri eklemekten daha zor olduğunu söyler. O (n kare) büyük n için O (n) 'den daha fazladır. Bu şu anlama gelir: Eğer n gerçekten büyürse, n şeyden oluşan karışık bir desteyi sıralamak sadece n karma şey eklemek yerine daha fazla zaman alır ZORUNLU.
Big O işi bizim için çözmez. Big O bize işin ne kadar zor olduğunu anlatıyor.
Bir deste kartım var. Onları sıraladım. Yardım ettin. Teşekkürler.
Kartları sıralamanın daha hızlı bir yolu var mı? Büyük O bize yardım edebilir mi?
Evet, daha hızlı bir yol var! Öğrenmek biraz zaman alıyor, ama işe yarıyor ... ve oldukça hızlı çalışıyor. Siz de deneyebilirsiniz, ancak her adımda zaman ayırın ve yerinizi kaybetmeyin.
Bir desteyi sıralamanın bu yeni yolunda, bir süre önce yaptığımız şekilde kart çiftlerini kontrol etmiyoruz. Bu desteyi sıralamak için yeni kurallarınız:
Bir: Şu anda üzerinde çalıştığımız destenin bir kartını seçiyorum. İsterseniz benim için bir tane seçebilirsiniz. (Bunu ilk yaptığımızda “şu anda üzerinde çalıştığımız destenin bir kısmı” elbette tüm destedir.)
İki: Desteyi seçtiğiniz kartın üzerine sürüyorum. Bu yayılma nedir; nasıl açarım? Başlangıç kartından birer birer aşağı iniyorum ve ekran kartından daha yüksek bir kart arıyorum.
Üç: Bitiş kartından yukarı çıkıyorum ve ekran kartından daha düşük bir kart arıyorum.
Bu iki kartı bulduğumda onları değiştirdim ve takas etmek için daha fazla kart aramaya devam ediyorum. Yani, İkinci adıma geri dönüyorum ve biraz daha seçtiğiniz karta yayıldım.
Bir noktada, bu döngü (İki ila Üç arası) sona erer. Bu aramanın her iki yarısı da splay kartında buluştuğunda sona erer. Sonra, birinci adımda seçtiğiniz kartla desteyi yaydık. Şimdi, başlangıçtaki tüm kartlar ekran kartından daha düşük; ve sondaki kartlar davan kartından daha yüksektir. Güzel numara!
Dört (ve bu eğlenceli kısım): Şu anda iki küçük desteğim var, bir splay kartından daha düşük ve bir daha yüksek. Şimdi her küçük güvertede birinci adıma geçiyorum! Yani ilk küçük güvertedeki birinci adımdan başlıyorum ve bu iş bittiğinde, sonraki küçük destedeki birinci adımdan başlıyorum.
Desteyi parçalara ayırıyorum ve her parçayı daha küçük ve daha küçük olarak sıralıyorum ve bir zamanda yapacak başka işim yok. Şimdi bu tüm kurallarla yavaş görünebilir. Ama güven bana, hiç de yavaş değil. Bir şeyleri sıralamanın ilk yolundan çok daha az iş!
Bu türün adı ne? Buna Hızlı Sıralama denir! Bu tür CAR Hoare adlı bir adam tarafından yapıldı ve ona Hızlı Sıralama adını verdi. Şimdi, Hızlı Sıralama her zaman kullanılır!
Hızlı Sıralama küçük olanlarda büyük desteler ayırır. Yani küçük işlerde büyük görevler üstlenir.
Hmmm. Orada bir kural olabilir diye düşünüyorum. Büyük görevleri küçük yapmak için onları parçalayın.
Bu tür oldukça hızlı. Ne kadar hızlı? Big O bize şunu söyler: bu tür bir ortalamada O (n log n) işinin yapılması gerekir.
İlk sıradan daha mı yoksa daha hızlı mı? Big O, lütfen yardım et!
İlk sıralama O (n kare) idi. Ancak Hızlı Sıralama O (n log n) şeklindedir. N log n'nin n kareden küçük olduğunu biliyorsunuz, büyük n için, değil mi? Hızlı Sıralamanın hızlı olduğunu bu şekilde biliyoruz!
Bir güverteyi sıralamak zorundaysanız, en iyi yol nedir? İstediğinizi yapabilirsiniz, ancak Hızlı Sıralama'yı seçerim.
Neden Hızlı Sıralama'yı seçiyorum? Tabii ki çalışmayı sevmiyorum! İşi en kısa sürede halledebilirim.
Hızlı Sıralama'nın daha az iş olduğunu nasıl anlarım? O (n log n) 'in O (n kare)' den daha az olduğunu biliyorum. O'lar daha küçüktür, bu yüzden Hızlı Sıralama daha az iş demektir!
Artık arkadaşımı biliyorsun, Büyük O. Daha az iş yapmamıza yardım ediyor. Ve eğer büyük O biliyorsanız, daha az iş yapabilirsiniz!
Bunları benimle öğrendin! Sen çok akıllısın! Çok teşekkür ederim!
Şimdi bu iş bitti, hadi oynayalım!
[1]: Bir şeyi n'den bir kerede hile yapmanın ve eklemenin bir yolu var. Gauss adında bir çocuk sekiz yaşındayken bunu öğrendi. Ben o kadar akıllı değilim, yani bana nasıl yaptığını sorma .
Zaman karmaşıklığını hesaplamak için en yaygın metriğinin Büyük O gösterimi olduğunu anlamak için zaman karmaşıklığını daha basit bir şekilde anladım. Bu tüm sabit faktörleri ortadan kaldırır, böylece N sonsuza yaklaştıkça çalışma süresi N'ye göre tahmin edilebilir. Genel olarak şöyle düşünebilirsiniz:
statement;
Sabittir. İfadenin çalışma süresi N'ye göre değişmez
for ( i = 0; i < N; i++ )
statement;
Doğrusaldır. Döngünün çalışma süresi N ile doğru orantılıdır. N iki katına çıktığında çalışma süresi de aynıdır.
for ( i = 0; i < N; i++ )
{
for ( j = 0; j < N; j++ )
statement;
}
İkinci dereceden. İki döngünün çalışma süresi N karesiyle orantılıdır. N iki katına çıktığında çalışma süresi N * N artar.
while ( low <= high )
{
mid = ( low + high ) / 2;
if ( target < list[mid] )
high = mid - 1;
else if ( target > list[mid] )
low = mid + 1;
else break;
}
Logaritmiktir. Algoritmanın çalışma süresi, N'nin 2'ye bölünme sayısı ile orantılıdır. Bunun nedeni, algoritmanın çalışma alanını her bir yinelemeyle ikiye bölmesidir.
void quicksort ( int list[], int left, int right )
{
int pivot = partition ( list, left, right );
quicksort ( list, left, pivot - 1 );
quicksort ( list, pivot + 1, right );
}
N * günlüğü (N). Çalışma süresi logaritmik olan N döngülerinden (yinelemeli veya özyinelemeli) oluşur, bu nedenle algoritma doğrusal ve logaritmik bir kombinasyonudur.
Genel olarak, bir boyuttaki her öğeyle bir şey yapmak doğrusaldır, iki boyutta her öğeyle bir şey yapmak ikinci derecelidir ve çalışma alanını ikiye bölmek logaritmiktir. Kübik, üstel ve karekök gibi başka Big O önlemleri de vardır, ancak bunlar neredeyse yaygın değildir. Büyük O gösterimi, ölçümün bulunduğu O () olarak tanımlanır. Hızlı sıralama algoritması O (N * log (N)) olarak tarif edilecektir.
Not: Bunların hiçbiri en iyi, ortalama ve en kötü durum önlemlerini dikkate almamıştır. Her birinin kendi Büyük O gösterimi olurdu. Ayrıca bunun ÇOK basit bir açıklama olduğunu unutmayın. Big O en yaygın olanıdır, ancak aynı zamanda gösterdiğimden daha karmaşık. Büyük omega, küçük o ve büyük teta gibi başka notasyonlar da vardır. Muhtemelen onlarla bir algoritma analizi kursu dışında karşılaşmayacaksınız.
Diyelim ki Harry Potter: 8 Film Koleksiyonunu [Blu-ray] Amazon'dan sipariş edin ve aynı film koleksiyonunu aynı anda çevrimiçi indirin. Hangi yöntemin daha hızlı olduğunu test etmek istiyorsunuz. Teslimatın ulaşması neredeyse bir gün sürer ve indirme işlemi yaklaşık 30 dakika önce tamamlanır. Harika! Yani sıkı bir yarış.
Yüzüklerin Efendisi, Alacakaranlık, Kara Şövalye Üçlemesi gibi birkaç Blu-ray filmi sipariş edersem ve tüm filmleri aynı anda çevrimiçi indirirsem ne olur? Bu kez, teslimatın tamamlanması bir gün sürüyor, ancak çevrimiçi indirme işleminin tamamlanması 3 gün sürüyor. Çevrimiçi alışveriş için, satın alınan ürün (giriş) sayısı teslimat süresini etkilemez. Çıktı sabittir. Buna O (1) diyoruz .
Çevrimiçi indirme için, indirme süresi film dosyası boyutları (giriş) ile doğru orantılıdır. Biz buna O (n) diyoruz .
Deneylerden, çevrimiçi alışverişin çevrimiçi indirmeden daha iyi ölçeklendiğini biliyoruz. Büyük O gösterimini anlamak çok önemlidir, çünkü algoritmaların ölçeklenebilirliğini ve verimliliğini analiz etmenize yardımcı olur .
Not: Büyük O gösterimi , bir algoritmanın en kötü senaryosunu temsil eder . Diyelim ki O (1) ve O (n) yukarıdaki örneğin en kötü senaryolarıdır.
Referans : http://carlcheo.com/compsci
Varsayalım ki , n büyüklüğünde bir veri kümesiyle bir şeyler yapması gereken A algoritmasından bahsediyoruz .
O zaman O( <some expression X involving n> )
basit İngilizce anlamına gelir:
A yürütülürken şanssızsanız, tamamlanması X (n) işlem kadar sürebilir.
O sırada da, bazı işlevler (olarak onları düşünüyorum vardır uygulamalar arasında X (n) oldukça sık meydana gelme eğilimindedir). Bu iyi bilinen ve kolayca karşılaştırılabilir olan (örnek olarak: 1
, Log N
, N
, N^2
, N!
, vs ..)
A ve diğer algoritmalar hakkında konuşurken bunları karşılaştırarak , algoritmaları, çalışabilecekleri işlem sayısına göre sıralamak kolaydır. (en kötü durum) tamamlamak için gereklidir.
Genel olarak, amacımız A algoritmasını X(n)
mümkün olduğunca düşük bir sayı döndüren bir işleve sahip olacak şekilde bulmak veya yapılandırmak olacaktır .
Kafanızda uygun bir sonsuzluk fikriniz varsa, çok kısa bir açıklama var:
Büyük O gösterimi size sonsuz büyük bir sorunu çözmenin maliyetini anlatır.
Ve ayrıca
Sabit faktörler ihmal edilebilir
Algoritmanızı iki kat daha hızlı çalıştırabilecek bir bilgisayara yükseltirseniz, büyük O gösterimi bunu fark etmez. Sabit faktör iyileştirmeleri, büyük O gösteriminin çalıştığı ölçekte bile fark edilemeyecek kadar küçüktür. Bunun büyük O gösterimi tasarımının kasıtlı bir parçası olduğunu unutmayın.
Bununla birlikte, sabit bir faktörden "daha büyük" bir şey tespit edilebilir.
Boyutu yaklaşık sonsuz olarak kabul edilecek kadar "büyük" olan hesaplamalar yapmakla ilgilendiğinde, büyük O gösterimi yaklaşık olarak probleminizi çözmenin maliyetidir.
Yukarıdakiler mantıklı değilse, kafanızda uyumlu bir sezgisel sonsuzluk fikriniz yoktur ve muhtemelen yukarıdakilerin tümünü göz ardı etmelisiniz; bu fikirleri titiz hale getirmenin ya da zaten sezgisel olarak faydalı olmadıklarını açıklamanın tek yolu size büyük O gösterimi ya da benzer bir şey öğretmektir. (gelecekte büyük O gösterimini iyi bir şekilde anladıktan sonra, bu fikirleri tekrar ziyaret etmek faydalı olabilir)
“Big O” notasyonunun açık İngilizce açıklaması nedir?
Çok Hızlı Not:
"Büyük O" daki O "Düzen" (veya tam olarak "sırası") olarak adlandırılır,
böylece kelimenin tam anlamıyla onları karşılaştırmak için bir şey sipariş etmek için kullanıldığı fikrini alabilirsiniz.
"Big O" iki şey yapar:
Notations
.En çok kullanılan yedi gösterim var
1
adımla bir görev aldığı anlamına gelir, mükemmel, Sipariş No. 1logN
adımlarla bir görevi tamamladığı anlamına gelir , iyi, Sipariş No. 2N
adımlarla tamamlayın , adil, Sipariş No.3O(NlogN)
adımlarla bitirir , iyi değildir, Sipariş No.4N^2
adımlarla bir iş yap , kötü, Sipariş No.52^N
adımlarla bir iş yap , korkunç, Sipariş No.6N!
, korkunç, Sipariş No.7Gösterime sahip olduğunuzu varsayalım O(N^2)
, sadece yöntemin bir görevi yerine getirmek için N * N adımlarını attığını değil, aynı zamanda O(NlogN)
sıralamasından da iyi olmadığını görüyorsunuz .
Lütfen daha iyi anlamanız için satır sonunda siparişi not edin. Tüm olasılıklar dikkate alınırsa 7'den fazla gösterim var.
CS'de bir görevi gerçekleştirmeye yönelik adımlar kümesine algoritmalar denir.
Terminolojide, bir algoritmanın performansını veya karmaşıklığını tanımlamak için Big O notasyonu kullanılır.
Buna ek olarak, Big O en kötü durumu belirler veya Üst Sınır adımlarını ölçer.
En iyi durum için Big-Ω (Big-Omega) 'ya başvurabilirsiniz.
Big-Ω (Big-Omega) gösterimi (makale) | Khan Academy
Özet
"Büyük O" algoritmanın performansını tanımlar ve değerlendirir.
ya da resmi olarak ele alırsak, "Big O" algoritmaları sınıflandırır ve karşılaştırma işlemini standartlaştırır.
Ona bakmanın en basit yolu (sade İngilizce)
Giriş parametresi sayısının bir algoritmanın çalışma süresini nasıl etkilediğini görmeye çalışıyoruz. Uygulamanızın çalışma süresi giriş parametresi sayısı ile orantılıysa, o zaman Büyük O'da n olduğu söylenir.
Yukarıdaki ifade iyi bir başlangıç ama tamamen doğru değil.
Daha doğru bir açıklama (matematiksel)
varsaymak
n = giriş parametresi sayısı
T (n) = Algoritmanın çalışma süresini n'nin bir fonksiyonu olarak ifade eden gerçek fonksiyon
c = sabit
f (n) = Algoritmanın çalışma süresini n'nin bir fonksiyonu olarak ifade eden yaklaşık bir fonksiyon
Daha sonra Big O söz konusu olduğunda, f (n) yaklaşımı, aşağıdaki koşul geçerli olduğu sürece yeterince iyi kabul edilir.
lim T(n) ≤ c×f(n)
n→∞
N, sonsuzluğa yaklaştıkça, n, T, n'nin c çarpı f'den küçük veya ona eşittir.
Büyük O gösteriminde bu şu şekilde yazılır:
T(n)∈O(n)
N'nin T'si n'nin büyük O'sunda olduğu için bu okunur.
İngilizceye geri dön
Yukarıdaki matematiksel tanıma dayanarak, algoritmanızın n büyük bir O olduğunu söylüyorsanız, bu n (giriş parametre sayısı) veya daha hızlı bir işlev olduğu anlamına gelir . Algoritmanız n'nin Büyük O'su ise, otomatik olarak n karesinin Büyük O'sudur.
N büyük O, algoritmamın en az bu kadar hızlı çalıştığı anlamına gelir. Algoritmanızın Big O notasyonuna bakamaz ve yavaş olduğunu söyleyemezsiniz. Sadece hızlı diyebilirsiniz.
UC Berkley'den Big O hakkında bir video eğitimi için buna göz atın . Aslında basit bir kavram. Profesör Shewchuck'un (Tanrı seviye öğretmeni olarak da bilinir) bunu açıkladığını duyarsanız, "Oh, hepsi bu!" Diyeceksiniz.
Özellikle matematik konusunda fazla bilgi sahibi olmayan biri için büyük O gösterimi hakkında gerçekten harika bir açıklama buldum.
https://rob-bell.net/2009/06/a-beginners-guide-to-big-o-notation/
Big O gösterimi Bilgisayar Biliminde bir algoritmanın performansını veya karmaşıklığını tanımlamak için kullanılır. Big O özellikle en kötü senaryoyu tanımlar ve bir algoritma tarafından gereken yürütme süresini veya kullanılan alanı (örneğin bellekte veya diskte) tanımlamak için kullanılabilir.
Programlama İncileri veya başka herhangi bir Bilgisayar Bilimi kitabını okuyan ve Matematik'te bir temeli olmayan herkes, O (N log N) veya diğer çılgın sözdiziminden söz eden bölümlere ulaştığında bir duvara çarpmış olacaktır. Umarım bu makale Big O ve Logarithms'in temellerini anlamanıza yardımcı olacaktır.
İlk önce bir programcı ve ikinci bir matematikçi (veya belki de üçüncü veya dördüncü) olarak Big O'yu iyice anlamanın en iyi yolunu kodda bazı örnekler üretmekti. Aşağıda, mümkün olan yerlerde açıklamalar ve örneklerle birlikte bazı yaygın büyüme düzenleri verilmiştir.
O (1)
O (1), giriş veri kümesinin boyutundan bağımsız olarak her zaman aynı zamanda (veya boşlukta) yürütülecek bir algoritmayı açıklar.
bool IsFirstElementNull(IList<string> elements) { return elements[0] == null; }
O (N)
O (N) performansı doğrusal olarak ve giriş veri kümesinin boyutuyla doğru orantılı olarak büyüyecek bir algoritmayı açıklar. Aşağıdaki örnek, Big O'nun en kötü durum performans senaryosunu nasıl desteklediğini de göstermektedir; for döngüsünün herhangi bir yinelemesi sırasında eşleşen bir dize bulunabilir ve işlev erken dönecektir, ancak Big O notasyonu her zaman algoritmanın maksimum yineleme sayısını gerçekleştireceği üst sınırı üstlenecektir.
bool ContainsValue(IList<string> elements, string value) { foreach (var element in elements) { if (element == value) return true; } return false; }
O (N 2 )
O (N 2 ), performansı, giriş veri kümesinin boyutu karesi ile doğru orantılı olan bir algoritma temsil eder. Bu, veri kümesi üzerinde iç içe yinelemeleri içeren algoritmalarda yaygındır. Daha derin iç içe yinelemeler O (N 3 ), O (N 4 ) vb.
bool ContainsDuplicates(IList<string> elements) { for (var outer = 0; outer < elements.Count; outer++) { for (var inner = 0; inner < elements.Count; inner++) { // Don't compare with self if (outer == inner) continue; if (elements[outer] == elements[inner]) return true; } } return false; }
O (2 N )
O (2 N ), giriş veri kümesine her bir ek ile büyümesi iki katına çıkan bir algoritmayı belirtir. Bir O (2 N ) fonksiyonunun büyüme eğrisi üsteldir - çok sığdan başlayıp meteorik olarak yükselir. O (2 N ) fonksiyonunun bir örneği , Fibonacci sayılarının özyinelemeli hesaplamasıdır:
int Fibonacci(int number) { if (number <= 1) return number; return Fibonacci(number - 2) + Fibonacci(number - 1); }
Logaritma
Logaritmalar açıklamak için biraz daha zorlayıcıdır, bu yüzden ortak bir örnek kullanacağım:
İkili arama, sıralanmış veri kümelerini aramak için kullanılan bir tekniktir. Veri kümesinin orta öğesini, esas olarak medyanı seçerek çalışır ve bunu bir hedef değerle karşılaştırır. Değerler eşleşirse başarı döndürür. Hedef değer prob elemanının değerinden yüksekse, veri kümesinin üst yarısını alır ve buna karşı aynı işlemi gerçekleştirir. Benzer şekilde, hedef değer prob elemanının değerinden daha düşükse, işlemi alt yarıya karşı gerçekleştirecektir. Değer bulunana kadar veya artık veri kümesini bölemeyene kadar her yinelemeyle veri kümesini yarıya indirmeye devam eder.
Bu tür algoritma O (log N) olarak tanımlanır. İkili arama örneğinde açıklanan veri kümelerinin yinelemeli yarıya indirilmesi, başlangıçta zirve yapan ve veri kümelerinin boyutu arttıkça yavaşça düzleşen bir büyüme eğrisi üretir, örneğin 10 öğe içeren bir giriş veri kümesinin tamamlanması bir saniye sürer, bir veri kümesi 100 öğe içeren iki saniye sürer ve 1000 öğe içeren bir veri kümesi üç saniye sürer. Giriş veri kümesinin boyutunun iki katına çıkarılması, algoritmanın tek bir yinelemesinden sonra veri kümesinin yarıya indirileceği ve bu nedenle giriş veri boyutunun yarısının yarısı ile eşit olduğu için büyümesi üzerinde çok az etkisi vardır. Bu, büyük veri kümeleriyle uğraşırken ikili arama gibi algoritmaları son derece verimli hale getirir.
Bu çok basitleştirilmiş bir açıklama, ama umarım en önemli detayları kapsar.
Diyelim ki problemle ilgili algoritmanız bazı 'faktörlere' bağlı, örneğin N ve X yapalım.
N ve X'e bağlı olarak, algoritmanız bazı işlemler gerektirecektir, örneğin WORST durumunda 3(N^2) + log(X)
işlemleri.
Big-O, sabit faktör (aka 3) hakkında çok fazla umursamadığı için algoritmanızın Big-O'sudur O(N^2 + log(X))
. Temel olarak 'algoritmanın en kötü durum için ihtiyaç duyduğu işlem miktarını bununla ölçeklendirir'.
algoritma : bir problemi çözmek için prosedür / formül
Algoritmaları nasıl analiz eder ve algoritmaları birbiriyle nasıl karşılaştırabiliriz?
örnek: siz ve bir arkadaşınızdan 0 ile N arasındaki sayıları toplamak için bir işlev oluşturmanız istenir. f (x) ile arkadaşınız g (x) ile gelir. Her iki işlev de aynı sonuca ancak farklı bir algoritmaya sahiptir. Algoritmaların verimliliğini objektif olarak karşılaştırmak için Big-O gösterimini kullanıyoruz .
Big-O gösterimi: giriş keyfi olarak büyüdükçe çalışma zamanının girdiye göre ne kadar hızlı büyüyeceğini açıklar .
3 temel çıkarım:
Alan karmaşıklığı: zaman karmaşıklığının yanı sıra, alan karmaşıklığına da önem veriyoruz (bir algoritmanın ne kadar bellek / alan kullandığı). İşlem zamanını kontrol etmek yerine, bellek tahsisinin boyutunu kontrol ediyoruz.