Faktörsüz özyineleme, Fibonacci sayıları vb.


47

Özyineleme ile ilgili bulabildiğim hemen hemen her makale, faktoring veya Fibonacci Sayılarının örneklerini içerir:

  1. Matematik
  2. Gerçek hayatta işe yaramaz

Bazı ilginç olmayan matematik var mıdır kod öğretme özyineleme örnekler?

Böl-ve-fet et algoritmalarını düşünüyorum ama genellikle karmaşık veri yapılarını içerirler.


26
Sorunuz tamamen geçerli olsa da, Fibonacci numaralarını gerçek hayatta işe yaramaz olarak aramakta tereddüt ediyorum . Aynı için de geçerli faktöriyele .
Zach L

2
Küçük Schemer, Fact veya Fib'i asla kullanmayan özyinelemeyle ilgili bir kitap. junix-linux-config.googlecode.com/files/…
Eric Wilson

5
@Zach: Öyle olsa bile, özyineleme, üstel çalışma süresi nedeniyle Fibonacci sayılarını uygulamak için korkunç bir yoldur .
dan04

2
@ dan04: Özyineleme, çoğu dilde yığın taşması olasılığı nedeniyle neredeyse her şeyi uygulamanın korkunç bir yoludur.
R.

5
Diliniz kuyruk çağrısı optimizasyonunu en işlevsel diller gibi uygulayabilecek kadar akıllı olmadığı sürece @ dan04, bu durumda çok iyi çalışır
Zachary K

Yanıtlar:


107

Dizin / Dosya yapıları özyinelemenin en iyi örneğidir, çünkü herkes başlamadan önce bunları anlar, ancak ağaç benzeri yapıları içeren herhangi bir şey yapacaktır.

void GetAllFilePaths(Directory dir, List<string> paths)
{
    foreach(File file in dir.Files)
    {
        paths.Add(file.Path);
    }

    foreach(Directory subdir in dir.Directories)
    {
        GetAllFilePaths(subdir, paths)
    }
}

List<string> GetAllFilePaths(Directory dir)
{
    List<string> paths = new List<string>();
    GetAllFilePaths(dir, paths);
    return paths;
}

1
Teşekkürler, dosya sistemiyle gideceğimi düşünüyorum. Somut bir şey ve birçok gerçek dünya örneği için kullanılabilir.
synapse

9
Not: unix komutu genellikle -r seçeneğini kaldırır (örnek için cp veya rm). -r özyinelemede durmak.
deadalnix 13:11

7
Eğer katılır ve yaşları vb sert bağlantılar oluşturabilir dosya sistemi tarafından destekleniyorsa dosya sistemleri, mutlaka aslında bir ağaç yönlendirilmiş grafiği olan gerçek dünyada olduğu gibi burada biraz dikkatli olmak zorunda
jk.

1
jk: Dizinler birbirleriyle bağlantılı olamaz, bu yüzden birden fazla yerde görünebilecek bazı yaprakları modüle edin ve sembolik işaretleri dışladığınızı varsayarsak, gerçek dünya dosya sistemleri ağaçtır.
R.

1
bazı dosya sistemlerinde, dizinler için NTFS reparse noktaları gibi başka özellikler de vardır. Demek istediğim, bunun farkında olmayan kodun gerçek dünya dosya sistemlerinde beklenmeyen sonuçlara yol açabileceği
jk.

51

Ağaç yapılarını içeren şeyleri araştırın. Bir ağacın kavranması nispeten kolaydır ve özyinelemeli bir çözümün güzelliği, listeler gibi doğrusal veri yapılarına göre çok daha kısa sürede ortaya çıkar.

