Algoritma analizinin büyüsünün ardında bir sistem var mı?


159

Algoritmaların çalışma zamanını nasıl analiz edeceğinizle ilgili birçok soru var (bkz. Örneğin ve ). Birçoğu, örneğin, iç içe döngüler için maliyet analizi veya bölme ve fethetme algoritmaları isteyenlere benzer, ancak çoğu cevap özel olarak yapılmış gibi görünmektedir.

Öte yandan, başka bir genel soruya verilen cevaplar , bazı örneklerle daha büyük resmi (özellikle de asimptotik analizle ilgili) açıklar, ancak ellerinizi nasıl kirleteceğinizi açıklamaz.

Algoritmaların maliyetini analiz etmek için yapısal, genel bir yöntem var mı? Maliyet, çalışma süresi (zaman karmaşıklığı) veya yapılan karşılaştırma sayısı, alan karmaşıklığı veya başka bir şey gibi başka bir maliyet ölçüsü olabilir.

Bunun yeni başlayanlara işaret etmek için kullanılabilecek bir referans soru olması gerekiyordu ; dolayısıyla normalden daha geniş kapsamı. Lütfen en az bir örnekle gösterilen, ancak yine de pek çok durumu kapsayan genel, didaktik olarak sunulan cevaplar vermeye özen gösterin. Teşekkürler!


3
Bu kadar uzun yazılar yazmayı kolaylaştırdığı için StackEdit'in yazarlarına / yazarlarına ve daha önceki taslaklardaki kusurları gidermeme yardımcı oldukları için beta okuyucularım FrankW , Juho , Gilles ve Sebastian'a teşekkürler.
Raphael

1
Hey @Raphael, bu harika bir şey. Dolaşmak için bir PDF olarak bir araya getirmeyi önerebileceğimi düşündüm? Bu tür bir şey gerçekten yararlı bir referans olabilir.
04

1
@ hadsed: Teşekkürler, sizin için faydalı olduğuna sevindim! Şimdilik bu yazıya bir bağlantının dolaştırılmasını tercih ediyorum. Bununla birlikte, SE kullanıcı içeriği "atıflar gerekliyse cc cc sa 3.0 altında lisanslanmıştır" (sayfa altbilgisine bakınız), bu nedenle, atıf verildiği sürece herkes ondan bir PDF oluşturabilir.
Raphael

2
Bu konuda özellikle yetkin değilim, ancak Master teoremine herhangi bir cevapta atıfta bulunmaması normal mi?
babou

1
@babou Burada "normal" in ne anlama geldiğini bilmiyorum. Benim bakış açıma göre, Master teoreminin burada hiçbir işi yoktur: bu algoritmaları analiz etmekle ilgilidir, Master teoremi (bazı) yinelemeleri (ve çok kabaca) çözmek için çok özel bir araçtır. Matematik başka bir yerde ele alındığından (örneğin burada ) algoritmadan matematiğe sadece bir bölümü ele almayı seçtim. Cevabımdaki matematiğin çalışılmasıyla ilgili yayınlara referans veriyorum.
Raphael

Yanıtlar:


134

Kodu Matematiğe Çevirmek

(Daha fazla veya daha az) resmi bir işlemsel anlambilim kuralı olarak, bir algoritmanın (sözde) kodunu kelimenin tam anlamıyla, ifadeyi yararlı bir forma sokabilmeniz koşuluyla size sonuç veren matematiksel bir ifadeye çevirebilirsiniz. Bu , karşılaştırma sayısı, takas, açıklama, hafıza erişimi, bazı soyut makinelerin ihtiyaç duyduğu döngüleri vb. İlave maliyet ölçümleri için iyi çalışır .

Örnek: Bubblesort'taki Karşılaştırmalar

Belirli bir diziyi sıralayan bu algoritmayı düşünün A:

 bubblesort(A) do                   1
  n = A.length;                     2
  for ( i = 0 to n-2 ) do           3
    for ( j = 0 to n-i-2 ) do       4
      if ( A[j] > A[j+1] ) then     5
        tmp    = A[j];              6
        A[j]   = A[j+1];            7
        A[j+1] = tmp;               8
      end                           9
    end                             10
  end                               11
end                                 12

