Algoritmalar nasıl tanımlanır, kanıtlanır ve analiz edilir?


20

Bilgisayar Programlama Sanatı'nı (TAOCP) okumadan önce bu soruları derinlemesine düşünmedim. Ben algoritmaları tanımlamak, onları anlamak ve sadece büyüme siparişleri hakkında çalışma süresini tahmin etmek için sahte kod kullanırdım. TAOCP iyice fikrimi değiştirir.

TAOCP , algoritmayı tanımlamak için adımlar ve goto ile karıştırılmış İngilizce kullanır ve algoritmayı daha kolay resmetmek için akış şemalarını kullanır. Düşük seviyeli görünüyor, ancak özellikle çok fazla göz ardı ettiğim akış şemasında bazı avantajlar olduğunu düşünüyorum. Hesaplamanın bu oku geçtiği andaki mevcut durum hakkında bir iddiayla okların her birini etiketleyebilir ve algoritma için endüktif bir kanıt oluşturabiliriz. Yazar diyor ki:

Bir algoritmanın neden geçerli olduğunu gerçekten anladığımız yazarın tartışmasıdır, ancak Şekil 4'te olduğu gibi zihinlerimizin tüm iddiaları örtülü olarak doldurduğu noktaya ulaştığımızda.

Ben böyle şeyler yaşamadım. Başka bir avantaj, her adımın kaç kez yürütüldüğünü sayabilmemizdir. Kirchhoff'un ilk yasasını kontrol etmek kolaydır. Çalışma süresini tam olarak analiz , bu yüzden çalışma süresini tahmin ederken bazı atlanmış olabilir.±1

Büyüme emirlerinin analizi bazen işe yaramaz. Örneğin, quicksort'u heatsort'tan ayırt edemeyiz çünkü hepsi , burada beklenen rasgele değişken sayısıdır , bu nedenle sabit, ve , böylece ve T_2 daha iyi. Ve ayrıca, bazen varyanslar gibi diğer miktarları karşılaştırmalıyız. Çalışma zamanının büyüme emirlerinin sadece kaba bir analizi yeterli değildir. As TAOCPE(T(n))=Θ(nlogn)EXXE(T1(n))=A1nlgn+B1n+O(logn)T 1 T 2E(T2(n))=A2lgn+B2n+O(logn)T1T2 algoritmaları montaj diline çevirir ve çalışma süresini hesaplar, Benim için çok zor, bu yüzden çalışma süresini biraz daha kabaca analiz etmek için bazı teknikleri bilmek istiyorum, bu da C, C ++ gibi daha üst düzey diller için yararlıdır veya sözde kodlar.

Ve esas olarak araştırma çalışmalarında hangi açıklama tarzının kullanıldığını ve bu sorunların nasıl ele alınacağını bilmek istiyorum.


6
Bunu algoritmaların yürütme sürelerini yakından karşılaştırırken çok dikkatli olmalısınız. Gerçek bilgisayarların önbellekleri, kayıtları ve boru hatları vardır, bu da çalışma süresini büyük ölçüde değiştirebilir. Hangi algoritmanın gerçekten daha hızlı olduğunu bulmak istiyorsanız, bunu bir bilgisayarda çalıştırmanız gerekir.
svick

1
Aslında böyle Knuth kullanımlar olarak montajcı analiz olduğu yolu hiçbir şey gizli ve denetim akışı kolaydır çünkü gerçek yaşam kodunu analiz daha kolay. Sen pratik istiyorsun; Bence Dave'in yorumu geçerlidir. Uygulayıcıların algoritmalarını çalışma zamanı ölçümleri kullanarak tasarlama olasılığı, sıkı analiz yapmaktan daha olasıdır. Ama o zaman ben uygulayıcı değilim, bu yüzden söylediklerimi bir tuz tanesi ile al.
Raphael

1
@Raphael My pratikte araştırma çalışmaları uygulamada programlama değil anlamına gelir .
Yai0Phah