Düşünecek şeyler:

  • dosya sistemleri - bunlar temel olarak ağaçlardır; güzel bir programlama görevi tüm .jpg resimlerini belirli bir dizinin altına ve alt dizinlerine getirmek olacaktır.
  • ata - bir aile ağacı verildiğinde, ortak bir ata bulmak için yukarı yürümek zorunda olduğunuz kuşak sayısını bulun; veya ağaçtaki iki kişinin aynı nesle ait olup olmadığını kontrol edin; veya ağaçtaki iki kişinin yasal olarak evlenip evlenemeyeceğini kontrol edin (yargı yetkisine bağlıdır :)
  • HTML benzeri belgeler - belgenin seri (metin) gösterimi ile DOM ağacı arasında dönüştürme; Bir DOM'nin alt kümelerinde işlemler gerçekleştirme (belki bir xpath alt kümesini bile uygulayabilir?); ...

Bunların hepsi gerçek gerçek dünya senaryolarıyla ilgilidir ve hepsi gerçek dünyaya önem veren uygulamalarda kullanılabilir.


Elbette, kendi ağaç yapınızı tasarlama özgürlüğüne sahip olduğunuzda, işaretçileri / referansları ebeveyne / bir sonraki kardeşe / vb. Tutmaktan her zaman daha iyidir. düğümlerde böylece özyineleme olmadan ağaç üzerinde yinelenebilir.
R.

1
İşaretçilerin bununla ne ilgisi var? İlk çocuğa, bir sonraki kardeşine ve ebeveyni için işaretçileriniz olsa bile, yine de bir şekilde ağaçlarınızdan yürümek zorundasınız ve bazı durumlarda özyineleme en uygun yoldur.
tdammers 14:11

40

https://stackoverflow.com/questions/105838/real-world-examples-of-recursion

  • bulaşıcı bir enfeksiyonun modellenmesi
  • üretim geometrisi
  • rehber yönetimi
  • sınıflandırma

https://stackoverflow.com/questions/2085834/how-did-you-practically-use-recursion

  • Işın izleme
  • satranç
  • kaynak kodu ayrıştırma (dil bilgisi)

https://stackoverflow.com/questions/4945128/what-is-a-good-example-of-recursion-other-than-generating-a-fibonacci-sequence

  • BST araması
  • Hanoi Kuleleri
  • palindrome arama

https://stackoverflow.com/questions/126756/examples-of-recursive-functions

  • Bir yatmadan önce hikaye özyinelemesini gösteren güzel bir İngilizce dil hikayesi verir.

10
Bu teorik olarak soruya cevap görülebilir fakat tercih edildiğini burada bu soruların ve cevapların temel parçalarını kapsadığı ve başvuru için bağlantılar sağlar. Sorular SO'dan çıkarılırsa, cevabınız tamamen işe yaramaz olacaktır.
Adam Lear

@Anna, Kullanıcılar sorularını silemezler, bu yüzden ne kadar muhtemel?
vemv

4
@vemv Silme oyları, moderatörler, konuyla ilgili değişiklikler hakkında kurallar ... olabilir. Her iki durumda da, burada daha eksiksiz bir cevap almak, yarasadaki dört farklı sayfaya bir ziyaretçi göndermekten daha uygun olacaktır.
Adam Lear

@Anna: Bu düşünme sırasının ardından, "kesin kopya" olarak kapatılan her soru, yapıştırılan orijinalin cevabına sahip olmalıdır. Programcılar hakkındaki soruların kopyası?
SF.

1
@SF Eğer kopya olarak kapatabilirsek, yapardık, ancak siteler arası kopyalar desteklenmiyor. Programcılar ayrı bir sitedir, bu nedenle ideal olarak yanıtlar, tamamen temsilci olarak değil, SO'yu başka bir referans olarak kullanır. Sadece "cevabınız bu kitapta" demekten farklı değil - teknik olarak doğru, ancak referansa danışmadan hemen kullanılamaz.
Adam Lear

22

İşte aklıma gelen bazı pratik problemler:

  • Sıralama Birleştir
  • Ikili arama
  • Ağaçlarda Geçiş, Yerleştirme ve Kaldırma (büyük ölçüde veritabanı uygulamalarında kullanılır)
  • Permütasyon üreteci
  • Sudoku çözücü (geri izleme ile)
  • Yazım denetimi (tekrar izleme ile)
  • Sözdizimi analizi (.eg, ön eki postfix notasyonuna dönüştüren bir program)