Diyelim ki, sıralı sıralama algoritması analizini yapmak istiyoruz, bu da element karşılaştırma sayısını sayar (satır 5). Hemen bu miktarın, dizinin içeriğine bağlı olmadığını A, sadece uzunluğuna bağlı olduğunu not ediyoruz n. Böylece (yuvalanmış) forhalkaları tam anlamıyla (yuvalanmış) toplamlara çevirebiliriz; döngü değişkeni birleştirme değişkeni haline gelir ve aralık devam eder. Biz alırız:

,Ccmp(n)=i=0n2j=0ni21==n(n1)2=(n2)

buradaki , 5. satırdaki her bir işlemin maliyetidir (ki biz sayarız).1

Örnek: Bubblesort'ta takaslar

Ben tarafından ifade edeceğiz hattından oluşmaktadır alt programı için ve tarafından C i , j bu alt programı (bir kez) yürütmek için maliyetleri.Pi,jijCi,j

Şimdi de saymak istediğiniz diyelim takaslarını , ne kadar sıklıkla yürütülür. Bu bir "temel blok", yani her zaman atomik olarak yürütülen ve sabit bir maliyeti olan bir alt programdır (burada, 1 ). Bu tür blokların sözleşme yapılması, genellikle düşünmeden veya konuşmadan uygulayacağımız kullanışlı bir basitleştirmedir.P6,81

Yukarıdaki gibi benzer bir çeviri ile aşağıdaki formüle geliyoruz:

.Cswaps(A)=i=0n2j=0ni2C5,9(A(i,j))

daha önce dizinin durumunu belirtmektedir ( i , j ) bir inci yineleme P 5 , 9 .A(i,j)(i,j)P5,9

Parametre olarak n yerine kullandığımı unutmayın ; Yakında neden göreceğiz. Ben katmayan i ve j parametreleri olarak C 5 , 9 (maliyetlerin beri burada onlara bağlı olmayan tek tip maliyet modeline yani); genel olarak, sadece olabilir.AnijC5,9

Açıktır ki, maliyeti içeriğine bağlıdır A (değerler ve özellikle de) bu nedenle bu hesaba gerekir. Şimdi bir zorlukla karşı karşıyayız: C 5 , 9'u nasıl açıyoruz ? A'nın içeriğine bağımlılığı yapabiliriz :P5,9AA[j]A[j+1]C5,9A