@Frank, varyansla ne demek istiyorsun ? Performans testlerim bana zamanlama sapmaları veriyor.
edA-qa mort-ora-y

@ Raphael, ilk noktanız artık gerçek değil. Modern çipler montajınızı yeniden düzenler, depolar / yükleri sıra dışı yapar ve tahmini çalıştırma ve yükleme yapar. Eşzamanlılık ve önceki konular için, kapsamlı bir analiz gerçekten gereklidir, ancak bunu resmi bir biçimde yapmıyorum.
edA-qa mort-ora-y

Yanıtlar:


18

Çok çeşitli uygulanabilir yaklaşımlar vardır. Hangisi daha uygun?

  • ne göstermeye çalışıyorsun,
  • ne kadar detay istediğiniz veya ihtiyacınız.

Algoritma, altyordam olarak kullandığınız yaygın olarak biliniyorsa, genellikle daha yüksek bir seviyede kalırsınız. Algoritma araştırılan ana nesne ise, muhtemelen daha ayrıntılı olmak istersiniz. Aynı şey analizler için de söylenebilir: kaba bir üst çalışma zamanı sınırına ihtiyacınız varsa, ifadelerin tam olarak sayılmasını istediğinizden farklı şekilde devam edersiniz.

Size umarım bunu gösteren iyi bilinen algoritma Mergesort için üç örnek vereceğim.

Yüksek seviye

Mergesort algoritması bir liste alır, iki (yaklaşık) eşit uzunlukta uzun parçaya ayırır, bu kısmi listelerde geri çekilir ve sonuçların sıralanması için (sıralanmış) sonuçları birleştirir. Tekli veya boş listelerde girdiyi döndürür.

