2010-09-23 5 views
2

Lorsque je crée des méthodes récursives, j'inclue souvent un paramètre Depth, en particulier lorsque j'ai besoin d'un mécanisme de renflouement. Le code sera généralement quelque chose comme çaEn Delphi: Comment trouver la profondeur de récursivité sans utiliser de paramètre?

procedure Recurse(<Params>; aDepth : integer = 0); 
begin 
    if aDepth > SomeLimit then 
    begin 
    //Tidy up, return best result found> 
    exit; 
    end; 

    <stuff> 

    if <Condition> then 
    Recurse(<Params>; aDepth+1) 
    else 
    begin 
    //Tidy up, return result of endnode> 
    end; 
end; 

Et je l'appelle sans paramètre de profondeur

Recurse(<Params>); 

Y at-il une autre façon de trouver facilement la profondeur?

+0

Voulez-vous une solution Delphi pure, ou êtes-vous prêt à passer à l'assembleur? – dthorpe

+0

Non, je ne veux pas d'assembleur. J'espérais une solution qui était _simpler_ alors mon approche actuelle. –

Répondre

7

Si vous aviez un moyen de parcourir la pile et de voir combien de fois le point d'entrée de votre fonction était là, je suppose que vous pourriez le faire de cette façon. Mais alors vous remarquerez que votre paramètre aDepth était là aussi, et vous vous rendrez compte qu'une profondeur est juste plus facile et beaucoup moins de problèmes que l'espionnage de la pile. IMO, la solution simple est la meilleure ici, elle est portable et à l'épreuve du futur, contrairement à n'importe quelle solution d'espionnage de pile que vous pourriez inventer.
Alors oui, il y a d'autres façons, mais votre solution originale est la meilleure, IMO.

+1

Pas ce que j'espérais, mais c'est toujours gratifiant d'entendre que "ma solution originale était la meilleure" :-) –

+0

La solution de "pile de marche" pourrait fonctionner, bien sûr , mais ça ne me semble pas idéal. La solution originale est la meilleure, ou peut-être utiliser un TObject alloué sur la pile pour partager certains paramètres initiaux et une valeur privée de profondeur pendant la récursivité. Cela pourrait être une solution élégante, mais cela dépend de ce que vous faites dans la fonction récursive. –

0

Avoir une variable globale qui compterait récursion? Sinon, no - récursivité appelle simplement une méthode avec certains paramètres.

+1

N'utilisez pas de variables globales pour résoudre un problème local. –

+0

Ne faites pas de déclarations globales sur des questions étroites. Cela dépend de la tâche. Le problème peut être aussi global que l'application elle-même (par exemple, le traitement récursif des fichiers dans certains dossiers peut être la seule fonction de certaines applications). –

+2

Le problème avec les solutions globales qui travaillent pour les 20% du temps d'un développeur est qu'il va casser dans les 80% du temps de maintenance. C'est pourquoi une solution non globale est généralement meilleure: elle résiste mieux aux erreurs. Et c'est la raison pour laquelle j'ai prévenu. Peut-être que j'aurais dû le formuler un peu plus amical cependant :-) –

2

Déclarez une constante typée dans votre procédure. Assurez-vous de définir l'option de compilation pour autoriser les modifications dans les constantes.

procedure Recurse; 
const 
    aDepth : integer = 0; 
begin 
    aDepth := aDepth + 1; 

    try 
    if aDepth > SomeLimit then 
    begin 
     //Tidy up, return best result found> 
     exit; 
    end; 

    <stuff> 

    if <Condition> then 
     Recurse 
    else 
    begin 
     //Tidy up, return result of endnode> 
    end; 
    finally 
    aDepth := aDepth - 1; 
    end; 
end; 
+0

Approche intéressante, mais je dois encore écrire du code pour garder une trace de la profondeur actuelle, ce qui était une sorte de ce que je voulais éviter. J'espérais une fonction magique "CurrentDepth" :-) –

+1

Plutôt que d'activer globalement les constantes assinables, n'emballez pas la procédure avec {$ J +}/{$ J-} ​​ –

+1

! Ces constantes assignables (ou variables initialisées) sont une chose globale.En utilisant cela, vous limiterez votre méthode à être seulement appelable d'un site à la fois; il va essentiellement tuer toute utilisation multi-thread ou re-entrant de votre méthode. –

0

En C++, je suis en mesure de le faire

class recursion_guard 
{ 
public: 
    recursion_guard() { depth_count++; } 
    ~recursion_guard() { depth_count--; } 
    static int depth_count; 
}; 
int recursion_guard::depth_count = 0; 
void recurse(recursion_guard a = recursion_guard()) 
{ 
    if(recursion_guard::depth_count > 100) 
     return; 
    recurse(); 
} 

mais étant donné que les objets Pascal Objet sont toujours attribués sur le tas, je me demande s'il est possible d'utiliser à la place chaîne avec l'argument par défaut et l'accès en quelque sorte la référence compte

const 
    MyRecursionGuardConstString: string = "whatever"; 
procedure Recurse(RecursionGuard: string = MyRecursionGuardConstString) 
begin 
    if GetRefCount(MyRecursionGuardConstString) > 100 then //o_o 
     exit; 
    end; 
    Recurse; 
end; 
+0

Ces globals ne sont pas threadsafe. La solution de paramètre de l'affiche est. –

+0

Si vous aviez votre propre compte de treadvar sur chaque récursion, cela fonctionnerait-il comme un moyen sûr d'éviter un paramètre supplémentaire? –

+0

@Peter Turner: Je suppose que oui, threadvar le ferait – Alsk

0
type 
    TMyRecursion = class 
    private 
    nDepth: integer; 
    public 
    constructor Create; 
    procedure Recursion(...) 
    end; 

dans le constructeur, vous devez initialiser nDepth, bien sûr.

Questions connexes