Salut,
Je préviens que ce que je vais dire risque de ne pas être clair et demande à être confirmé.
Pour les index, il s'agit juste d'une autre façon de parcourir ta chaine de caractère.
En effet, pour l'instant tu as - si je ne me trompe - fait comme si tu travaillais sur une pile / liste, à savoir un truc du genre :
Ici, on applique fonction au premier élément de la chaine de caractère, puis on rappelle parcourir sur le reste de la chaine. Ainsi, la chaine sera bien balayée.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 let rec parcourir fonction chaine = fonction (sub_string chaine 0 1); parcourir fonction (sub_string chaine 1 (string_length chaine - 1)) ;;
Mais tu remarques qu'on effectue en fait que deux actions sur la chaine : l'accès à son premier élément, et l'accès à la chaine privée de son premier élément. Certaines structures de données (comme les piles ou les listes) sont adaptées à cela. Ainsi, si on devait réécrire exactement le même programme pour une liste on aurait :
Mais ce n'est pas adaptés pour les chaînes de caractères, car il n'est pas facile d'avoir accès à la chaîne privée de son premier caractère. En effet, les chaînes sont implantées comme des tableaux de caractères, c'est-à-dire un ensemble de n caractères indexés par des entiers de 0 à n-1. Ainsi, quand je vais vouloir avoir accès à une chaîne privée de son premier caractères, il va falloir créer un objet de longueur n-1 puis le remplir avec les bons caractères... Ce qui a une complexité de la longueur de la sous-chaine...
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6 let rec parcourir fonction liste = match liste with | [] -> () | tete :: queue -> fonction tete; parcourir fonction queue ;;
Du coup tu vois l'inefficacité du premier mode de balayage avec les chaînes (et les tableaux) : la complexité va être en (n-1) + (n-2) + ... + 1 = n.(n-1)/2, c'est-à-dire quadratique !
En revanche, la structure "en tableau" offre un autre avantage : il est très simple d'avoir accès au i-ème élément : ça se fait avec la syntaxe chaine.[i], et c'est "immédiat" (contrairement aux listes et aux piles, où il va falloir parcourir l'objet en ayant un compteur pour s'arrêter au i-ème élément). Du coup, il faut s'en servir !
Ainsi, la première fonction devient tout simplement :
soit, sans boucle for (mais là c'est très moche) :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6 (* l'index est ici i *) let rec parcourir fonction chaine = let n = string_length chaine in for i = 0 to n - 1 do fonction chaine.[i] done ;;
Attention, il y a une petite inexactitude dans ce que j'ai dit (mais j'étais obligé pour ne pas dévoiler la notation chaine.[i] trop tôt) :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11 (* l'index est ici n *) let parcourir fonction chaine = let auxiliaire n = match n with | -1 -> () | n -> fonction chaine.[n]; auxiliaire (n - 1) in auxiliaire ((string_length chaine) - 1) ;;
sub_string renvoie une chaine de caractère (string), alors que chaine.[i] renvoie un caractère (char). Donc dans la première version fonction est de string -> 'a, alors que dans la dernière version elle est de char -> 'a
(en gros c'est la différence entre "a" et `a`, ou même entre [|`a`|] et `a`...)
J'espère avoir été clair !
Partager