Bu algoritma açık bir şekilde doğru bir sıralama algoritmasıdır. Listeyi bölmek ve birleştirmek her zaman zamanında uygulanabilir , bu da bize en kötü çalışma zamanı için bir yineleme sağlar . Ana teorem ile bu değerlendirilir .T ( n ) = 2 T ( nΘ(n)T(n)Θ(nlogn)T(n)=2T(n2)+Θ(n)T(n)Θ(ngünlükn)

Orta düzey

Mergesort algoritması aşağıdaki sahte kodla verilir:

procedure mergesort(l : List) {
  if ( l.length < 2 ) {
    return l
  }

  left  = mergesort(l.take(l.length / 2)
  right = mergesort(l.drop(l.length / 2)
  result = []

  while ( left.length > 0 || right.length > 0 ) {
    if ( right.length == 0 || (left.length > 0 && left.head <= right.head) ) {
      result = left.head :: result
      left = left.tail
    }
    else {
      result = right.head :: result
      right = right.tail
    }
  }

  return result.reverse
}

Doğruluğu tümevarım ile kanıtlarız. Sıfır veya bir uzunluktaki listeler için algoritma önemsizdir. Tümevarım hipotezi olarak, bazı keyfi, ancak sabit doğal için mergesortuzunluk listelerinde en fazla doğru çalıştığını varsayın . Şimdi uzunluğunun bir listesi olsun . Tümevarım hipotezleri ve ilk azalan (azalan olmayan) sıralanmış versiyonları tutun. özyinelemeli çağrılardan sonra ikinci yarısı . Bu nedenle, döngü her yinelemede henüz araştırılmamış en küçük elemanı seçer ve ekler ; böylece , tüm öğeleri içeren ven > 1 L n + 1 L Lnn>1Ln+1leftrightLwhileresultresultleftright. Bunun tersi, döndürülen ve istenen sonuç olan azaltılmayan bir versiyonudur .L

Çalışma zamanına gelince, öğe karşılaştırmalarını ve çalışma zamanlarını asimptotik olarak domine eden işlemleri listeleyelim. İkiden az uzunluk listeleri de neden olmaz. uzunluk listelerinde , yinelemeli çağrılar için girişlerin, özyinelemeli çağrıların kendileri artı döngü ve bir için girişlerin hazırlanmasından kaynaklanan bu işlemlere sahibiz . Her iki özyinelemeli parametrenin her biri en fazla liste işlemi ile hesaplanabilir . Döngü tam olarak yürütülür en fazla bir elemanı karşılaştırma zamanları ve her yineleme nedenlerini ve tam iki liste operasyonları. Final kullanmak için uygulanabilirn n 2 nn>1whilereversenwhilenreverse2nliste işlemleri - her eleman girişten çıkarılır ve çıkış listesine eklenir. Bu nedenle, işlem sayısı aşağıdaki yinelemeyi karşılar:

T(0)=T(1)=0T(n)T(n2)+T(n2)+7n

Olarak açık azalmayan, değerlendirmek yeterlidir; asimptotik büyüme için. Bu durumda , nüks basitleşirn = 2 kTn=2k

T(0)=T(1)=0T(n)2T(n2)+7n

Ana teorem ile, çalışma zamanına kadar uzanan da alırız .TΘ(nlogn)mergesort

Ultra düşük seviye

Mergesort'un Isabelle / HOL'daki bu (genelleştirilmiş) uygulamasını düşünün :

types dataset  =  "nat * string"

fun leq :: "dataset \<Rightarrow> dataset \<Rightarrow> bool" where
   "leq (kx::nat, dx) (ky, dy) = (kx \<le> ky)"

fun merge :: "dataset list \<Rightarrow> dataset list \<Rightarrow> dataset list" where
"merge [] b = b" |
"merge a [] = a" |
"merge (a # as) (b # bs) = (if leq a b then a # merge as (b # bs) else b # merge (a # as) bs)"

function (sequential) msort :: "dataset list \<Rightarrow> dataset list" where
  "msort []  = []" |
  "msort [x] = [x]" |
  "msort l   = (let mid = length l div 2 in merge (msort (take mid l)) (msort (drop mid l)))"
by pat_completeness auto
  termination
  apply (relation "measure length")
by simp+

Bu zaten iyi tanımlanmış ve feshedilmiş kanıtları da içermektedir. Burada (neredeyse) tam bir doğruluk kanıtı bulun .

"Çalışma zamanı", yani karşılaştırma sayısı için, önceki bölümdekine benzer bir yineleme ayarlanabilir. Master teoremini kullanmak ve sabitleri unutmak yerine, asemptotik olarak gerçek miktara eşit bir yaklaşım elde etmek için analiz edebilirsiniz. Analizin tamamını [1] 'de bulabilirsiniz; İşte kaba bir taslak (mutlaka Isabelle / HOL koduna uymuyor):

Yukarıdaki gibi, karşılaştırma sayısının tekrarlaması

f0=f1=0fn=fn2+fn2+en

burada , kısmi sonuçların birleştirilmesi için gerekli karşılaştırma sayısı²'dir. Zemin ve tavanlardan kurtulmak için eşit olup olmadığı konusunda bir vaka ayrımı yaparız : nenn

{f2m=2fm+e2mf2m+1=fm+fm+1+e2m+1

İç içe kullanma ileri / geri farklılıkları arasında ve bunu almake nfnen

k=1n1(nk)Δfk=fnnf1 .

Toplam, Perron formülünün sağ tarafıyla eşleşir . Bu tanımlar Dirichlet üreten serisi arasında olarakΔfk

W(s)=Σk1Δfkk-s=11-2-sΣk1Δekks=: (s)

Perron'un formülü ile birlikte bizi

fn=nf1+n2πben3-ben3+ben(s)ns(1-2-s)s(s+1)ds .

değerlendirilmesi hangi vakanın analiz edildiğine bağlıdır. Bunun dışında - bazı hilelerden sonra - elde etmek için kalıntı teoremini uygulayabiliriz(s)

fn~ngünlük2(n)+nbir(günlük2(n))+1

burada , daki değerlere sahip periyodik bir fonksiyondur .bir[-1,-0.9]


  1. Mellin dönüşümleri ve asimptotikler: Flajolet ve Golin tarafından yapılan birleşmenin tekrarlanması (1992)
  2. En iyi durum: En kötü durum: Ortalama vaka:en=n2
    en=n-1
    en=n-n2n2+1-n2n2+1

Çalışma zamanı analizi sorum, ve tam olarak nasıl belirlendiğidir , uygulamaya yakındır (örneğin, birleştirme sıralaması ve qsort'u karşılaştırmak mümkündür). αβT(n)=T(n/2)+T(n/2)+αn+β
Yai0Phah

@Frank: Kısa cevap Sen yapamazsın ; sabitler, temel algoritmaya önem vermeyen makine mimarisi, dil ve derleyici gibi uygulama ayrıntılarına bağlıdır.
JeffE

@JeffE Ben ve sadece bazı karşılaştırma yapmak için yeterince kesin olması gerektiğini iddia etmek zorunda . Daha kısaca, sabitleri belirlemek için makine dilleri olmadan çok fazla iş yapabilen bir matematiksel model . αβ
Yai0Phah

@JeffE, örneğin, taocp'deki MIX / MMIX, ancak bir algoritmayı böyle bir makine diline çevirmek çok zordur.
Yai0Phah

@FrankScience: Uygulamaya yaklaşmak için tüm işlemleri saymanız gerekir (Knuth'un yaptığı gibi). Daha sonra, gerçek çalışma zamanı elde etmek için sonucunuzu makineye özgü işlem maliyetleri ile başlatabilirsiniz (işlem sırasının sahip olabileceği etkileri göz ardı ederek, önbellekleme, boru hatları, ...). Genellikle, insanlar sadece bazı işlemleri sayar ve bu durumda ve sabitleme size çok şey anlatmaz. αβ
Raphael

3

Dijkstra'nın "Programlama disiplini" algoritmaları analiz etmek ve ispatlamak ve ispat için tasarım yapmakla ilgilidir. Bu kitabın önsözünde Dijkstra, analiz edilmesi için uygun şekilde tasarlanmış çok basit bir şekilde inşa edilmiş bir mini dilin birçok algoritmayı resmi olarak açıklamak için nasıl yeterli olduğunu açıklıyor:

Böyle bir kitaba başlarken derhal “Hangi programlama dilini kullanacağım?” Sorusuyla karşı karşıya kalırsınız ve bu değildir.sadece bir sunum sorusu! Herhangi bir aracın en önemli, ama aynı zamanda en zorlayıcı yönü, kullanımında kendilerini eğitenlerin alışkanlıkları üzerindeki etkisidir. Araç bir programlama diliyse, bu etki - ister beğenip beğenmeyelim - düşünme alışkanlıklarımız üzerinde bir etkidir. Bu etkiyi bilgim dahilinde analiz ettikten sonra, mevcut programlama dillerinden hiçbirinin veya alt kümesinin amacım için uygun olmadığı sonucuna vardım; Öte yandan, yeni bir programlama dilinin tasarımı için kendimi çoktan biliyordum ki önümüzdeki beş yıl boyunca bunu yapmama sözü verdim ve o dönemin henüz geçmediğine dair çok belirgin bir his vardı! (Bundan önce, diğer birçok şeyin yanında, bu monografinin yazılması gerekiyordu.

Daha sonra, mini dilini ne kadar küçük başardığını açıklıyor.

Okuyucuya mini dili neden bu kadar küçük tuttuğumun prosedürleri ve özyinelemeyi bile içermediğini açıklıyorum. ... Mesele şu ki, mesajımı iletmek için onlara ihtiyaç duymadım, yani. yüksek kaliteli programların tasarımı için endişelerin ayrılmasını ne kadar dikkatlice seçtiğini; mini dilin mütevazı araçları bize önemsiz, ancak çok tatmin edici tasarımlar için fazlasıyla yeterli enlem verdi.

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.