Bir algoritmanın zaman karmaşıklığından bahsederken "Sabit İtfa Edilmiş Zaman" ile kastedilen nedir?
Bir algoritmanın zaman karmaşıklığından bahsederken "Sabit İtfa Edilmiş Zaman" ile kastedilen nedir?
Yanıtlar:
İtfa edilmiş zaman basit bir şekilde açıklanmıştır:
Bir operasyonu milyonlarca kez söylerseniz, o operasyonun en kötü veya en iyi durumunu umursamıyorsunuz - umursadığınız şey, operasyonu bir milyon kez tekrarladığınızda toplamda ne kadar zaman harcandığınızdır. .
Bu nedenle, "arada bir" yavaşlığın seyreltilmesi için yeterince nadir olduğu sürece, işlemin arada bir çok yavaş olması önemli değildir. Esasen itfa edilmiş süre, "birçok işlem yaparsanız işlem başına harcanan ortalama süre" anlamına gelir. İtfa edilmiş zamanın sabit olması gerekmez; doğrusal ve logaritmik amortisman süresine veya başka bir şeye sahip olabilirsiniz.
Paspasların tekrar tekrar yeni öğeler eklediğiniz dinamik bir dizi örneğini ele alalım. Normalde bir öğe eklemek sabit bir zaman alır (yani O(1)
). Ancak dizi her dolduğunda, iki kat daha fazla alan ayırır, verilerinizi yeni bölgeye kopyalar ve eski alanı boşaltırsınız. Tahsis edilen ve serbest bırakılanların sabit sürede çalıştığı varsayılarak, bu büyütme işlemi O(n)
n'nin dizinin geçerli boyutu olduğu zaman alır .
Böylece her büyüttüğünüzde, son büyütmenin iki katı kadar zaman alırsınız. Ama sen de yapmadan önce iki kez bekledin! Dolayısıyla, her bir büyütmenin maliyeti, eklemeler arasında "dağıtılabilir". Bu, uzun vadede, diziye m öğe eklemek için harcanan toplam sürenin O(m)
ve dolayısıyla itfa edilen sürenin (yani ekleme başına süre) olduğu anlamına gelir O(1)
.
Bu, zaman içinde en kötü senaryo varsayılan olarak O (1) veya sabit süreye ayarlanacağı anlamına gelir. Yaygın bir örnek, dinamik dizidir. Yeni bir giriş için zaten bellek tahsis ettiysek, eklemek O (1) olacaktır. Eğer tahsis etmediysek, bunu mevcut meblağın iki katı tahsis ederek yaparız. Bu belirli bir ekleme olacak değil O (1) olabilir, fakat başka ziyade bir şey.
Önemli olan, algoritmanın bir dizi işlemden sonra pahalı işlemlerin itfa edilmesini ve böylece tüm işlemin O (1) yapılmasını garanti etmesidir.
Veya daha katı terimlerle,
Sabit bir c vardır, öyle ki L uzunluğundaki her işlem dizisi için (ayrıca bir pahalı işlemle biten), zaman c * L'den daha büyük değildir (Teşekkürler Rafał Dowgird )
Bu konuda sezgisel bir düşünme yöntemi geliştirmek için, dinamik diziye (örneğin std::vector
C ++) eleman eklemeyi düşünün . Diziye N öğeleri eklemek için gereken işlemlerin (Y) bağımlılığını gösteren bir grafik çizelim:
Siyah grafiğin dikey bölümleri, bir diziyi genişletmek için bellek yeniden tahsislerine karşılık gelir. Burada bu bağımlılığın kabaca bir çizgi olarak gösterilebildiğini görebiliriz. Ve bu çizgi denklemi Y=C*N + b
( C
sabittir, b
bizim durumumuzda = 0). Bu nedenle C*N
, diziye N öğesi eklemek için işlemleri ortalama olarak veya C*1
bir öğe eklemek için işlemleri (amortize edilmiş sabit zaman) harcamanız gerektiğini söyleyebiliriz .
Vikipedi açıklamasının 3 kez tekrarlanmasının ardından yararlı buldum:
Kaynak: https://en.wikipedia.org/wiki/Amortized_analysis#Dynamic_Array
"Dinamik Dizi
Dinamik Dizi için İtme işleminin itfa edilmiş Analizi
Java'da ArrayList gibi daha fazla öğe eklendikçe boyutu büyüyen dinamik bir dizi düşünün. 4 boyutunda dinamik bir dizi ile başlasaydık, üzerine dört öğenin itilmesi sürekli zaman alacaktı. Ancak, dizinin beşinci bir öğeyi itmesi, dizinin geçerli boyutun iki katı yeni bir dizi oluşturmak (8), eski öğeleri yeni diziye kopyalamak ve yeni öğeyi eklemek zorunda olduğundan daha uzun sürer. Sonraki üç itme işlemi de benzer şekilde sabit zaman alacaktır ve daha sonra eklenmesi için dizi boyutunun yavaşça iki katına çıkarılması gerekecektir.
Genel olarak, n'yi bir boyut dizisine rasgele n itme sayısı göz önüne alırsak, itme işlemlerinin, boyut ikiye katlama işlemini gerçekleştirmek için O (n) zaman alan son işlem haricinde sabit zaman aldığını fark ederiz. Toplam n işlem olduğu için, bunun ortalamasını alabilir ve öğeleri dinamik diziye itmek için şunu alırız: O (n / n) = O (1), sabit zaman. "
Basit bir hikaye olarak anlayışım için:
Çok paranız olduğunu varsayın. Ve onları bir odada biriktirmek istiyorsun. Ve şimdi veya gelecekte ihtiyacınız olduğu kadar uzun el ve bacaklarınız var. Ve hepsini bir odaya doldurmalısınız, bu yüzden onu kilitlemek kolaydır.
Böylece, odanın sonuna / köşesine gidin ve istiflemeye başlayın. Onları biriktirdikçe, oda yavaş yavaş yer kaplayacak. Ancak, doldururken onları istiflemek kolaydı. Parayı aldım, parayı koy. Kolay. O (1). Daha önce hiç para taşımamıza gerek yok.
Bir kez oda boş kalıyor. Daha büyük bir odaya ihtiyacımız var. Burada bir sorun var, çünkü sadece 1 kilit alabileceğimiz için sadece 1 odamız olabilir, o odadaki tüm parayı yeni büyük odaya taşımalıyız. Yani, tüm parayı küçük odadan daha büyük odaya taşıyın. Yani, hepsini tekrar istifleyin. Yani, önceki tüm parayı taşımamız gerekiyor. Yani O (N). (N'nin önceki paranın toplam para sayısı olduğunu varsayarsak)
Başka bir deyişle, N'ye kadar kolaydı, sadece 1 operasyon, ama daha büyük bir odaya taşınmamız gerektiğinde N operasyonları yaptık. Yani, başka bir deyişle, eğer ortalama yaparsak, başlangıçta 1 ek ve başka bir odaya taşınırken 1 hareket daha olur. Toplam 2 işlem, bir kesici uç, bir hareket.
N'nin küçük odada bile 1 milyon gibi büyük olduğu varsayılırsa, N (1 milyon) ile karşılaştırıldığında 2 işlem gerçekten karşılaştırılabilir bir sayı değildir, bu nedenle sabit veya O (1) olarak kabul edilir.
Yukarıdakilerin hepsini daha büyük bir odada yaptığımızda ve tekrar hareket etmemiz gerektiğini varsayarsak. Hala aynı. Diyelim ki N2 (diyelim 1 milyar) büyük odada yeni para sayımı
Yani, N2 var (küçükten büyük odaya taşındığımızdan önceki N'yi içerir)
Hala sadece 2 operasyona ihtiyacımız var, biri daha büyük odaya yerleştiriliyor, daha sonra başka bir hareket operasyonu daha da büyük bir odaya geçmek için.
Yani, N2 (1 milyar) için bile, her biri için 2 işlemdir. ki bu yine bir şey değil. Yani, sabit veya O (1)
Yani, N N'den N2'ye veya diğerlerine arttıkça, önemli değil. Hala sabittir veya N'nin her biri için O (1) işlemi gereklidir.
Şimdi, 1 olarak N'ye sahip olduğunuzu, çok küçük olduğunu, para sayımının küçük olduğunu ve sadece 1 paraya uyacak çok küçük bir odanız olduğunu varsayalım.
Odadaki parayı doldurur doldurmaz oda doldurulur.
Daha büyük odaya gittiğinizde, içine sadece bir para daha sığabileceğini varsayın, toplam 2 para. Yani, önceki para ve 1 daha taşındı. Ve yine doldurulur.
Bu şekilde, N yavaş yavaş büyüyor ve artık sabit O (1) değil, çünkü önceki odadan tüm parayı taşıyoruz, ancak sadece 1 para daha sığabiliyor.
100 kez sonra, yeni oda bir öncekinden 100 sayma para ve sığabileceği 1 para daha sığdırır. Bu O (N), çünkü O (N + 1) O (N), yani 100 veya 101 derecesi aynı, her ikisi de yüzlerce, önceki hikayenin aksine, milyonlarca ve milyarlarca .
Yani, bu, para (değişkenler) için oda (veya bellek / RAM) tahsis etmenin yetersiz bir yoludur.
Yani, 2'nin gücü ile daha fazla yer ayırmak iyi bir yoldur.
1. oda büyüklüğü = 1 adet paraya uyuyor
2. oda boyutu = 4 paraya uyuyor
3. oda boyutu = 8 paraya
uyuyor 4. oda boyutu = 16 paraya
uyuyor 5. oda büyüklüğü = 32 paraya
uyuyor 6. oda büyüklüğü = 64 para sayısı
7 oda büyüklüğü = 128 para sayısı
8 oda büyüklüğü = 256 para sayısı
9 oda büyüklüğü = 512 para sayısı
10 oda büyüklüğü = 1024 para sayısı
11 oda büyüklüğü = 2,048 para sayısı için uygundur
. ..
16. oda büyüklüğü = 65.536 para sayısına uyar
...
32. oda büyüklüğü = 4.294.967.296 para sayısına uyar
...
64. oda büyüklüğü = 18.446.744.073.709.551.616 para sayısına uyar
Bu neden daha iyi? Çünkü başlangıçta yavaş büyüyor ve daha sonra daha hızlı, yani RAM'imizdeki bellek miktarına kıyasla.
Bu yararlıdır, çünkü ilk durumda iyi olmasına rağmen, para başına yapılacak toplam iş miktarı sabittir (2) ve oda büyüklüğü (N) ile karşılaştırılamaz, ilk aşamalarda aldığımız oda da büyük (1 milyon) kullanamayız.
Bununla birlikte, son durumda, 2'nin gücü, RAM'imizin sınırlarında büyür. Ve böylece, 2'nin gücünde artış, hem Armotized analizi sabit kalır hem de bugün itibariyle sahip olduğumuz sınırlı RAM için dostudur.
Yukarıdaki açıklamalar, birden çok işlem üzerinde "ortalama" alma fikri olan Toplam Analiz için geçerlidir. Bankacılar yöntemine ya da Fizikçiler Amortisman yöntemlerine nasıl başvurduklarından emin değilim.
Şimdi. Doğru cevaptan tam olarak emin değilim. Ancak, her iki Fizikçi + Banker yönteminin temel durumu ile ilgili olacaktır:
(İşlemlerin itfa edilmiş maliyetinin toplamı)> = (İşlemlerin gerçek maliyetinin toplamı).
Karşılaştığım en büyük zorluk, işlemlerin itfa edilmiş asimptotik maliyetlerinin normal asimptotik maliyetten farklı olduğu göz önüne alındığında, itfa edilmiş maliyetlerin önemini nasıl derecelendireceğimi bilmiyorum.
Birisi benim amortismana tabi bir maliyet verdiğinde, bunun normal asimptotik maliyetle aynı olmadığını biliyorum. Öyleyse itfa edilmiş maliyetten ne gibi sonuçlar çıkaracağım?
Bazı operasyonlar fazla yüklenirken bazı operasyonların fazla ücretlendirildiğinden, bir hipotez, bireysel operasyonların itfa edilmiş maliyetlerinin teklifinin anlamsız olacağı olabilir.
Örneğin: Bir fibonacci yığını için, sadece azalan anahtarın O (1) olarak itfa edilmiş maliyetinden alıntı yapmak anlamsızdır, çünkü maliyetler "yığın potansiyelinin artması için daha önceki operasyonlar tarafından yapılan çalışma" ile azaltılır.
VEYA
İtfa edilmiş maliyetlerle ilgili nedenlerin şu şekilde olduğu başka bir hipotezimiz olabilir:
Pahalı operasyonun öncesinde ÇOK DÜŞÜK MALİYETLİ operasyonlar olacağını biliyorum.
Analiz uğruna, bazı düşük maliyetli işlemleri aşırı yükleyeceğim.
Artan bu düşük maliyetli operasyonlarla, pahalı operasyonun daha küçük bir asimptotik maliyeti olduğunu kanıtlayabilirim.
Böylece n operasyonlarının maliyetinin ASİMPTOTİK SINIRINI geliştirdim / azalttım.
Dolayısıyla, itfa edilmiş maliyet analizi + itfa edilmiş maliyet sınırları artık sadece pahalı operasyonlar için geçerlidir. Ucuz operasyonlar, normal asimptotik maliyetleriyle aynı asimtotik-itfa edilmiş maliyete sahiptir.
Herhangi bir işlevin performansı, "toplam işlev çağrısı sayısı" nı "yapılan tüm bu çağrılar için toplam süreye" bölerek ortalanabilir. Yaptığınız her çağrı için daha uzun ve daha uzun süren işlevlerin bile bu şekilde ortalaması alınabilir.
Dolayısıyla, performans gösteren bir fonksiyonun özü, Constant Amortized Time
bu "ortalama sürenin" çağrıların sayısı artmaya devam ettikçe aşılmayan bir tavana ulaşmasıdır. Belirli bir çağrı performansta değişiklik gösterebilir, ancak uzun vadede bu ortalama süre daha da büyümeye devam etmez.
Bu, performans gösteren bir şeyin temel değeridir Constant Amortized Time
.