Ne gerçek dünya bir özyinelemeli yaklaşım derinliğine arama (DFS) yanında doğal çözümdür sorunlar?
( Tower of Hanoi , Fibonacci sayısı veya faktöryel gerçek dünya problemlerini düşünmüyorum . Aklımda biraz uydurulmuşlar.)
Ne gerçek dünya bir özyinelemeli yaklaşım derinliğine arama (DFS) yanında doğal çözümdür sorunlar?
( Tower of Hanoi , Fibonacci sayısı veya faktöryel gerçek dünya problemlerini düşünmüyorum . Aklımda biraz uydurulmuşlar.)
Yanıtlar:
Burada pek çok matematik örneği var, ancak gerçek bir dünya örneği istediniz , bu yüzden biraz düşünerek, muhtemelen sunabileceğim en iyisi bu:
Belirli bir bulaşıcı enfeksiyon kapmış, ölümcül olmayan ve kendini hızlı bir şekilde düzelten (Tip A) bir kişi buluyorsunuz, (Bu tip B olarak adlandıracağız) 5 kişiden biri hariç ve bu hastalığa kalıcı olarak bulaşan semptomlar ve sadece bir yayıcı görevi görür.
Bu, B tipi çok sayıda A tipini etkilediğinde oldukça can sıkıcı tahribat dalgaları yaratır.
Göreviniz, tüm B tiplerinin izini sürmek ve hastalığın omurgasını durdurmak için onları aşılamak. Ne yazık ki, herkese ülke çapında bir tedavi uygulayamazsınız, çünkü tipA olan insanlar aynı zamanda B tipi için işe yarayan tedaviye ölümcül alerjiktirler.
Bunu yapmanın yolu, enfekte bir kişi (Tip A) verildiğinde sosyal keşif olacaktır, geçen hafta tüm bağlantılarını seçip her bir kişiyi bir yığın üzerinde işaretleyin. Bir kişiye virüs bulaştığını test ettiğinizde, onu "takip" sırasına ekleyin. Bir kişi B tipi olduğunda, onu baştaki "takip" e ekleyin (çünkü bunu hızlı bir şekilde durdurmak istersiniz).
Belirli bir kişiyi işledikten sonra, sıranın önünden kişiyi seçin ve gerekirse aşı uygulayın. Daha önce ziyaret edilmemiş tüm kişilerini alın ve ardından virüs bulaşıp bulaşmadığını test edin.
Enfekte kişilerin sırası 0 olana kadar tekrarlayın ve ardından başka bir salgın bekleyin.
(Tamam, bu biraz yinelemelidir, ancak yinelemeli bir sorunu çözmenin yinelemeli bir yolu, bu durumda, bir nüfus tabanının enine ilk geçişi, sorunlara olası yolları keşfetmeye çalışır ve ayrıca yinelemeli çözümler genellikle daha hızlı ve daha etkilidir ve özyinelemeyi her yerde zorunlu olarak kaldırıyorum, o kadar içgüdüsel hale geliyor ki ... kahretsin!)
Dosya sistemindeki bir dizin yapısını içeren herhangi bir şeye ne dersiniz? Özyinelemeli olarak dosya bulma, dosyaları silme, dizinler oluşturma vb.
Burada, bir dizinin ve alt dizinlerinin içeriğini yinelemeli olarak yazdıran bir Java uygulaması verilmiştir.
import java.io.File;
public class DirectoryContentAnalyserOne implements DirectoryContentAnalyser {
private static StringBuilder indentation = new StringBuilder();
public static void main (String args [] ){
// Here you pass the path to the directory to be scanned
getDirectoryContent("C:\\DirOne\\DirTwo\\AndSoOn");
}
private static void getDirectoryContent(String filePath) {
File currentDirOrFile = new File(filePath);
if ( !currentDirOrFile.exists() ){
return;
}
else if ( currentDirOrFile.isFile() ){
System.out.println(indentation + currentDirOrFile.getName());
return;
}
else{
System.out.println("\n" + indentation + "|_" +currentDirOrFile.getName());
indentation.append(" ");
for ( String currentFileOrDirName : currentDirOrFile.list()){
getPrivateDirectoryContent(currentDirOrFile + "\\" + currentFileOrDirName);
}
if (indentation.length() - 3 > 3 ){
indentation.delete(indentation.length() - 3, indentation.length());
}
}
}
}
Hızlı sıralama , birleştirme sıralaması ve diğer çoğu N-log N sıralaması .
Matt Dillard'ın örneği iyidir. Daha genel olarak, bir ağacın herhangi bir yürüyüşü genellikle özyineleme ile çok kolay bir şekilde gerçekleştirilebilir. Örneğin, ayrıştırma ağaçlarını derlemek, XML veya HTML üzerinde yürümek vb.
Özyineleme genellikle Backtracking algoritmasının uygulamalarında kullanılır . Bunun "gerçek dünya" uygulaması için, bir Sudoku çözücüsüne ne dersiniz ?
Özyineleme, bir problemi alt problemlere bölerek çözülebildiğinde uygundur, bu problemleri çözmek için aynı algoritmayı kullanabilirler. Ağaçlar ve sıralı listeler üzerindeki algoritmalar doğal bir uyum sağlar. Hesaplamalı geometride (ve 3B oyunlarda) birçok sorun, ikili uzay bölümleme (BSP) ağaçları, yağ alt bölümleri veya dünyayı alt bölümlere ayırmanın diğer yolları kullanılarak yinelemeli olarak çözülebilir .
Yineleme, bir algoritmanın doğruluğunu garanti etmeye çalışırken de uygundur. Değişmez girdiler alan ve girdilerdeki özyinelemeli ve özyinelemeli olmayan çağrıların bir kombinasyonu olan bir sonuç döndüren bir işlev verildiğinde, matematiksel tümevarımı kullanarak işlevin doğru (veya değil) olduğunu kanıtlamak genellikle kolaydır. Bunu yinelemeli bir işlevle veya mutasyona uğrayabilecek girdilerle yapmak çoğu zaman zorludur. Bu, finansal hesaplamalarla ve doğruluğun çok önemli olduğu diğer uygulamalarla uğraşırken yararlı olabilir.
Elbette, oradaki birçok derleyici özyinelemeyi yoğun bir şekilde kullanıyor. Bilgisayar dilleri doğaları gereği özyinelemelidir (yani, 'if' ifadelerini diğer 'if' ifadelerinin içine gömebilirsiniz, vb.).
Bir kapsayıcı denetimindeki tüm alt denetimler için salt okunur devre dışı bırakma / ayarlama. Bunu yapmam gerekiyordu çünkü bazı çocukların kontrolleri kaplardı.
public static void SetReadOnly(Control ctrl, bool readOnly)
{
//set the control read only
SetControlReadOnly(ctrl, readOnly);
if (ctrl.Controls != null && ctrl.Controls.Count > 0)
{
//recursively loop through all child controls
foreach (Control c in ctrl.Controls)
SetReadOnly(c, readOnly);
}
}
(kaynak: mit.edu )
İşte eval'un tanımı:
(define (eval exp env)
(cond ((self-evaluating? exp) exp)
((variable? exp) (lookup-variable-value exp env))
((quoted? exp) (text-of-quotation exp))
((assignment? exp) (eval-assignment exp env))
((definition? exp) (eval-definition exp env))
((if? exp) (eval-if exp env))
((lambda? exp)
(make-procedure (lambda-parameters exp)
(lambda-body exp)
env))
((begin? exp)
(eval-sequence (begin-actions exp) env))
((cond? exp) (eval (cond->if exp) env))
((application? exp)
(apply (eval (operator exp) env)
(list-of-values (operands exp) env)))
(else
(error "Unknown expression type - EVAL" exp))))
Uygulamanın tanımı şöyledir:
(define (apply procedure arguments)
(cond ((primitive-procedure? procedure)
(apply-primitive-procedure procedure arguments))
((compound-procedure? procedure)
(eval-sequence
(procedure-body procedure)
(extend-environment
(procedure-parameters procedure)
arguments
(procedure-environment procedure))))
(else
(error
"Unknown procedure type - APPLY" procedure))))
İşte eval-sequence'in tanımı:
(define (eval-sequence exps env)
(cond ((last-exp? exps) (eval (first-exp exps) env))
(else (eval (first-exp exps) env)
(eval-sequence (rest-exps exps) env))))
eval
-> apply
-> eval-sequence
->eval
İnsanlar genellikle yinelemeli bir yöntem kullanarak belge yığınlarını sıralar. Örneğin, üzerinde isimler bulunan 100 belgeyi sıraladığınızı hayal edin. Önce belgeleri ilk harfe göre yığınlara yerleştirin, ardından her yığını sıralayın.
Sözlükteki kelimelerin aranması genellikle ikili arama benzeri, yinelemeli bir teknikle gerçekleştirilir.
Organizasyonlarda patronlar genellikle departman başkanlarına komutlar verir, onlar da yöneticilere komutlar verir vb.
Özyineleme, onu daha küçük parçalara bölebileceğiniz (azaltabileceğiniz) ve her parçanın / parçaların orijinal soruna benzer göründüğü sorunlara (durumlara) uygulanır.
Kendine benzer daha küçük parçalar içeren şeylerin iyi örnekleri şunlardır:
Özyineleme, problemi daha küçük parçalara ayırmaya devam eden bir tekniktir, bu parçalardan biri çocuk oyuncağı olacak kadar küçük hale gelene kadar. Tabii ki, onları ayırdıktan sonra, orijinal probleminize tam bir çözüm oluşturmak için sonuçları doğru sırada "birleştirmeniz" gerekir.
Bazı yinelemeli sıralama algoritmaları, ağaçta gezinme algoritmaları, eşleme / azaltma algoritmaları, böl ve yönet bu tekniğin tüm örnekleridir.
Bilgisayar programlamasında, yığın tabanlı arama-dönüş tipi dillerin çoğu, özyineleme için yerleşik yeteneklere sahiptir:
Bir durum makinesini simüle etmek için birkaç yerde saf kuyruk özyinelemesini kullanan bir sistemim var .
İşlevsel programlama dillerinde bazı harika özyineleme örnekleri bulunur . İşlevsel programlama dillerinde ( Erlang , Haskell , ML / OCaml / F # , vb.), Herhangi bir liste işlemenin özyineleme kullanması çok yaygındır.
Tipik zorunlu OOP tarzı dillerdeki listelerle uğraşırken, bağlantılı listeler ([öğe1 -> öğe2 -> öğe3 -> öğe4]) olarak uygulanan listeleri görmek çok yaygındır. Bununla birlikte, bazı işlevsel programlama dillerinde, listelerin kendilerinin yinelemeli olarak uygulandığını, listenin "başının" listedeki ilk öğeye işaret ettiğini ve "kuyruk" da öğelerin geri kalanını içeren bir listeyi gösterdiğini görüyorsunuz ( [öğe1 -> [öğe2 -> [öğe3 -> [öğe4 -> []]]]]). Bence oldukça yaratıcı.
Listelerin bu şekilde ele alınması, kalıp eşleştirmeyle birleştirildiğinde ÇOK güçlüdür. Diyelim ki bir sayı listesi toplamak istiyorum:
let rec Sum numbers =
match numbers with
| [] -> 0
| head::tail -> head + Sum tail
Bu, esasen "eğer boş bir listeyle çağrıldıysak 0 döndür" (özyinelemeyi kırmamıza izin verir) der, aksi halde head değerini + kalan öğelerle çağrılan Sum değerini (dolayısıyla özyinelememiz) döndürür.
Örneğin, bir URL listesine sahip olabilirim , sanırım her URL'nin bağlantı verdiği tüm URL'leri ayırıyorum ve ardından bir sayfa için "değerler" oluşturmak için tüm URL'lere giden / gelen toplam bağlantı sayısını azaltıyorum (Google'ın PageRank ile birlikte alır ve orijinal MapReduce belgesinde tanımlanmış olarak bulabilirsiniz ). Bunu bir belgedeki kelime sayıları oluşturmak için de yapabilirsiniz. Ve çok, çok, çok başka şeyler de.
Bu işlevsel modeli, herhangi bir tür MapReduce koduna genişletebilirsiniz ; burada bir şeyin bir listesini alabilir, onu dönüştürebilir ve başka bir şeyi geri döndürebilirsiniz (ister başka bir liste, ister listedeki bir zip komutu olsun).
XML veya ağaç olan herhangi bir şeyin üzerinden geçmek. Dürüst olmak gerekirse, işimde neredeyse hiç özyineleme kullanmıyorum.
Hiyerarşik bir organizasyonda geri bildirim döngüleri.
Üst düzey patron, üst düzey yöneticilere şirketteki herkesten geri bildirim almalarını söyler.
Her yönetici, doğrudan raporlarını toplar ve onlara doğrudan raporlarından geri bildirim almalarını söyler.
Ve hattın aşağısında.
Doğrudan raporları olmayan insanlar - ağaçtaki yaprak düğümleri - geri bildirimde bulunur.
Geri bildirim, her yönetici kendi geri bildirimini ekleyerek ağacın yukarısına gider.
Sonunda tüm geri bildirimler onu en üst patrona geri götürür.
Bu doğal bir çözümdür, çünkü özyinelemeli yöntem her seviyede filtrelemeye izin verir - kopyaların harmanlanması ve saldırgan geri bildirimlerin kaldırılması. Üst patron olabilir küresel e-posta göndermek ve doğrudan onu geri / ona her çalışanın raporu geribildirim var, ama orada tekrarlama iyi burada çalışan böylece, ve "kovuldun" sorunları "gerçeği işleyemez".
Sayfalarınızın bir ağaç yapısında olduğu bir web sitesi için bir CMS oluşturduğunuzu ve diyelim ki kökün ana sayfa olduğunu varsayalım.
Ayrıca {kullanıcı | müşteri | müşteri | patronunuzun}, ağaçta nerede olduğunuzu göstermek için her sayfaya bir kırıntı izi yerleştirmenizi istediğini varsayalım.
Herhangi bir n sayfası için, sayfa ağacının köküne geri dönen düğümlerin bir listesini oluşturmak için özyinelemeli olarak n'nin ebeveynine ve üstüne gitmek isteyebilirsiniz.
Elbette, bu örnekte db'yi sayfa başına birkaç kez vuruyorsunuz, bu nedenle, page-table'i a olarak ve page-table'i tekrar b olarak gördüğünüz ve a.id ile b.parent, böylece veritabanının yinelemeli birleştirmeleri yapmasını sağlarsınız. Uzun zaman oldu, bu yüzden sözdizimim muhtemelen yardımcı olmuyor.
Sonra tekrar, bunu yalnızca bir kez hesaplamak ve bunu sayfa kaydıyla saklamak, yalnızca sayfayı taşırsanız güncellemek isteyebilirsiniz. Bu muhtemelen daha verimli olur.
Neyse, bu benim 0,02 dolarım
Benim işimde ağaç olarak tanımlanabilecek genel veri yapısına sahip bir sistemimiz var. Bu, özyinelemenin verilerle çalışmak için çok etkili bir teknik olduğu anlamına gelir.
Özyineleme olmadan çözmek, çok fazla gereksiz kod gerektirir. Özyineleme ile ilgili sorun, ne olduğunu takip etmenin kolay olmamasıdır. Yürütme akışını takip ederken gerçekten konsantre olmalısınız. Ancak çalıştığında kod zarif ve etkilidir.
Windows Forms veya WebForms'da (.NET Windows Forms / ASP.NET ) bir denetim ağacını ayrıştırma .
Bildiğim en iyi örnek hızlı sıralama , özyinelemeyle çok daha basit. Şuna baksana:
shop.oreilly.com/product/9780596510046.do
www.amazon.com/Beautiful-Code-Leading-Programmers-Practice/dp/0596510047
(3. bölümdeki ilk alt başlığa tıklayın: "Yazdığım en güzel kod").
Telefon ve kablo şirketleri, aslında büyük bir ağ veya grafik olan kablolama topolojilerinin bir modelini korurlar. Özyineleme, tüm üst öğeleri veya tüm alt öğeleri bulmak istediğinizde bu modeli çaprazlamanın bir yoludur.
Özyineleme, işleme ve bellek açısından pahalı olduğu için, bu adım genellikle yalnızca topoloji değiştirildiğinde ve sonuç değiştirilmiş bir ön-sıralı liste formatında saklandığında gerçekleştirilir.
Derleyiciler hakkındaki yorumu aynen yapın. Soyut sözdizimi ağaç düğümleri doğal olarak kendilerini özyinelemeye borçludur. Tüm özyinelemeli veri yapıları (bağlantılı listeler, ağaçlar, grafikler vb.) Özyinelemeyle daha kolay işlenir. Çoğumuzun gerçek dünya sorunları nedeniyle okuldan çıktıktan sonra özyinelemeyi çok fazla kullanamayacağımızı düşünüyorum, ancak bunun bir seçenek olarak farkında olmak iyi.