11

QuickSort, akla ilk gelen olabilir. İkili arama da özyinelemeli bir sorundur. Bunun ötesinde, özyineleme ile çalışmaya başladığınızda çözümlerin neredeyse ücretsiz olarak ortaya çıktığı bütün problem sınıfları vardır.


3
İkili arama genellikle özyinelemeli bir sorun olarak formüle edilir, ancak zorunlu bir şekilde uygulanması önemsizdir (ve genellikle tercih edilir).
kabarık

Hangi dili kullandığınıza bağlı olarak, kod açıkça özyinelemeli veya zorunlu veya özyinelemeli olabilir veya olmayabilir. Ancak yine de özyinelemeli bir algoritmadır, çünkü sorunu çözmek için sorunu daha küçük ve daha küçük parçalara bölüyorsunuz.
Zachary K

2
Zachary: Kuyruk özyinelemeli (ikili arama gibi) uygulanabilecek algoritmalar, temel özyinelemeyi gerektirenlardan (veya eşit derecede pahalı alan gereksinimli kendi durum yapılarınızı) temelden farklı bir uzay sınıfındadır. Aynı şeymiş gibi birlikte öğretilmelerinin faydalı olacağını sanmıyorum.
R.

8

Python'da özyinelemeli olarak tanımlanmış sıralama.