.C5,9(A(i,j))=C5(A(i,j))+{1,A(i,j)[j]>A(i,j)[j+1]0,else

Herhangi bir giriş dizisi için, bu maliyetler iyi tanımlanmıştır, ancak daha genel bir ifade istiyoruz; daha güçlü varsayımlarda bulunmamız gerekiyor. Üç tipik olayı araştıralım.

  1. En kötü durum

    Sadece toplamı incelemek ve değerine dikkat çekerek, maliyet için önemsiz bir üst sınır bulabiliriz:C5,9(A(i,j)){0,1}

    .Cswaps(A)i=0n2j=0ni21=n(n1)2=(n2)

    Ancak bu olabilir mi , yani bu üst sınırın elde edildiği için bir var mı? Görünen o ki, evet: tersine sıralanmış bir ikili ayrı eleman dizisi girersek, her yineleme bir takas gerçekleştirmelidir. Bu nedenle, bubblesort'un en kötü durumda olan takas sayısını kesin olarak belirledik.A

  2. En iyi durum

    Tersine, önemsiz bir alt sınır var:

    .Cswaps(A)i=0n2j=0ni20=0

    Bu da olabilir: zaten sıralanan bir dizide, Bubblesort tek bir takas yürütmez.

  3. Ortalama durum

    En kötü ve en iyi durum oldukça açık. Fakat tipik takas sayısı nedir? Bu soruyu cevaplamak için "tipik" ifadenin ne anlama geldiğini tanımlamamız gerekir. Teoride, bir girişi bir başkasına tercih etmek için hiçbir nedenimiz yoktur ve bu nedenle genellikle tüm olası girdiler üzerinde eşit bir dağılım olduğunu varsayıyoruz , bu da her girdi eşit derecede muhtemeldir. İkili ayrı elementler içeren dizileri kendimizle sınırlıyoruz ve böylece rastgele permütasyon modelini üstleniyoruz .

    Ardından, bu gibi masraflarımızı yeniden yazabiliriz:

    E[Cswaps]=1n!Ai=0n2j=0ni2C5,9(A(i,j))

    Şimdi toplamların basit manipülasyonunun ötesine geçmeliyiz. Algoritması bakarak, biz her takas tam olarak bir kaldırır dikkat inversiyon içinde (biz sadece hiç neighbours³ takas). Bu, üzerinde yapılan swap sayısını, A tam inversiyon sayısıdır inv ( A ) arasında bir . Böylece içsel iki toplamı değiştirebiliriz.AAinv(A)A

    .E[Cswaps]=1n!Ainv(A)

    Şanslıyız ki, ortalama inversiyon sayısı

    E[Cswaps]=12(n2)

    bu bizim nihai sonucumuz. Bunun en kötü durum maliyetinin yarısı kadar olduğuna dikkat edin.


  1. Algoritmanın dikkatli bir şekilde formüle edildiğine dikkat edin i = n-1, dış döngü ile hiçbir şey yapmadan "son" yineleme yapılmaz.
  2. E
  3. Biz o yol boyunca öğrenmek hayır sadece komşu elemanlarını değiştirir algoritma asimptotik hızlı (hatta ortalama olarak) BubbleSort daha olabilir - inversiyon sayısı bir alt sınır tür tüm algoritmalar içindir. Bu, örneğin Ekleme Sıralama ve Seçim Sıralama için geçerlidir .

Genel Yöntem

Örnekte kontrol yapısını matematiğe çevirmemiz gerektiğini gördük; Tipik bir çeviri kuralları topluluğu sunacağım. Ayrıca herhangi bir alt programın maliyetinin mevcut duruma bağlı olduğunu, yani değişkenlerin şu anki değerlerine (kabaca) bağlı olduğunu gördük . Algoritma (genellikle) durumu değiştirdiğinden, genel metot not almak için biraz hantaldır. Kafanız karıştıysa, örneğe geri dönmenizi veya kendinize ait bir şeyler yapmanızı öneririm.

Mevcut durumu ile gösteririz (bunu bir değişken atama kümesi olarak hayal edin). Bir programı çalıştırmak zaman durum başlangıç ψ , bir devlet sona ψ / P (Resim sonlandırır).ψPψψ/PP

  • Bireysel ifadeler

    S;CS(ψ)

  • İfade

    EFormun bir ifadesi varsa E1 ∘ E2(örneğin, toplama veya çarpma olabilecek bir aritmetik ifade) , maliyetleri tekrarlı olarak eklersiniz:

    CE(ψ)=c+CE1(ψ)+CE2(ψ)

    Bunu not et

    • cE1E2
    • ifadelerin değerlendirilmesi birçok dilde devleti değiştirebilir,

    bu kural ile esnek olmanız gerekebilir.

  • Sıra

    PProgramların sırası olarak bir program göz önüne alındığında Q;R, maliyetleri

    CP(ψ)=CQ(ψ)+CR(ψ/Q)

  • Şartlılar

    PFormun bir programı göz önüne alındığında if A then Q else R end, maliyetler devlete bağlıdır:

    CP(ψ)=CA(ψ)+{CQ(ψ/A),A evaluates to true under ψCR(ψ/A),else

    Genel olarak, değerlendirme A, durumu çok iyi değiştirebilir, dolayısıyla bireysel branşların maliyetleri için güncelleme yapılabilir.

  • -Loops için

    PFormun bir programı göz önüne alındığında for x = [x1, ..., xk] do Q end, maliyet atamak

    CP(ψ)=cinit_for+i=1kcstep_for+CQ(ψi{x:=xi})

    ψiQxixx1xi-1

    cinit_forcstep_for

    • Bir sonraki hesaplama xipahalı olabilir ve
    • forBoş gövdeli bir döngü (örneğin, belirli bir maliyetle en iyi durum ayarında sadeleştirmeden sonra), yineleme yaparsa sıfır maliyeti yoktur.
  • -Loops iken

    PFormun bir programı göz önüne alındığında while A do Q end, maliyet atamak

    CP(ψ) =CA(ψ)+{0,A evaluates to false under ψCQ(ψ/A)+CP(ψ/A;Q), else

    Algoritmayı inceleyerek, bu tekrarlama genellikle for-loop'lara benzer bir toplam olarak güzel bir şekilde gösterilebilir.

    Örnek: Bu kısa algoritmayı düşünün:

    while x > 0 do    1
      i += 1          2
      x = x/2         3
    end               4
    

    Kuralı uygulayarak alırız

    C1,4({i:=i0;x:=x0}) =c<+{0,x00c+=+c/+C1,4({i:=i0+1;x:=x0/2}), else

    cix

    C1,4i

    C1,4(x)={c>,x0c>+c+=+c/+C1,4(x/2), else

    Bu birlikte çözer temel aracı için

    C1,4(ψ)=log2ψ(x)(c>+c+=+c/)+c>

    ψ={,x:=5,}ψ(x)=5

  • Prosedür Çağrıları

    Bazı parametreler Piçin formun bir programı verildiğinde , (adlandırılmış) parametresiyle bir prosedür olan maliyetler atayınM(x)xMp

    CP(ψ)=ccall+CM(ψglob{p:=x})

    ccallψ

    Buradaki devletle ilgili olabilecek bazı anlamsal sorunları anlatıyorum. Küresel durumu ve bu tür yerel işlemleri prosedür çağrılarına göre ayırt etmek isteyeceksiniz. Sadece biz burada sadece küresel devlet geçmek ve varsayalım Mdeğerini ayarlayarak başlatıldı yeni bir yerel devlet, alır piçin x. Ayrıca, x(genellikle) geçmeden önce değerlendirmeyi düşündüğümüz bir ifade olabilir.

    Örnek: Prosedürü düşünün

    fac(n) do                  
      if ( n <= 1 ) do         1
        return 1               2
      else                     3
        return n * fac(n-1)    4
      end                      5
    end                        
    

    Kurallara göre:

    Cfac({n:=n0})=C1,5({n:=n0})=c+{C2({n:=n0}),n01C4({n:=n0}), else=c+{creturn,n01creturn+c+ccall+Cfac({n:=n01}), else

    facHiçbir şekilde erişemediği için küresel devleti göz ardı ettiğimizi unutmayın . Bu özel yinelemenin çözülmesi kolaydır

    Cfac(ψ)=ψ(n)(c+creturn)+(ψ(n)1)(c+ccall)

Tipik sözde kodla karşılaşacağınız dil özelliklerini ele aldık. Üst düzey sahte kodu analiz ederken gizli maliyetlere dikkat edin; şüphe durumunda, açılmak. Notasyon hantal görünebilir ve kesinlikle bir zevk meselesidir; Yine de listelenen kavramlar göz ardı edilemez. Bununla birlikte, bazı deneyimlerle, devletin hangi kısımlarının hangi maliyet ölçüsü için uygun olduğunu hemen görebileceksiniz, örneğin "sorun boyutu" veya "tepe noktası sayısı". Gerisi düşebilir - bu işleri önemli ölçüde kolaylaştırır!

Bu çok karmaşık olduğunu şimdi düşünüyorsanız, tavsiye edilebilir: Bu olduğunu ! Gerçek zamanlı makinelere çalışma süresi tahminlerini (göreceli olanlar bile) mümkün kılacak kadar yakın olan herhangi bir modelde algoritmaların kesin maliyetlerini türetmek zor bir çabadır. Ve bu, gerçek makineler üzerindeki önbellekleme ve diğer kötü etkileri dikkate almıyor bile.

Bu nedenle, algoritma analizi genellikle matematiksel olarak izlenebilir olma noktasına göre basitleştirilmiştir. Örneğin, kesin bir maliyete ihtiyacınız yoksa, herhangi bir noktada (üst ve alt sınırlar için) aşırı veya düşük tahmin edebilirsiniz: sabitleri azaltın, koşullardan kurtulun, toplamları basitleştirin, vb.

Asimptotik maliyet notu

n

Bu (genellikle) adildir, çünkü soyut ifadeler , makineye, işletim sistemine ve diğer faktörlere bağlı olarak gerçekte bazı (genel olarak bilinmeyen) maliyetlere sahiptir ve işlemi ilk etapta ve ne olursa olsun yapan işletim sistemi tarafından kısa çalışma sürelerine hâkim olabilir. Zaten biraz sapkınlık yaşarsın.

Asimptotik analizin bu yaklaşımla ilişkisi:

  1. Tanımlayın baskın , yani (sabit faktörlere kadar) en sık ortaya operasyonlar (yani maliyetleri teşvik) işlemleri. Bubblesort örneğinde, olası bir seçenek, 5. satırdaki karşılaştırmadır.

    Alternatif olarak, temel işlemler için tüm sabitleri en fazla (yukarıdan) karşılık olarak bağlarlar. minimum (aşağıdan) ve normal analiz yapın.

  2. Bu işlemin yürütme sayılarını maliyet olarak kullanarak analizi gerçekleştirin.
  3. OΩ

O

daha fazla okuma

Algoritma analizinde daha birçok zorluk ve püf noktası var. İşte önerilen bazı okumalar.

etiketli birçok soru var, buna benzer teknikler kullanıyor.


1
belki asimptotik analiz için ana teoremi (ve uzantıları ) bazı referanslar ve örnekler
Nikos M.

@NikosM Burada kapsam dışındadır (ayrıca yukarıdaki soru hakkındaki yorumlara bakın). Master teorem ve ark.
Raphael

@Nikos M: $ 0,02: Master teoremi birçok yinelenme için çalışırken, diğerleri için olmaz; tekrarları çözmek için standart yöntemler vardır. Ve çalışma zamanını tekrarlayan bir nükse bile sahip olamayacağımız algoritmalar var; bazı ileri sayım teknikleri gerekli olabilir. İyi bir matematik geçmişine sahip biri için Sedgewick ve Flajolet'in "nüks ilişkileri", "fonksiyon üretme" ve "asimptotik yaklaşımlar" gibi bölümleri olan "Algoritmaların Analizi" adlı kitabını öneririm. Veri yapıları arada bir örnek olarak ortaya çıkıyor ve odak nokta metotlar!
Jay

@Raphael Operasyonel semantiye dayalı bu "Matematiğe Kod Dönüştürme" yöntemi için web üzerinde herhangi bir söz bulamıyorum. Bununla daha resmi olarak ilgilenen kitap, makale ya da makaleye referans verebilir misiniz? Ya da bunun sizin tarafınızdan geliştirildiği durumda, daha derinlemesine bir şeyiniz var mı?
Wyvern666

1
@ Wyvern666 Maalesef hayır. Bunu kendim yaptım, herkesin böyle bir şey yapmayı iddia edebileceği kadarıyla. Belki bir noktada kendimi doyurucu bir çalışma yazarım. Bununla birlikte, analitik kombinatoriklerin (Flajolet, Sedgewick ve diğerleri) etrafındaki bütün çalışma grubu bunun temelidir. Çoğu zaman "kod" un resmi anlamlarıyla uğraşmazlar, ancak genel olarak "algoritmaların" ek maliyetleriyle uğraşmaları için matematiği sağlarlar. Gerçekten burada ortaya konan kavramların çok derin olmadığını düşünüyorum - girebileceğiniz matematik de olsa.
Raphael

29

İcra İfadeleri

Bilgisayar Programcılığı Sanatı programında Donald E. Knuth tarafından öne sürülen başka bir yöntem daha var . Tüm algoritmayı tek bir formüle çevirmenin aksine , “şeyleri bir araya getirmek” tarafındaki kodun anlambiliminden bağımsız olarak çalışır ve "kartal gözü" görünümünden başlayarak yalnızca gerektiğinde daha düşük bir seviyeye gitmesine izin verir. Her ifade diğerlerinden bağımsız olarak analiz edilebilir ve böylece daha net hesaplamalar yapılabilir. Bununla birlikte, teknik, çok daha yüksek seviye sözde koduna değil, oldukça ayrıntılı koda kendisini iyi verir.

Yöntem

Prensip olarak oldukça basit:

  1. Her ifadeye bir ad / numara atayın.
  2. SiCi
  3. Siei
  4. Toplam maliyetleri hesapla

    C=ieiCi

Tahminleri ve / veya sembolik büyüklükleri herhangi bir noktaya ekleyebilirsiniz, cevap verebiliriz. sonucun buna göre genelleştirilmesi.

e77O(nlogn)

Örnek: Derinlik ilk arama

Aşağıdaki grafik geçiş algoritmasını göz önünde bulundurun:

dfs(G, s) do
  // assert G.nodes contains s
  visited = new Array[G.nodes.size]     1
  dfs_h(G, s, visited)                  2
end 

dfs_h(G, s, visited) do
  foo(s)                                3
  visited[s] = true                     4

  v = G.neighbours(s)                   5
  while ( v != nil ) do                 6
    if ( !visited[v] ) then             7
      dfs_h(G, v, visited)              8
    end
    v = v.next                          9
  end
end

{0,,n1}m

ABCei

i123456789eiAABBBB+CCB1C

e8=e31foodfse6=e5+e7while

A=1fooB=nC=2m

i123456789ei11nnn2m+n2mn12m

Bu bizi tam olarak toplam maliyete götürür

C(n,m)=(C1+C2C8)+ n(C3+C4+C5+C6+C8)+ 2m(C6+C7+C9).

Ci

i123456789Cin00110101

ve Al

Cmem(n,m)=3n+4m

daha fazla okuma

Diğer cevabımın alt kısmına bakınız .


8

Algoritma analizi, teorem ispatlama gibi, büyük ölçüde bir sanattır (örneğin, nasıl analiz edeceğimizi bilmediğimiz basit programlar vardır ( Collatz problemi gibi )). Bir algoritma karmaşıklığı problemini, Raphael tarafından kapsamlı bir şekilde cevaplandırıldığı gibi matematiksel bir soruna dönüştürebiliriz , ancak daha sonra bilinen fonksiyonlar açısından bir algoritmanın maliyetine bağlılığı ifade etmek için:

  1. Mevcut analizlerden bildiğimiz teknikleri kullanın; örneğin, anladığımız yinelemelere dayalı sınırları bulma veya hesaplayabildiğimiz / toplayabildiğimiz toplamları.
  2. Algoritmayı nasıl analiz edeceğimizi bildiğimiz bir şeyle değiştirin.
  3. Tamamen yeni bir yaklaşımla gelin.

1
Sanırım bunun diğer cevapların üstünde, üstünde faydalı ve yeni bir şey eklediğini göremiyorum. Teknikler zaten diğer cevaplarda açıklanmıştır. Bu bana bir sorunun cevabından çok bir yorum gibi görünüyor.
DW

1
Diğer cevapların bunun bir sanat olmadığını kanıtladığını düşünüyorum . Bunu yapamayabilirsiniz (yani matematik) ve bazı yaratıcılık (bildiğiniz matematiği nasıl uygulayacağınızla ilgili), olsa bile gerekli olabilir, ancak bu herhangi bir görev için geçerlidir . Burada yeni matematik oluşturmak istemediğimizi varsayıyorum. (Aslında, bu soruya cevap veriyor. Verdiği cevaplar tüm süreci susturmaya yönelikti.)
Raphael

4
@Raphael Ari, “program tarafından yürütülen talimatların sayısı” yerine, sınır olarak tanınabilir bir fonksiyonun ortaya çıkmasından bahsediyor. Genel durum olduğu bir sanat - tüm algoritmalar için aşikar olmayan sınır ile gelip hiçbir algoritma var. Bununla birlikte, ortak durum bilinen bir teknikler kümesidir (örneğin, ana teorem gibi).
Gilles

@Gilles Herhangi bir algoritma bulunmayan her şey bir sanat ise, sanatkarlara (özellikle programcılara) daha kötü ödeme yapılırdı.
Raphael

1
@AriTrachlenberg önemli bir noktaya değindi, ancak bir algoritma zaman karmaşıklığını değerlendirmek için sayısız yol var. Big O notasyonu tanımları, yazara bağlı olarak teorik niteliklerini ima eder veya doğrudan belirtir. “En kötü durum senaryosu” açıkça görüşme için odayı açıklar ve / veya odada tartışan herhangi bir N insanı arasında yeni gerçekleri açık bırakır. Asimptotik tahminlerin doğasından bahsetmiyorum bile ... tam anlamıyla mükemmel bir şey değil.
Brian Ogden,
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.