Gerektiğinde bir çözüme nasıl ulaştığına ilişkin bir açıklama veren algoritma modeli


14

Aşağıdaki senaryo bana birkaç kez oldu.

Belli bir sorunu çözen bir algoritma programladım. İyi çalışır ve doğru çözümleri bulur. Şimdi, algoritmaya "çözüme nasıl ulaştığınıza dair tam bir açıklama yazın" deme bir seçeneğim var. Amacım, çevrimiçi gösterilerde, öğretici sınıflarda vb. Kullanılacak iyi bir tasarım deseni nedir?

ÖRNEK: En büyük ortak böleni bulmak için bu yöntemi uyguladığımı varsayalım . Geçerli uygulanan yöntem, doğru bir yanıt verir, ancak açıklama içermez. Yöntem gibi eylemlerini açıklamak için bir seçenek var istiyorum:

Initially, a=6 and b=4. The number of 2-factors, d, is initialized to 0.
a and b are both even, so we divide them by 2 and increment d by 1.
Now, a=3 and b=2.
a is odd but b is even, so we divide b by 2.
Now, a=3 and b=1.
a and b are both odd, so we replace a by (a-b)/2 = 1.
Now, a=1 and b=1.
a=b, so the GCD is a*2^d = 2.

Çıktı, hem konsolda hem de web tabanlı uygulamalarda kolayca görüntülenebilecek şekilde döndürülmelidir.

Açıklama gerekmediğinde algoritmanın gerçek zamanlı performansını etkilemeden, gerektiğinde açıklama sağlamak için iyi bir model nedir?

Yanıtlar:


50

Aradığınız "kalıp", "günlük" olarak adlandırılır, günlük ifadelerini ihtiyacınız olduğu kadar ayrıntılı yapın. İyi bir günlük kaydı çerçevesi kullanarak, çalışma zamanında açıp kapatabilmeli, farklı ayrıntı düzeyi sağlayabilmeli veya çıktıyı farklı amaçlara (web ve konsol gibi) göre ayarlayabilmelisiniz.

Bunun kayda değer bir performans etkisi varsa (günlük kaydı kapalı olsa bile) büyük olasılıkla dile, çerçeveye ve belirli bir durumda ihtiyacınız olan günlük kaydı ifadelerinin sayısına bağlı olacaktır. Derlenmiş dillerde, bu gerçekten bir sorun haline gelirse, kodunuzun "günlüğe kaydetme varyantını" ve "günlüğe kaydetmeyen varyantını" oluşturmak için bir derleyici anahtarı sağlayabilirsiniz. Ancak, ilk önce ölçüm yapmadan "her ihtimale karşı" optimizasyona karşı şiddetle tavsiye ederim.


2
Günlük kaydı gibi açıp kapadığınız bir şey olmasa da, yorumlar ve kendi kendini belgeleyen kodun en azından "kendini açıklayan algoritma" hakkındaki bir soruda onurlu bir söz alması gerekir.
candied_orange

9
@CandiedSoru, özellikle içinde gerçek çalışma zamanı değerleri bulunan bir "açıklama" ister. Bu durumda yorumlar pek yardımcı olmaz.
16:54

@metacubed oh hadi. Günlüğe bir alternatif olduğunu söylemedim. Soru başlığına bakın ve buraya gelen trafiği düşünün.
candied_orange

4
@CandiedOrange: Bence soru başlığı yanıltıcı, bu şekilde yorumlanabileceği doğru, ama OP'nin istediği bu değil. Ama bunu düzeltmeme izin verin, başlığı düzenleyeceğim.
Doc Brown

1
Treelog gibi bir şeyin , işlev çağrılarının tam bir kaydını oluşturarak karmaşık hesaplamaları açıklayan çıktılar üretmek için özel olarak tasarlandığını unutmayın .
Örümcek Boris

7

İyi bir model Gözlemci'dir. https://en.wikipedia.org/wiki/Observer_pattern

Algoritmanızda, bir şey çıkarmak istediğiniz her noktada, bazı gözlemcilere bildirirsiniz. Daha sonra, metninizi konsolda çıktılamak veya HTML motoruna / Apache'ye göndermek için ne yapacaklarına karar verirler.

Programlama dilinize bağlı olarak, onu hızlı hale getirmenin farklı yolları olabilir. Örneğin, Java'da (kısalık için sahte kod olarak kabul edin; alıcılar, ayarlayıcılar ile "doğru" yapmak okuyucuya bırakılır):

interface AlgoLogObserver {
   public void observe(String message);
}

class AlgorithmXyz {   
   AlgoLogObserver observer = null;
   void runCalculation() {   
       if (observer!=null) { oberserver.observe("Hello"); }
       ...
   }   
}

...
algo = new AlgorithmXyz();
algo.observer = new ConsoleLoggingObserver();  // yes, yes make a 
                                               // setter instead, or use Ruby :-)
algo.runCalculation();

Bu biraz ayrıntılı, ancak kontrol ==nullolabildiğince hızlı olmalıdır.