def sort( a ):
    if len(a) == 1: return a
    part1= sort( a[:len(a)//2] )
    part2= sort( a[len(a)//2:] )
    return merge( part1, part2 )

Yinelemeli olarak tanımlanmış birleştirme.

def merge( a, b ):
    if len(b) == 0: return a
    if len(a) == 0: return b
    if a[0] < b[0]:
        return [ a[0] ] + merge(a[1:], b)
    else:
        return [ b[0] ] + merge(a, b[1:]) 

Özyinelemeli olarak tanımlanan doğrusal arama.

def find( element, sequence ):
    if len(sequence) == 0: return False
    if element == sequence[0]: return True
    return find( element, sequence[1:] )

Tekrarlı olarak tanımlanmış ikili arama.

def binsearch( element, sequence ):
    if len(sequence) == 0: return False
    mid = len(sequence)//2
    if element < mid: 
        return binsearch( element, sequence[:mid] )
    else:
        return binsearch( element, sequence[mid:] )

6

Bir anlamda, özyineleme, bölünme ve fethetme ile ilgilidir, basit bir problem için çözümü bulmaya yardımcı olmak için problem alanını daha küçük bir alana çeker ve daha sonra normalde doğru cevabı oluşturmak için orijinal problemi yeniden inşa etmeye devam eder.

Özyinelemeyi öğretmek için matematiği içermeyen bazı örnekler (en azından üniversite yıllarımdan hatırladığım problemler):

Bunlar sorunu çözmek için Geri Taramayı kullanma örnekleridir.

Diğer problemler Yapay Zeka alanının klasikleridir: İlk Derinlikli Aramayı Kullanma, yol bulma, planlama.

Bütün bu problemler bir çeşit "karmaşık" veri yapısını içerir, fakat matematik (sayılar) ile öğretmek istemiyorsanız, seçimleriniz daha sınırlı olabilir. Yoy, bağlantılı bir Liste gibi temel bir veri yapısıyla öğretime başlamak isteyebilir. Örneğin, bir Liste kullanarak doğal sayıları temsil etmek için:

0 = boş liste 1 = bir düğümlü liste. 2 = 2 düğümlü liste. ...

sonra iki sayının toplamını aşağıdaki gibi bu veri yapısına göre tanımlayın: Boş + N = N Düğüm (X) + N = Düğüm (X + N)


5

Hanoi Kuleleri, özyinelemeyi öğrenmeye yardımcı olacak iyi bir kulübe sahiptir.

İnternette pek çok farklı dilde birçok çözüm var.


3
Bu aslında benim görüşüme göre başka bir kötü örnek. Öncelikle, gerçekçi değil; Bu aslında insanların sahip olduğu bir sorun değil. İkincisi, özyinelemeli olmayan kolay çözümler var. (Birincisi: diskleri numaralandırın. Bir diski asla aynı paritedeki bir diske götürmeyin ve yaptığınız son hareketi asla geri almayın. Bu iki kurala uyarsanız, bulmacayı en uygun çözümle çözersiniz. )
Eric Lippert

5

Bir Palindrome Dedektörü:

Bir dizeyle başlayın: "ABCDEEDCBA" Başlangıç ​​ve bitiş karakterleri eşitse, tekrarlayın ve "BCDEEDCB" vb. İşaretleyin.


6
Aynı zamanda özyinelemeden çözülmesi ve IMHO, onsuz daha iyi çözülmesi çok önemlidir.
Blrfl 13:11

3
Kabul edildi, ancak OP Özellikle veri yapılarının minimum kullanımı ile öğretim örnekleri istedi.
NWS

5
Öğrencilerinizin özyinelemeli olmayan bir çözümü hemen düşünmeleri iyi bir öğretme örneği değildir. Örneğin, örneğinizin "Bir döngüle ilgisi olmayan bir şey var. Şimdi size bariz bir neden olmadan size zor bir yol göstereceğim."
Monica


4

Fonksiyonel programlama dillerinde, üst düzey fonksiyonlar olmadığında, değişken durumdan kaçınmak için zorunlu döngüler yerine özyineleme kullanılır.

F #, her iki stile de izin veren saf bir işlevsel dildir, bu yüzden her ikisini de burada karşılaştırabilirim. Aşağıdaki bir listedeki tüm sayıları toplar.

Değişken Değişkenli Emperatif Döngü

let xlist = [1;2;3;4;5;6;7;8;9;10]
let mutable sum = 0
for x in xlist do
    sum <- sum + x

Değişken Devleti Olmayan Özyinelemeli Döngü

let xlist = [1;2;3;4;5;6;7;8;9;10]
let rec loop sum xlist = 
    match xlist with
    | [] -> sum
    | x::xlist -> loop (sum + x) xlist
let sum = loop 0 xlist

Toplanmasının bu tür geldiğini hatırlatırız edilir yüksek mertebeden fonksiyonu yakalanan List.foldgibi yazılmış olabilir List.fold (+) 0 xlistveya aslında daha basit kolaylık fonksiyonu ile List.sumtıpkı List.sum xlist.


benden sadece + 1'den daha fazla puan hak ediyorsun. Özyineleme olmadan F # çok sıkıcı olurdu, bu SADECE özyinelemeden hiçbir döngü yapıları olmayan Haskell için daha da doğrudur!
schoetbi

3

Oyunda AI özyinelemeyi yoğun olarak kullandım. C ++ 'da yazarken, birbirlerini sırayla çağıran yaklaşık 7 fonksiyondan oluşan bir seri kullandım (ilk fonksiyon tüm bunları atlamak için bir seçeneğe sahip ve bunun yerine 2 fonksiyon daha bir zincir çağırıyor). Her iki zincirdeki son işlev, aramak istediğim kalan derinliğe kadar tekrar ilk işlevi çağırdı, bu durumda son işlev değerlendirme işlevimi çağıracak ve konumun puanını döndürecektir.

Çoklu fonksiyonlar, oyuncu kararlarına veya oyundaki rastgele olaylara dayanarak kolayca dalmama izin verdi. Yapabildiğim zaman referans referansını kullanırdım, çünkü çok büyük veri yapılarının etrafından dolaşıyordum, ancak oyunun nasıl yapılandırıldığından dolayı, aramamda bir "geri alma hareketi" yapmak çok zordu. Orijinal verilerimi değiştirmemek için bazı işlevlerde parola değeri kullanırım. Bu nedenle, özyinelemeli bir yaklaşım yerine döngü temelli bir yaklaşıma geçmenin çok zor olduğu ortaya çıktı.

Bu tür bir programın ana hatlarını görebilirsiniz, bkz. Https://secure.wikimedia.org/wikipedia/en/wiki/Minimax#Pseudocode


3

İş dünyasında gerçekten iyi bir gerçek hayat örneği "Malzeme Listesi" olarak adlandırılan bir şeydir. Bu, bitmiş bir ürünü oluşturan tüm bileşenleri temsil eden veridir. Örneğin, bir Bisiklet kullanalım. Bir Bisikletin gidonları, tekerlekleri, çerçevesi vb. Vardır. Bu bileşenlerin her birinin alt bileşenleri olabilir. örneğin Tekerleğin konuşmacıya, bir valf gövdesine, vs. sahip olabilir.

Şimdi malzeme listesi ile ilgili herhangi bir toplu bilgiyi sorgulamak veya malzeme listesi içindeki öğeleri değiştirmek için genellikle yinelemeye başvurduğunuzda.

    class BomPart
    {
        public string PartNumber { get; set; }
        public string Desription { get; set; }
        public int Quantity { get; set; }
        public bool Plastic { get; set; }
        public List<BomPart> Components = new List<BomPart>();
    }

Ve örnek bir özyinelemeli çağrı ...

    static int ComponentCount(BomPart part)
    {
        int subCount = 0;
        foreach(BomPart p in part.Components)
            subCount += ComponentCount(p);
        return part.Quantity * Math.Max(1,subCount);

    }

Açıkçası, BomPart Sınıfının çok daha fazla alanı olacaktı. Ne kadar plastik parçaya sahip olduğunuzu, tam bir parça oluşturmak için ne kadar emek harcayacağınızı vb. Bulmanız gerekebilir. Bütün bunlar, bir ağaç yapısındaki özyinelemenin yararına geri döner.


Bir malzeme listesi bir ağaç yerine yönlendirilmiş bir ızgara olabilir, örneğin aynı vida türü bir bileşenden daha fazlası tarafından kullanılabilir.
Ian

-1

Aile ilişkileri iyi örnekler veriyor çünkü herkes onları sezgisel olarak anlıyor:

ancestor(joe, me) = (joe == me) 
                    OR ancestor(joe, me.father) 
                    OR ancestor(joe, me.mother);

bu kod hangi dilde yazılmıştır?
törzsmókus

@ törzsmókus Belirli bir dil yok. Sözdizimi oldukça yakın C, Obj C, C ++, Java ve birçok diğer dillere, ancak gerçek kod isterseniz gibi uygun bir operatör yerine gerekebilir ||için OR.
Caleb

-1

Oldukça işe yaramaz, ancak özyinelemeli bir iç çalışmanın iyi olduğunu gösteren özyinelemelidir strlen():

size_t strlen( const char* str )
{
    if( *str == 0 ) {
       return 0;
    }
    return 1 + strlen( str + 1 );
}

Matematik yok - çok basit bir fonksiyon. Elbette özyinelemeli olarak gerçek hayatta uygulamıyorsunuz, ama bu iyi bir özyineleme demosu.


-2

Öğrencilerin ilgili olabileceği bir başka gerçek dünya geri kazanma problemi, bir web sitesinden bilgi alan ve o site içindeki tüm bağlantıları (ve bu bağlantılardan gelen tüm bağlantıları) izleyen kendi web tarayıcısını oluşturmaktır.


2
Bu, geleneksel anlamda özyinelemenin aksine bir süreç kuyruğunun daha iyi hizmet etmesidir.
kabarık

-2

Bir özyinelemeli program kullanarak bir şövalye deseni (satranç tahtasında) ile ilgili bir problem çözdüm. Şövalyeyi etrafında hareket ettirmeniz gerekiyordu, böylece birkaç karenin dışında her kareye dokundu.

Sen sadece:

mark your "Current" square
gather a list of free squares that are valid moves
are there no valid moves?
    are all squares marked?
        you win!
for each free square
    recurse!
clear the mark on your current square.
return.    

Bunun gibi bir ağaçta gelecekteki olasılıkları test ederek, birçok "ileri görüşlü" senaryo türü kullanılabilir.

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.