Vous connaissiez la récurrence sans récursivité ? Démonstration... Astucieuse et performante. Le but recherché par ce code est d'accroître l'optimisation de la mémoire RAM. En effet, l'auto-récurrence directe consomme beaucoup de mémoire, car les procédures s'enchaînent alors qu'elles ne sont pas encore terminées. Ici, il n'y a rien de tout ça, car le code utilise un couple de procédures qui exploitent la même variable et qui s'informent l'une l'autre (version 1 seulement).
Posons:
(1) la procédure principale
(2) la fonction assistante qui dresse la liste des sous-dossiers en fonction des paramètres donnés par /1/.
Expliquons le principe en prenant un exemple. Imaginons l'arborescence suivante ordonnée. On suppose aussi que la fonction FindNext renvoit les fichiers par ordre alphabétique:
c:\
c:\Alphonse\
c:\Alphonse\Buffle\
c:\Alphonse\Girafe\
c:\Barbara\
c:\Barbara\Citroën\
c:\Barbara\Lada\
c:\Barbara\Lada\Airbag\
c:\Barbara\Lada\ESP de série\
c:\Barbara\Porsche\
c:\Chantal\
>>>====================>>>
>>> PREMIERE IDEE IMPLEMENTEE LE 08/12/04 <<<
La procédure (1) initialise la liste DIRSTL sur "c:\" (niveau 0). La fonction (2) énumère alors les sous-dossiers en ajoutant les résulats à DIRSTL. Mais (1) ne le sait pas. En revanche, ce qu'elle sait, c'est si oui ou non des dossiers ont été ajoutés. Si c'est le cas, elle se branche sur le premier dossier ajouté par (2) et considère les dossiers suivants qui ont donc été ajoutés par (2). On refait de même: sur ordre de (1), (2) dresse la liste les dossiers, et (1) les prend en compte et fait ensuite lister (2)...
Ainsi, le résultat avant le tri est ainsi:
### ETAPE 0 ###
c:\
### ETAPE 1 ###
c:\Alphonse\
c:\Barbara\
c:\Chantal\
### ETAPE 2 ###
c:\Alphonse\Buffle\
c:\Alphonse\Girafe\
c:\Barbara\Citroën\
c:\Barbara\Lada\
c:\Barbara\Porsche\
### ETAPE 3 ###
c:\Barbara\Lada\Airbag\
c:\Barbara\Lada\ESP de série\
On voit ainsi qu'à chaque fois que (1) fait lister (2), on passe à un niveau de sous-dossier supérieur. C'est une récurrence sans récursivité. C'est ce que j'appelle de la récursivité indirecte.
>>>====================>>>
>>> SECONDE IDEE IMPLEMENTEE LE 18/12/04 <<<
En fait, l'idée pourrait être bien meilleure. En effet, pourquoi ajouter les sous-dossiers à la fin de la liste, et non pas juste en-dessous de l'item actuellement scanné ? Cela permettrait d'avoir un scan plus logique. Si on reprend l'arborescence précédente, compte tenu du nouveau programme, on obtient ceci :
c:\
c:\Alphonse\
c:\Alphonse\Girafe\
c:\Alphonse\Buffle\
c:\Barbara\
c:\Barbara\Porsche\
c:\Barbara\Lada\
c:\Barbara\Lada\ESP de série\
c:\Barbara\Lada\Airbag\
c:\Barbara\Citroën\
c:\Chantal\
La logique de cette liste peut être déroutante, mais remarquez simplement qu'il y a de nombreuses inversions liées à l'utilisation de la fonction Insert. Le désordre règne finalement, mais on s'en fiche pas mal, car les fonctions FindNext et compagnie prennent en réalité le fichier qui tombe sous la main quelque soit son classement alphabétique par rapport aux autres fichiers du même répertoire. Ainsi, pour que tout soit très beau, on a quand même besoin d'utiliser la fonction ~.Sort dans n'importe quelle idée. C'est juste que le classement sera légèrement plus rapide si les items sont déjà un peu classés.
Source / Exemple :
program RecDir;
uses Windows, Classes, SysUtils, Dialogs;
var DirSTL : TStringList;
function IncludeTrailing(const S: string): string;
begin
Result:=S;
if not IsPathDelimiter(Result,Length(Result)) then
Result:=Result+'\';
end;
function IsDirectory(SRec:TSearchRec):boolean;
begin
IsDirectory:= SRec.Attr and faDirectory <> 0;
end;
procedure AddSubDirs(Dir,Mask:string;Index:integer);
var AttrWord : integer;
Pntr, s1, s2 : string;
Recherche : TSearchRec;
begin
AttrWord:=faDirectory or faReadOnly or faArchive or faHidden or faSysFile;
{$I-} ChDir(Dir); {$I+}
while Mask<>'' do
begin
if Pos(';',Mask)=0 then Pntr:=Mask
else Pntr:=Copy(Mask,1,Pos(';',Mask)-1);
if FindFirst(IncludeTrailing(Dir)+Pntr, AttrWord, Recherche)=0 then
begin
repeat
s1:=ExtractFileName(Recherche.Name);
s2:=IncludeTrailing(Dir+s1);
if (s1<>'.') and (s1<>'..') and (IsDirectory(Recherche)) then
DirSTL.Insert(Index+1, UpperCase(s2));
until FindNext(Recherche)<>0;
SysUtils.FindClose(Recherche);
end;
if Pos(';',Mask)=0 then Break
else Mask:=Copy(Mask,Pos(';',Mask)+1,Length(Mask));
end;
end;
procedure RecurseSubFolder(Rcn:string);
var Idx : integer;
begin
Rcn:=IncludeTrailing(Rcn);
DirSTL.Clear;
DirSTL.Add(UpperCase(Rcn));
Idx:=0;
repeat
AddSubDirs(DirSTL[Idx],'*.*',Idx);
Idx:=Idx+1;
until (Idx>=DirSTL.Count);
DirSTL.Sort;
end;
begin
DirSTL:=TStringList.Create;
RecurseSubFolder('c:\mes documents\');
ShowMessage(DirSTL.Text);
DirSTL.Clear;
DirSTL.Free;
end.
Conclusion :
Le code source tient uniquement dans un fichier DPR. Aucun PAS ni DFM... De plus, le Zip est annoté.
Vous pouvez toujours aller voir
http://altert.family.free.fr/
Vous n'êtes pas encore membre ?
inscrivez-vous, c'est gratuit et ça prend moins d'une minute !
Les membres obtiennent plus de réponses que les utilisateurs anonymes.
Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.
Le fait d'être membre vous permet d'avoir des options supplémentaires.