(Not genel durumda olduğunu observermuhtemelen olurdu Vector observersyerine birden fazla gözlemci için izin vermek; bu sıra elbette ki mümkündür ve daha havai yol açmayacak; Yine ayarladığınız optimizasyonu koyabilirsiniz observers=nullbir kalmadan boş Vector.)

Elbette, neyi başarmak istediğinize bağlı olarak farklı türden gözlemciler uygularsınız. Ayrıca zamanlama istatistiklerini vb. Koyabilir veya başka süslü şeyler yapabilirsiniz.


5

Düz günlüğe kaydetmede küçük bir iyileştirme olarak, algoritmanın bir yürütülmesini modelleyen bir tür nesne oluşturun. Kodunuz her ilginç şey yaptığında bu kapsayıcı nesnesine bir "adım" ekleyin. Algoritmanın sonunda, biriken adımları kaptan günlüğe kaydedin.

Bunun birkaç avantajı vardır:

  1. Tam yürütmeyi tek bir günlük girişi olarak kaydedebilirsiniz, genellikle diğer iş parçacıklarının algo adımlarınız arasında bir şeyler kaydetme olasılığı olduğunda yararlıdır
  2. Bu sınıfın Java sürümünde (yalnızca "Hata Ayıklama" olarak adlandırılır), günlük girişleri olarak dizeler eklemezim , ancak dizeler üreten lambdalar eklerim . Bu lambda'lar yalnızca gerçek günlük kaydı gerçekleşirse, örneğin Debug nesnesi günlük düzeyinin şu anda etkin olduğunu tespit ederse değerlendirilir. Bu şekilde, günlük dizelerini gereksiz yere oluşturmanın performans yükü ortadan kalkar.

DÜZENLEME: Başkaları tarafından yorumlandığı gibi, lambdaların ek yükü vardır, bu nedenle bu ek yükün günlük dizesini oluşturmak için gereken kodun gereksiz değerlendirmesinden daha az olduğundan emin olmak için karşılaştırmanız gerekir (günlük girişleri genellikle basit değişmez değerler değildir, ancak katılan nesneler).


2
Tabii ki, lambdalar yaratma yükü var ...
Sergio Tulentsev

1
Sergio mantığını aydınlatır, ancak mantığınızın çılgınlığını tam olarak açıklamaz. Kütük dizeleri oluşturmanın performans yükü, lambdaları inşa etme yükünden daha düşük bir büyüklük sırasıdır . Burada çok kötü bir ödün
verdiniz

2
@Tyrsius: Bunu kanıtlayan güvenilir bir kriter var mı? (Bağlantı
kurduğunuz

1
@Tyrsius her şey belirli duruma bağlıdır. Size tartışmalı olarak daha alakalı bir karşı örnek de verebilirim . Dize sürümünün Runnable'dan daha yavaş bir büyüklük sırası olduğunu görebilirsiniz. Bu durum daha gerçekçi, çünkü bu soru bağlamında her zaman dizelerinizi dinamik olarak oluşturmak isteyeceksiniz. Bu her zaman Stringbuilder nesnelerinin oluşturulmasını gerektirirken Lambda ile sadece gerektiğinde (yani, oturum açma açıkken) oluşturulurlar.
jhyot

1
Lambdas'ın genel yükü var, kabul etti. Ancak, yayınlanan kıyaslama bu bağlamda tamamen önemsizdir. Algoritmaların günlüğe kaydedilmesi genellikle günlüğe kaydetme atlanmış olsaydı değerlendirilmeyen diğer kodların değerlendirilmesini içerir (katılımcı nesnelerden bağlamsal bilgi alınması, vb.). Lamdaların kaçındığı bu değerlendirmedir. Ama haklısın, yukarıdaki cevabım, lambda ek yükünün bu ek yükten daha az olduğunu varsayıyor, sürekli test etmediğim bir şey.
Cornel Masson

0

Genellikle dallanma ararım, yani if-ifadeleri ararım. Çünkü bunlar bir değeri değerlendirdiğimi gösterir, bu algoritmanın akışını kontrol eder. Bu gibi her durumda (her koşul), seçilen yolu ve neden seçildiğini kaydedebilirim.

Bu yüzden temelde giriş değerlerini (başlangıç ​​durumu), seçilen her dalı (koşullu) ve seçilen dalı (geçici durum) girerken değerleri kaydederim.


1
sorulan bu bile hakkında açıklamalar vardır algoritmasının gerçek zamanlı performansı incitmiyorum, soruyu ele almak denemez değil gerekli
tatarcık

Soruyu bundan daha genel olarak aldım ve bir tasarım düzeyinde cevapladım. Ancak bu bir endişe kaynağıysa, günlüğe yazdırmak isteyip istemediğinizi ayarlamak için koşullu bir bayrak ekleyin. Başlatma sırasında bu bayrağı bir parametre olarak ayarlayın.
Richard Tyregrim
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.