Quels sont problèmes du monde réel où une approche récursive est la solution naturelle en plus de la recherche en profondeur d'abord (DFS)?
(Je ne considère pas Tour de Hanoi , nombre de Fibonacci , ou les problèmes factoriels du monde réel. Ils sont un peu artificiels dans mon esprit.)
Il y a beaucoup d'exemples mathématiques ici, mais vous vouliez un exemple monde réel, donc avec un peu de réflexion, c'est probablement le meilleur que je puisse offrir:
Vous trouvez une personne qui a contracté une infection contagieuse donnée, qui n'est pas mortelle, et se corrige rapidement (type A), à l'exception d'une personne sur 5 (nous les appellerons type B) qui en sont infectées de façon permanente et ne montre aucune symptômes et agit simplement comme un épandeur.
Cela crée des vagues de ravages assez ennuyeux lorsque le type B infecte une multitude de types A.
Votre tâche consiste à traquer tous les types B et à les immuniser pour arrêter l'épine dorsale de la maladie. Malheureusement, vous ne pouvez pas administrer à tous un traitement national, car les personnes de type As sont également mortellement allergiques au traitement qui fonctionne pour le type B.
La façon dont vous le feriez serait une découverte sociale, étant donné qu'une personne infectée (Type A), choisirait tous ses contacts au cours de la dernière semaine, marquant chaque contact sur un tas. Lorsque vous testez une personne infectée, ajoutez-la à la file d'attente de "suivi". Lorsqu'une personne est de type B, ajoutez-la au "suivi" en tête (parce que vous voulez arrêter ça aussi vite).
Après avoir traité une personne donnée, sélectionnez-la à l'avant de la file d'attente et appliquez la vaccination si nécessaire. Obtenez tous leurs contacts précédemment non consultés, puis testez pour voir s'ils sont infectés.
Répétez jusqu'à ce que la file d'attente des personnes infectées devienne 0, puis attendez une autre épidémie.
(Ok, c'est un peu itératif, mais c'est une façon itérative de résoudre un problème récursif, dans ce cas, l'étendue de la première traversée d'une base de population essayant de découvrir les chemins probables des problèmes, et en plus, les solutions itératives sont souvent plus rapides et plus efficaces , et j'enlève compulsivement la récursion partout tellement ça devient instinctif. .... bon sang!)
Que diriez-vous de tout ce qui implique une structure de répertoires dans le système de fichiers. Recherche récursive de fichiers, suppression de fichiers, création de répertoires, etc.
Voici une implémentation Java qui imprime récursivement le contenu d'un répertoire et de ses sous-répertoires.
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());
}
}
}
}
Quicksort , tri par fusion , et la plupart des autres types de N-log N.
L'exemple de Matt Dillard est bon. Plus généralement, toute marche d'un arbre peut généralement être gérée par récursivité très facilement. Par exemple, compiler des arbres d'analyse, parcourir XML ou HTML, etc.
La récursivité est souvent utilisée dans les implémentations de algorithme de retour arrière . Pour une application "réelle" de cela, que diriez-vous d'un solveur Sudok ?
La récursivité est appropriée chaque fois qu'un problème peut être résolu en le divisant en sous-problèmes, qui peuvent utiliser le même algorithme pour les résoudre. Les algorithmes sur les arbres et les listes triées conviennent naturellement. De nombreux problèmes de géométrie computationnelle (et de jeux 3D) peuvent être résolus récursivement en utilisant partitionnement d'espace binaire (BSP) arbres, grosses subdivisions , ou d'autres façons de diviser le monde en sous- les pièces.
La récursivité est également appropriée lorsque vous essayez de garantir l'exactitude d'un algorithme. Étant donné une fonction qui prend des entrées immuables et renvoie un résultat qui est une combinaison d'appels récursifs et non récursifs sur les entrées, il est généralement facile de prouver que la fonction est correcte (ou non) en utilisant l'induction mathématique. Il est souvent difficile de le faire avec une fonction itérative ou avec des entrées qui peuvent muter. Cela peut être utile lorsque vous traitez des calculs financiers et d'autres applications où l'exactitude est très importante.
Il est certain que de nombreux compilateurs utilisent beaucoup la récursivité. Les langages informatiques sont intrinsèquement récursifs eux-mêmes (c'est-à-dire que vous pouvez intégrer des instructions `` if '' dans d'autres instructions `` if '', etc.).
Désactivation/définition en lecture seule pour tous les contrôles enfants dans un contrôle conteneur. J'avais besoin de le faire parce que certains des contrôles des enfants étaient eux-mêmes des conteneurs.
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);
}
}
(source: mit.ed )
Voici la définition de eval:
(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))))
Voici la définition de Apply:
(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))))
Voici la définition de la séquence d'évaluation:
(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
La récursivité est utilisée dans des éléments tels que les arbres BSP pour la détection des collisions dans le développement de jeux (et dans d'autres domaines similaires).
Les gens trient souvent des piles de documents à l'aide d'une méthode récursive. Par exemple, imaginez que vous triez 100 documents avec des noms dessus. Placez d'abord les documents en piles par la première lettre, puis triez chaque pile.
La recherche de mots dans le dictionnaire est souvent effectuée par une technique de type recherche binaire, qui est récursive.
Dans les organisations, les patrons donnent souvent des ordres aux chefs de département, qui à leur tour donnent des ordres aux gestionnaires, etc.
La récursivité est appliquée aux problèmes (situations) où vous pouvez la décomposer (la réduire) en parties plus petites, et chaque partie (s) ressemble au problème d'origine.
De bons exemples de cas où des choses qui contiennent des pièces plus petites similaires à lui-même sont:
La récursivité est une technique pour continuer à décomposer le problème en morceaux de plus en plus petits, jusqu'à ce que l'un de ces morceaux devienne assez petit pour être un morceau de gâteau. Bien sûr, après les avoir décomposés, vous devez ensuite "recoudre" les résultats ensemble dans le bon ordre pour former une solution totale à votre problème d'origine.
Certains algorithmes de tri récursif, les algorithmes d'arborescence, les algorithmes de cartographie/réduction, la division et la conquête sont tous des exemples de cette technique.
En programmation informatique, la plupart des langages de type retour d'appel basés sur la pile ont déjà les capacités intégrées pour la récursivité: i.e.
De grands exemples de récursivité se trouvent dans les langages programmation fonctionnelle . Dans les langages de programmation fonctionnels ( Erlang , Haskell , ML / OCaml / F # , etc.), il est très courant que toute traitement de liste utilise la récursivité.
Lorsque vous traitez des listes dans des langages typiques de style OOP impératif, il est très courant de voir des listes implémentées en tant que listes liées ([item1 -> item2 -> item3 -> item4]). Cependant, dans certains langages de programmation fonctionnels, vous constatez que les listes elles-mêmes sont implémentées de manière récursive, où la "tête" de la liste pointe vers le premier élément de la liste et la "queue" pointe vers une liste contenant le reste des éléments ( [item1 -> [item2 -> [item3 -> [item4 -> []]]]]). C'est assez créatif à mon avis.
Cette gestion des listes, lorsqu'elle est combinée avec la correspondance de modèles, est TRÈS puissante. Disons que je veux résumer une liste de nombres:
let rec Sum numbers =
match numbers with
| [] -> 0
| head::tail -> head + Sum tail
Cela dit essentiellement "si nous étions appelés avec une liste vide, retourne 0" (ce qui nous permet de rompre la récursivité), sinon retourne la valeur de head + la valeur de Sum appelée avec les éléments restants (d'où notre récursivité).
Par exemple, je pourrais avoir une liste de RL , je pense séparer toutes les URL vers lesquelles chaque URL est liée, puis je réduis le nombre total de liens vers/depuis toutes les URL pour générer des "valeurs" pour une page (une approche que Google adopte avec PageRank et que vous pouvez trouver définie dans l'original MapReduce papier). Vous pouvez également effectuer cette opération pour générer le nombre de mots dans un document. Et beaucoup, beaucoup, beaucoup d'autres choses aussi.
Vous pouvez étendre ce modèle fonctionnel à n'importe quel type de code MapReduce où vous pouvez prendre une liste de quelque chose, le transformer et renvoyer autre chose (que ce soit une autre liste ou une commande Zip de la liste).
Exigence du monde réel que j'ai eu récemment:
Exigence A: implémentez cette fonctionnalité après avoir bien compris l'exigence A.
Les analyseurs et les compilateurs peuvent être écrits selon une méthode de descente récursive. Ce n'est pas la meilleure façon de le faire, car des outils comme Lex/yacc génèrent des analyseurs plus rapides et plus efficaces, mais conceptuellement simples et faciles à implémenter, ils restent donc courants.
J'ai un système qui utilise pur récursivité de la queue à quelques endroits pour simuler une machine à états.
XML, ou traversant tout ce qui est un arbre. Bien que, pour être honnête, je n'utilise pratiquement pas de récursivité dans mon travail.
Boucles de rétroaction dans une organisation hiérarchique.
Le patron supérieur demande aux cadres supérieurs de recueillir les commentaires de tous les membres de l'entreprise.
Chaque dirigeant rassemble ses subordonnés directs et leur dit de recueillir les commentaires de leurs subordonnés directs.
Et sur toute la ligne.
Les personnes sans rapports directs - les nœuds foliaires de l'arbre - donnent leur avis.
Les commentaires remontent dans l'arborescence, chaque responsable ajoutant ses propres commentaires.
Finalement, tous les commentaires reviennent au boss supérieur.
C'est la solution naturelle, car la méthode récursive permet de filtrer à chaque niveau - le rassemblement des doublons et la suppression des commentaires offensants. Le patron supérieur pourrait envoyer un e-mail global et demander à chaque employé de lui renvoyer directement ses commentaires, mais il y a les problèmes "vous ne pouvez pas gérer la vérité" et "vous êtes viré" , donc la récursivité fonctionne mieux ici.
Calculs pour la finance/physique, tels que les moyennes composées.
Le meilleur exemple que je connaisse est quicksort , c'est beaucoup plus simple avec la récursivité. Jeter un coup d'œil à:
shop.oreilly.com/product/9780596510046.do
www.Amazon.com/Beautiful-Code-Leading-Programmers-Practice/dp/0596510047
(Cliquez sur le premier sous-titre du chapitre 3: "Le plus beau code que j'ai jamais écrit").
Supposons que vous construisez un CMS pour un site Web, où vos pages sont dans une arborescence, avec par exemple la racine étant la page d'accueil.
Supposons également que votre {utilisateur | client | client | patron} vous demande de placer un fil d'Ariane sur chaque page pour montrer où vous vous trouvez dans l'arborescence.
Pour n'importe quelle page n donnée, vous voudrez peut-être remonter jusqu'au parent de n, et son parent, et ainsi de suite, de manière récursive pour construire une liste de nœuds à la racine de l'arborescence de la page.
Bien sûr, vous frappez la base de données plusieurs fois par page dans cet exemple, vous pouvez donc utiliser un alias SQL où vous recherchez page-table comme a, et page-table à nouveau comme b, et joignez a.id avec b.parent pour que la base de données fasse les jointures récursives. Cela fait un moment, donc ma syntaxe n'est probablement pas utile.
Là encore, vous souhaiterez peut-être calculer cela une seule fois et le stocker avec l'enregistrement de page, le mettant à jour uniquement si vous déplacez la page. Ce serait probablement plus efficace.
Quoi qu'il en soit, c'est mon 0,02 $
Vous avez un arbre d'organisation qui est N niveaux profonds. Plusieurs des nœuds sont vérifiés et vous souhaitez développer uniquement les nœuds qui ont été vérifiés.
C'est quelque chose que j'ai réellement codé. C'est agréable et facile avec récursivité.
Analyse d'une arborescence de contrôles dans Windows Forms ou WebForms (.NET Windows Forms/ ASP.NET ).
Dans mon travail, nous avons un système avec une structure de données générique qui peut être décrite comme un arbre. Cela signifie que la récursivité est une technique très efficace pour travailler avec les données.
Le résoudre sans récursivité nécessiterait beaucoup de code inutile. Le problème avec la récursivité est qu'il n'est pas facile de suivre ce qui se passe. Vous devez vraiment vous concentrer lorsque vous suivez le flux d'exécution. Mais quand il fonctionne, le code est élégant et efficace.
Tout où vous utilisez l'itération se fait de façon plus naturelle avec la récursion si ce n'est pas pour la limitation pratique de provoquer un débordement de pile ;-)
Mais sérieusement, la récursivité et l'itération sont très interchangeables, vous pouvez réécrire tous les algorithmes en utilisant la récursivité pour utiliser l'itération et vice versa. Les mathématiciens aiment la récursivité et les programmeurs aiment l'itération. C'est probablement aussi pourquoi vous voyez tous ces exemples artificiels que vous mentionnez. Je pense que la méthode de la preuve mathématique appelée induction mathématique a quelque chose à voir avec pourquoi les mathématiciens aiment la récursivité. http://en.wikipedia.org/wiki/Mathematical_induction
La multiplication des nombres naturels est un exemple réel de récursivité:
To multiply x by y
if x is 0
the answer is 0
if x is 1
the answer is y
otherwise
multiply x - 1 by y, and add x
Les méthodes de recherche des nombres premiers sont récursives. Utile pour générer des clés de hachage, pour divers schémas de chiffrement qui utilisent des facteurs de grands nombres.
Les compagnies de téléphone et de câblodistribution maintiennent un modèle de leur topologie de câblage, qui est en fait un grand réseau ou un graphique. La récursivité est un moyen de parcourir ce modèle lorsque vous souhaitez rechercher tous les éléments parents ou enfants.
Étant donné que la récursivité est coûteuse du point de vue du traitement et de la mémoire, cette étape n'est généralement effectuée que lorsque la topologie est modifiée et le résultat est stocké dans un format de liste précommandé modifié.
Le raisonnement inductif, le processus de formation du concept, est de nature récursive. Votre cerveau le fait tout le temps, dans le monde réel.
Généralement, la récursivité est très naturelle pour traiter les structures de données récursives. Cela signifie essentiellement des structures de liste et des structures arborescentes. Mais la récursivité est aussi une belle façon naturelle de/créer/des structures d'arbre à la volée d'une manière ou d'une autre, en divisant et conquérant par exemple quicksort , ou recherche binaire.
Je pense que votre question est un peu erronée dans un sens. Qu'est-ce qui n'est pas réel dans la première recherche en profondeur? Il y a beaucoup à faire avec la recherche en profondeur d'abord.
Par exemple, un autre exemple que j'ai pensé donner est la compilation de descente récursive. C'est assez d'un problème du monde réel pour avoir été utilisé dans de nombreux compilateurs du monde réel. Mais vous pourriez dire que c'est DFS, c'est essentiellement une recherche en profondeur d'abord pour un arbre d'analyse valide.
J'ai écrit un analyseur XML une fois qui aurait été beaucoup plus difficile à écrire sans récursivité.
Je suppose que vous pouvez toujours utiliser une pile + itération, mais parfois la récursivité est tellement élégante.
Tout programme avec des structures de données arborescentes ou graphiques aura probablement une récursivité.
Trouver la médiane dans le cas moyen O (n). Équivaut à trouver le k-ème élément le plus grand dans une liste de n choses, avec k = n/2:
Ici, partition
sélectionne un élément pivot et, en un seul passage dans les données, réorganise la liste de sorte que les éléments inférieurs au pivot viennent en premier, puis le pivot, puis les éléments plus grands que le pivot. L'algorithme "kthLargest" est très similaire à quicksort, mais ne se reproduit que d'un côté de la liste.
Pour moi, c'est l'algorithme récursif le plus simple qui s'exécute plus rapidement qu'un algorithme itératif. Il utilise en moyenne 2 * n comparaisons, quel que soit k. C'est beaucoup mieux que l'approche naïve de l'exécution de k passe à travers les données, en trouvant le minimum à chaque fois et en les rejetant.
Alejo
Idem le commentaire sur les compilateurs. Les nœuds d'arbre de syntaxe abstraite se prêtent naturellement à la récursivité. Toutes les structures de données récursives (listes chaînées, arborescences, graphiques, etc.) sont également plus faciles à gérer avec la récursivité. Je pense que la plupart d'entre nous n'utilisons pas beaucoup la récursivité une fois que nous sommes sortis de l'école à cause des types de problèmes du monde réel, mais il est bon d'en être conscient en option.
Écrivez une fonction qui traduit un nombre comme 12345,67 en "douze mille trois cent quarante-cinq dollars et soixante-sept cents".
Alors A(n) = A(n-1) + 50 + 0.05*(1/12)* A(N-1)
J'ai écrit un arbre en C # pour gérer les recherches sur une table qui contient une clé à 6 segments avec des cas par défaut (si la clé [0] n'existe pas, utilisez le cas par défaut et continuez). Les recherches ont été effectuées de manière récursive. J'ai essayé un dictionnaire de dictionnaires de dictionnaires (etc) et il est devenu trop complexe très rapidement.
J'ai également écrit un évaluateur de formule en C # qui évaluait les équations stockées dans un arbre pour obtenir l'ordre d'évaluation correct. Certes, il s'agit probablement de choisir la langue incorrecte pour le problème, mais c'était un exercice intéressant.
Je n'ai pas vu beaucoup d'exemples de ce que les gens avaient fait, mais plutôt des bibliothèques qu'ils avaient utilisées. J'espère que cela vous donne quelque chose à penser.
Une méthode pour générer un menu arborescent à partir d'une table de base de données en utilisant subsonique.
public MenuElement(BHSSiteMap node, string role)
{
if (CheckRole(node, role))
{
ParentNode = node;
// get site map collection order by sequence
BHSSiteMapCollection children = new BHSSiteMapCollection();
Query q = BHSSiteMap.CreateQuery()
.WHERE(BHSSiteMap.Columns.Parent, Comparison.Equals, ParentNode.Id)
.ORDER_BY(BHSSiteMap.Columns.Sequence, "ASC");
children.LoadAndCloseReader(q.ExecuteReader());
if (children.Count > 0)
{
ChildNodes = new List<MenuElement>();
foreach (BHSSiteMap child in children)
{
MenuElement childME = new MenuElement(child, role);
ChildNodes.Add(childME);
}
}
}
}
Calculs géométriques pour les SIG ou la cartographie, comme trouver le bord d'un cercle.
Les méthodes de recherche d'une racine carrée sont récursives. Utile pour calculer les distances dans le monde réel.
Le dernier exemple du monde réel que je possède est assez frivole, mais il montre comment la récursion "convient" parfois.
J'utilisais le modèle de chaîne de responsabilité, donc un objet gestionnaire gère une demande lui-même ou la délègue le long de la chaîne. Il est utile de consigner la construction de la chaîne:
public String getChainString() {
cs = this.getClass().toString();
if(this.delegate != null) {
cs += "->" + delegate.getChainString();
}
return cs;
}
Vous pourriez faire valoir que ce n'est pas la récursivité la plus pure, car bien que la méthode s'appelle "elle-même", elle l'est dans une instance différente à chaque fois qu'elle est appelée.
Vous avez un immeuble. L'immeuble compte 20 chambres. Légalement, vous ne pouvez avoir qu'un certain nombre de personnes dans chaque pièce. Votre travail consiste à affecter automatiquement des personnes à une pièce. Si ma chambre est pleine, vous devez trouver une chambre disponible. Étant donné que seules certaines pièces peuvent contenir certaines personnes, vous devez également faire attention à quelle pièce.
Par exemple:
Les chambres 1, 2, 3 peuvent se rouler l'une dans l'autre. Cette chambre est destinée aux enfants qui ne peuvent pas marcher seuls, vous devez donc les éloigner de tout le reste pour éviter la distraction et les autres maladies (ce qui n'est pas une chose pour les personnes âgées, mais pour un 6mo, cela peut devenir très mauvais. tous les trois soient pleins, la personne doit se voir refuser l'entrée.
Les chambres 4, 5, 6 peuvent se rouler l'une sur l'autre. Cette chambre est destinée aux personnes allergiques aux arachides et, par conséquent, elles ne peuvent pas entrer dans d'autres chambres (qui peuvent contenir des arachides). Si les trois deviennent pleins, offrez un avertissement demandant leur niveau d'allergie et les perahsp auxquels ils peuvent avoir accès.
À tout moment, les chambres peuvent changer. Vous pouvez donc autoriser la pièce 7-14 à être sans cacahuètes. Vous ne savez pas combien de chambres vérifier.
Ou, peut-être que vous voulez vous séparer en fonction de l'âge. Grade, sexe, etc. Ce ne sont que quelques exemples dans lesquels je suis entré.
Un problème "réel" résolu par la récursivité serait les poupées gigognes. Votre fonction est OpenDoll ().
Étant donné une pile d'entre eux, vous recursilvey ouvririez les poupées, appelant OpenDoll () si vous voulez, jusqu'à ce que vous ayez atteint la poupée la plus intérieure.
Si vous avez deux séquences différentes mais similaires et que vous souhaitez faire correspondre les composants de chaque séquence de sorte que les gros morceaux contigus soient favorisés en premier, suivis d'un ordre de séquence identique, vous pouvez analyser récursivement ces séquences pour former un arbre, puis traiter récursivement cet arbre pour l'aplatir. il.
Je viens d'écrire une fonction récursive pour déterminer si une classe devait être sérialisée à l'aide d'un DataContractSerializer. Le gros problème est venu avec les modèles/génériques où une classe pouvait contenir d'autres types qui devaient être sérialisés par datacontract ... alors il faut passer par chaque type, si ce n'est pas datacontractserializable vérifier ses types.
Nous les utilisons pour rechercher le chemin SQL.
Je dirai également que c'est difficile de déboguer, et il est très facile pour un pauvre programmeur de le gâcher.
La récursivité est une technique de programmation très basique, et elle se prête à tant de problèmes que les lister revient à lister tous les problèmes qui peuvent être résolus en utilisant une sorte d'addition. En parcourant simplement mes solutions LISP pour Project Euler, je trouve: une fonction de total croisé, une fonction d'appariement de chiffres, plusieurs fonctions de recherche d'un espace, un analyseur de texte minimal, une fonction divisant un nombre dans la liste de ses chiffres décimaux, une fonction construction d'un graphe et d'une fonction traversant un fichier d'entrée.
Le problème est que de nombreux, sinon la plupart des langages de programmation traditionnels ne disposent pas aujourd'hui de l'optimisation des appels de queue, de sorte qu'une récursivité profonde n'est pas possible avec eux. Cette insuffisance signifie que la plupart des programmeurs sont obligés de désapprendre cette façon naturelle de penser et de s'appuyer à la place sur d'autres constructions en boucle, sans doute moins élégantes.
Puisque vous ne semblez pas aimer les exemples en informatique ou en mathématiques, voici un autre: les puzzles de fils.
De nombreux casse-tête de fil impliquent de retirer une longue boucle fermée de fil en la faisant entrer et sortir des anneaux de fil. Ces puzzles sont récursifs. L'un d'eux est appelé "dynamique des flèches". Je suis sue vous pouvez le trouver si vous cherchez sur Google "puzzle dynamique du fil de flèche"
Ces puzzles ressemblent beaucoup aux tours de Hanoi.
Vérifiez si l'image créée fonctionnera dans une zone de taille limitée.
function check_size($font_size, $font, $text, $width, $height) {
if (!is_string($text)) {
throw new Exception('Invalid type for $text');
}
$box = imagettfbbox($font_size, 0, $font, $text);
$box['width'] = abs($box[2] - $box[0]);
if ($box[0] < -1) {
$box['width'] = abs($box[2]) + abs($box[0]) - 1;
}
$box['height'] = abs($box[7]) - abs($box[1]);
if ($box[3] > 0) {
$box['height'] = abs($box[7] - abs($box[1])) - 1;
}
return ($box['height'] < $height && $box['width'] < $width) ? array($font_size, $box['width'], $height) : $this->check_size($font_size - 1, $font, $text, $width, $height);
}
Je pense que cela dépend vraiment de la langue. Dans certaines langues, LISP par exemple, la récursivité est souvent la réponse naturelle à un problème (et souvent avec les langues où c'est le cas, le compilateur est optimisé pour faire face à la récursivité).
Le modèle courant dans LISP consistant à effectuer une opération sur le premier élément d'une liste, puis à appeler la fonction sur le reste de la liste afin d'accumuler une valeur ou une nouvelle liste est un moyen assez élégant et le plus naturel de faire beaucoup de les choses dans cette langue. En Java , pas tellement.