Page d'accueil
Thèmes d'activités
<< Thème précédent
Dans cette feuille de
calcul, nous définirons une structure représentant un
arbre n-aire
(arbre tel que chaque nœud donne naissance à au plus
n fils).
Notre application étant le codage d'un dictionnaire, nous supposerons
que chaque nœud de l'arbre est étiqueté par une chaîne de caractères.
Ainsi, par exemple l'arbre n-aire suivant représente le codage du
dictionnaire:
"EPI","EPIER","EPIERA","EPIERAI","EPIERAS","EMU","SU","SALI","JEU".
Le point à la suite d'une lettre indiquera la fin d'un mot, ainsi "EPIE"
n'est pas un mot du dictionnaire, mais est un préfixe pour les mots
"EPIER","EPIERA","EPIERAI","EPIERAS".
L'arbre sera représenté
par une structure de listes imbriquées:
La racine de l'arbre est
un noeud étiqueté par une chaîne de caractères vide:
La procédure récursive
insert
permet d'ajouter le mot
word à un arbre
tree .
Le booléen b
indique s'il a la valeur
true le rajout
d'un point à la fin du mot dans l'arbre,
sinon aucun point n'est rajouté à la fin du mot.
> |
insert:=proc(tree::list,word::string,b::boolean)
local letter,i,s,M;
if word="" then return `if`(b,subsop(1=cat(tree[1],"."),tree),tree)
end if;
letter:=word[1]:
for i from 2 to nops(tree) do
if op(1,tree[i])[1]=letter then
return(subsop(i=procname(tree[i],word[2..length(word)],b),tree))
end if
end do;
M:=[op(tree),[letter]]:
return(subsop(nops(M)=procname(M[nops(M)],word[2..length(word)],b),M))
end proc:
|
> |
tree:=insert(tree,"EPI",false);
|
> |
tree:=insert(tree,"EPI",true); |
Notez la différence
suivant la valeur booléenne de
b : dans le
premier cas "EPI" n'est pas un mot du dictionnaire puisque son dernier
caractère "I" n'est pas suivi
d'un point dans
tree
, mais pourra servir de préfixe pour d'autres mots
à ajouter.
Dans le second cas, "EPI"
est un mot du dictionnaire puisque son dernier caractère "I" est suivi
d'un point dans tree
.
> |
tree:=insert(tree,"EPIER",true);
|
> |
tree:=insert(tree,"EMU",true);
|
> |
tree:=insert(tree,"SU",true); |
> |
tree:=insert(tree,"SALI",true);
|
> |
tree:=insert(tree,"EPIERAI",true);
|
> |
tree:=insert(tree,"EPIERA",true);
|
> |
tree:=insert(tree,"EPIERAS",true);
|
> |
tree:=insert(tree,"JEU",true);
|
On obtient la
représentation en listes imbriquées correspondant à l'exemple précédent.
La procédure
width
, utilisée par la procédure
drawtree ,
calcule la largeur de l'arbre tree
:
> |
width:=proc(tree::list)
local s,nb,level,maxlevel,i;
level:=-1: maxlevel:=0: s:=convert(tree,string);
for i to length(s) do
if s[i]="[" then
level:=level+1:
if level>maxlevel then maxlevel:=level end if:
if assigned(nb[level]) then nb[level]:=nb[level]+1 else
nb[level]:=1 end if
elif s[i]="]" then
level:=level-1
end if:
end do:
`if`(maxlevel>0,max(seq(nb[k],k=1..maxlevel)),1)
end proc:
|
> |
with(plottools): with(plots): |
Warning, the names arrow and changecoords have been redefined
La procédure drawtree permet une représentation graphique de l'arbre tree :
> |
drawtree:=proc(tree::list)
local dr,P;
dr:=proc(t::list,leftlim,oldx,oldy)
local x,y,nb,i,l;
l:=leftlim;
nb:=width(t);
x:=l+iquo(50*nb,2);
y:=oldy+80;
if op(1,t)<>"" then
P:=P,textplot([x,y+10,op(1,t)],color=blue,font=[HELVETICA,BOLD,12]),display(line([x,y-5],[oldx,oldy]))
end if;
for i from 2 to nops(t) do
dr(t[i],l,x,y+20):
nb:=max(nb,width(t[i]));
l:=l+(nb-1)*50;
end do
end proc:
P:=NULL: dr(tree,0,0,0): display(P,axes=none)
end proc:
|
La procédure
delete
permet de supprimer le mot
word de l'arbre
tree :
en fait la procédure ne fait que supprimer dans
tree le point
suivant le dernier caractère de word
.
Le mot disparaît ainsi du dictionnaire mais garde son rôle de préfixe
éventuel pour d'autres mots.
> |
delete:=proc(tree::list,word::string)
local del,t;
del:=proc(a::list,s::string)
local m,i;
m:=s:
for i from 2 to nops(a) do
m:=cat(m,op(1,a[i])[1]):
if op(1,a[i])[2]="." then
t:=insert(t,m,`if`(m=word,false,true))
end if;
procname(a[i],m):
m:=s
end do:
end proc:
t:=[""]: del(tree,""); t
end proc:
|
> |
tree; delete(tree,"EPIER"); |
Le point derrière le "R"
de "EPIER" a été supprimé.
La procédure deletenode
permet de supprimer de l'arbre
tree tous les
descendants de node
, c'est à dire tous les mots dont
node
était un préfixe:
> |
deletenode:=proc(tree::list,node::string)
local del,n,t;
del:=proc(a::list,s::string)
local m,i,l,b;
m:=s:
for i from 2 to nops(a) do
m:=cat(m,op(1,a[i])[1]): l:=length(m):
if op(1,a[i])[2]="." then b:=true else b:=false end if:
if l<n or (l>=n and m[1..n]<>node ) then t:=insert(t,m,b) end if;
procname(a[i],m):
m:=s
end do:
end proc:
t:=[""]: n:=length(node): del(tree,""); t
end proc:
|
> |
tree; deletenode(tree,"EPIER"); drawtree(%);
|
Parcours récursif en
préordre
de l'arbre tree
, dans le sens: nœud - fils
1 - fils
2 ... - fils
n .
> |
preorder:=proc(tree::list)
local path, disp;
disp:=proc(t::list)
local k;
path:= path,op(1,t);
for k from 2 to nops(t) do
procname(t[k]);
end do;
end proc;
path:=NULL; disp(tree); path
end proc:
|
La procédure récursive
find
permet de trouver
word dans l'arbre
tree : elle
retourne true
(ou false
) suivant que word
a été (ou non) trouvé dans
tree
.
> |
find:=proc(tree::list,word::string)
local letter,i;
if word="" and op(1,tree)[2]="." then return true end if;
letter:=word[1];
for i from 2 to nops(tree) do
if op(1,tree[i])[1]=letter then return
procname(tree[i],word[2..length(word)]) end if
end do;
false
end proc:
|
> |
find(tree,"EPI"),find(tree,"EPIE"),find(tree,"EPIER"),find(tree,"EPIERAI"),
find(tree,"JE"),find(tree,"JEU");
|
Procédure permettant de
constituer un dictionnaire de mots à partir de l'arbre
tree
:
> |
makedict:=proc(tree::list)
local dict,words;
dict:=proc(t::list,s::string)
local word,i;
word:=s:
for i from 2 to nops(t) do
word:=cat(word,op(1,t[i])[1]):
if op(1,t[i])[2]="." then words:=words,word end if;
procname(t[i],word):
word:=s
end do:
end proc:
words:=NULL: dict(tree,""): [words]
end proc:
|
Second exemple à partir
d'une liste triée comportant davantage de mots:
> |
tree1:=[""]:
txt:=sort(["ENTRER","FIL","EGEEN","EGAL","GRASSES","EMULE","FINE","FINAL","EMUE","FILS","EGEE",
"GRASSE","FINES","EMUS","FILE","GRAS","GRAPPE","EGO","EMU","ENTREE","FINS"]);
for k in txt do tree1:=insert(tree1,k,true) od: tree1;
|
Troisième exemple à
partir d'un texte-source (ici un poème de Léo Ferré):
> |
txt:="La mémoire et la mer
La marée, je l'ai dans le cœur
Qui me remonte comme un signe
Je meurs de ma petite sœur,
de mon enfance et de mon cygne
Un bateau, ça dépend comment
On l'arrime au port de justesse
Il pleure de mon firmament
Des années lumières et j'en laisse
Je suis le fantôme jersey
Celui qui vient les soirs de frime
Te lancer la brume en baiser
Et te ramasser dans ses rimes
Comme le trémail de juillet
Où luisait le loup solitaire
Celui que je voyais briller
Aux doigts de sable de la terre
Rappelle-toi ce chien de mer
Que nous libérions sur parole
Et qui gueule dans le désert
Des goémons de nécropole
Je suis sûr que la vie est là
Avec ses poumons de flanelle
Quand il pleure de ces temps là
Le froid tout gris qui nous appelle
Je me souviens des soirs là-bas
Et des sprints gagnés sur l'écume
Cette bave des chevaux ras
Au raz des rocs qui se consument
Ö l'ange des plaisirs perdus
Ö rumeurs d'une autre habitude
Mes désirs dès lors ne sont plus
Qu'un chagrin de ma solitude
Et le diable des soirs conquis
Avec ses pâleurs de rescousse
Et le squale des paradis
Dans le milieu mouillé de mousse
Reviens fille verte des fjords
Reviens violon des violonades
Dans le port fanfarent les cors
Pour le retour des camarades
Ö parfum rare des salants
Dans le poivre feu des gerçures
Quand j'allais, géométrisant,
Mon âme au creux de ta blessure
Dans le désordre de ton cul
Poissé dans des draps d'aube fine
Je voyais un vitrail de plus,
Et toi fille verte, mon spleen
Les coquillages figurant
Sous les sunlights cassés liquides
Jouent de la castagnette tant
Qu'on dirait l'Espagne livide
Dieux de granits, ayez pitié
De leur vocation de parure
Quand le couteau vient s'immiscer
Dans leur castagnette figure
Et je voyais ce qu'on pressent
Quand on pressent l'entrevoyure
Entre les persiennes du sang
Et que les globules figurent
Une mathématique bleue,
Sur cette mer jamais étale
D'où me remonte peu à peu
Cette mémoire des étoiles
Cette rumeur qui vient de là
Sous l'arc copain où je m'aveugle
Ces mains qui me font du fla-fla
Ces mains ruminantes qui meuglent
Cette rumeur me suit longtemps
Comme un mendiant sous l'anathème
Comme l'ombre qui perd son temps
À dessiner mon théorème
Et sous mon maquillage roux
S'en vient battre comme une porte
Cette rumeur qui va debout
Dans la rue, aux musiques mortes
C'est fini, la mer, c'est fini
Sur la plage, le sable bêle
Comme des moutons d'infini...
Quand la mer bergère m'appelle
Léo Ferré":
|
> |
txt:=sort(StringTools[Split](txt," :!,.';\n")): |
> |
tree2:=[""]:
for k in txt do tree2:=insert(tree2,k,true) od: |
> |
find(tree2,"fjord"),find(tree2,"fjords");
|
|