2

I try to build a generic binary search tree module in Ada, and the tree will be the generic parameter, so, i do that:

-- Spécification du module ABR.


-- Mettre T_ABR comme un pointeur générique.
Generic
    type T_Noeud(<>);
        type T_ABR is access T_Noeud; -- Pointeur sur T_Noeud.


package ABR is


    Cle_Presente_Exception : Exception; -- une clé est déjà présente dans un ABR
    Cle_Absente_Exception  : Exception; -- une clé est absente d'un ABR


    -- Initialiser un Abr.  Abr est vide.
    -- Param Abr : L'arbre qu'on va initialiser.
    procedure Initialiser(Abr: out T_ABR) with
        Post => Est_Vide (Abr); -- Abr := Null.


    -- Est-ce qu'un Abr est vide ?
    -- Param Abr : L'arbre qu'on vaudra savoir si elle est vide.
    -- Retrun Boolean : Retourne True si Abr est vide, sinon False.
    function Est_Vide (Abr : T_Abr) return Boolean;


    -- Obtenir le nombre d'éléments d'un Abr. 
    -- Param Abr : L'arbre qu'on vaudra calculer sa taille.
        -- Retrun Integer : Retourne la taille de Abr.
    function Taille (Abr : in T_ABR) return Integer with
        Post => Taille'Result >= 0        -- Retourne une taille positive.
        and (Taille'Result = 0) = Est_Vide (Abr); -- If taille (Abr) = 0 then Abr := Null


    -- Insérer une clé associée à un nouveau noeud dans Abr.
    -- Param Abr : L'arbre où on veut insérer un noeud.
    -- Param Cle : La Clé correspondante au noeud qu'on veut insérer.
    -- Exception : Cle_Presente_Exception si la clé est déjà dans l'Abr.
    procedure Inserer (Abr : in out T_ABR ; Cle : in Integer) with
        Post => Taille (Abr) = Taille (Abr)'Old + 1; -- Un élément de plus.


    -- Supprimer la donnée associée à la clé Clé dans l'ABR Abr.
    -- Param Abr : L'arbre où on veut supprimer un noeud.
        -- Param Cle : La Clé correspondante au noeud qu'on veut supprimer.
    -- Exception : Cle_Absente_Exception si Clé n'est pas utilisée dans l'Abr
    procedure Supprimer (Abr : in out T_ABR ; Cle : in Integer) with
        Post =>  Taille (Abr) = Taille (Abr)'Old - 1; -- Un élément de moins.


    -- Supprimer tous les éléments d'un ABR.
    -- Doit être utilisée dès qu'on sait qu'un ABR ne sera plus utilisé.
    -- Param Abr : L'arbre à détruire.
    procedure Vider (Abr : in out T_ABR) with
        Post => Est_Vide (Abr);


    -- Afficher un ABR Abr dans l'ordre croissant des clés (parcours infixe)
    -- Param Abr : L'arbre à afficher.
    procedure Afficher (Abr : in T_Abr);


    -- Afficher un ABR Abr (en faisant apparaître la strucre grâce à une
    -- indendation et un signe '<', '>', '/' pour indiquer la sous-arbre
    -- gauche, '>' pour un sous arbre droit et '/' pour la racine)
    -- Exemple :
    --
    --  / Cle1 : Valeur1
    --      < Cle2 : Valeur2
    --          > Cle3 : Valeur3
    --      > Cle4 : Valeur 4
    --          < Cle5 : Valeur 5
    -- Param Abr : L'arbre à afficher.
    procedure Afficher_Debug (Abr : in T_Abr);


private


    type T_Noeud is
        record
            Cle: Integer;
            Sous_Arbre_Gauche : T_ABR;
            Sous_Arbre_Droit : T_ABR;
            -- Invariant
            --    Pour tout noeud N dans Sous_Arbre_Gauche, N.Cle < Cle.
            --    Pour tout noeud N dans Sous_Arbre_Droit,  N.Cle > Cle.
        end record;


end ABR;

then, I implemented the body of this module in abr.adb:

-- Implantation du module ABR.


with Ada.Text_IO;            use Ada.Text_IO;
with Ada.Unchecked_Deallocation;


package body ABR is


    -- Libérer la mémoire.
    procedure Free is
        new Ada.Unchecked_Deallocation (Object => T_Noeud, Name => T_ABR);


    procedure Initialiser(Abr: out T_ABR) is
    begin
        Abr := Null;
    end Initialiser;


    function Est_Vide (Abr : T_Abr) return Boolean is
    begin
        return Abr = Null;
    end;


    function Taille (Abr : in T_ABR) return Integer is
    begin
        if Est_Vide (Abr) then
            return 0;
        else
            return 1 + Taille (Abr.all.Sous_Arbre_Gauche) + Taille (Abr.all.Sous_Arbre_Droit);
        end if;
    end Taille;


    procedure Inserer (Abr : in out T_ABR ; Cle : Integer) is
    begin
        if (Est_Vide(Abr)) then 
            Abr := New T_Noeud'(Cle, Null, Null); 
            elsif (ABR.all.Cle = Cle) then
            raise Cle_Presente_Exception;
        elsif (Cle < Abr.all.Cle) then
                Inserer(Abr.all.Sous_Arbre_Gauche, Cle); 
            elsif (Cle > Abr.all.Cle) then
                Inserer(Abr.all.Sous_Arbre_Droit, Cle);   
        end if;
    end Inserer;


    procedure Supprimer (Abr : in out T_ABR ; Cle : in Integer) is
        tmp1 ,tmp2 : T_ABR;
    begin
        if (Abr = Null) then
            Null;
        else
            if (Cle < Abr.all.Cle) then 
                    Supprimer (Abr.all.Sous_Arbre_Gauche, Cle); 
            elsif (Cle > Abr.all.Cle) then
                            Supprimer (Abr.all.Sous_Arbre_Droit, Cle);
                else

                    if (Abr.all.Sous_Arbre_Gauche = Null) then  
                    tmp1 := Abr.all.Sous_Arbre_Droit; 
                        Free (Abr); 
                            Abr := tmp1; 

                    elsif (Abr.all.Sous_Arbre_Droit = Null) then 
                            tmp1 := Abr.all.Sous_Arbre_Gauche; 
                            Free (Abr); 
                            Abr := tmp1; 
                else 
                    tmp2 := Abr.all.Sous_Arbre_Droit;
                    while (not Est_Vide (tmp2) and tmp2.all.Sous_Arbre_Gauche /= Null) loop
                            tmp2 := tmp2.all.Sous_Arbre_Gauche;
                    end loop;
                    tmp1 := tmp2;

                    Abr.all.Cle := tmp1.all.Cle;
                    Supprimer (Abr.all.Sous_Arbre_Droit, tmp1.all.Cle);
                end if;
            end if;
        end if;
    end Supprimer;


    procedure Vider (Abr : in out T_ABR) is
    begin
        if not Est_Vide (ABR) then
            Vider (ABR.all.Sous_Arbre_Gauche);
            Vider (ABR.all.Sous_Arbre_Droit);
            free (ABR);
        end if;
    end Vider;


    procedure Afficher (ABR : in T_Abr) is
    begin
        if Est_Vide (ABR) then
                Afficher( Abr.all.Sous_Arbre_Gauche);
                Put_Line(Integer'Image(ABR.all.Cle));
                Afficher( ABR.all.Sous_Arbre_Droit);
        end if;
    end Afficher;


    procedure Afficher_Debug (Abr : in T_Abr) is
    begin
        if not Est_Vide (ABR) then
            Put_Line (Integer'Image(ABR.all.Cle));
            Afficher_Debug ( ABR.all.Sous_Arbre_Gauche);
            Afficher_Debug ( ABR.all.Sous_Arbre_Droit);
        end if;
    end Afficher_Debug;


end ABR;

And I created a test file for ABR module, but i don't know how i can instantiate the previous module :

-- Programme de test du module ABR.


with Ada.Text_IO;          use Ada.Text_IO;
with ABR;                  use ABR;


procedure Test_ABR is


    -- Instantiation du package ABR. 
    package ABR_Test is
            new ABR (T_Noeud => xxx);
        use ABR_Test;


    -- Initialisation des variables.
    Nb_Donnees : constant Integer := 10; -- Taille du tableau Cles.
    Cles : constant array (1..Nb_Donnees) of Integer -- Cles est un tableau 
    := (56, 78, 76, 27, 90, 23, 12, 43, 24, 39);     -- contenant des clés.


    -- Initialise l'ABR Abr commen un ABR vide dans lequel ont été insérées
    -- les cles Cles ci-dessus.
    procedure Construire_Exemple_Arbre (Annuaire : out T_ABR) is
    begin
        Initialiser (Annuaire);
        pragma Assert (Est_Vide (Annuaire));
        pragma Assert (Taille (Annuaire) = 0);

        for i in 1..Nb_Donnees loop
            Inserer (Annuaire, Cles (i));

            Put_Line ("Après insertion de la clé " & Cles (i));
            Afficher_Debug (Annuaire);
            New_Line;

            pragma Assert (not Est_Vide (Annuaire));
            pragma Assert (Taille (Annuaire) = i);
        end loop;

        Vider (Annuaire);
        pragma Assert (Est_Vide (Annuaire));
        pragma Assert (Taille (Annuaire) = 0);

        Put_Line ("Procédure Construire_Exemple_Arbre est exécuté avec succès.");
        New_Line;
    end Construire_Exemple_Arbre;


    procedure Tester_Exemple_Arbre is
        Annuaire : T_ABR;
    begin
        Construire_Exemple_Arbre (Annuaire);
        Vider (Annuaire);
        pragma Assert (Est_Vide (Annuaire));
        pragma Assert (Taille (Annuaire) = 0);

        Put_Line ("Procédure Tester_Exemple_Arbre est exécuté avec succès.");
        New_Line;
    end Tester_Exemple_Arbre;


    -- Tester suppression en commençant par supprimer les feilles.
    procedure Tester_Supprimer_Inverse is
        Annuaire : T_ABR;
    begin
        Put_Line ("Tester_Supprimer_Inverse...");
        New_Line;

        Construire_Exemple_Arbre (Annuaire);

        for i in reverse 1..Nb_Donnees loop

            Supprimer (Annuaire, Cles (i));

            Put_Line ("Après suppression de " & Cles (i) & " :");
            Afficher_Debug (Annuaire); 
            New_Line;
        end loop;

        Vider (Annuaire);

        Put_Line ("Procédure Tester_Supprimer_Inverse est exécuté avec succès.");
        New_Line;
    end Tester_Supprimer_Inverse;


    -- Tester suppression. Suppression de noeuds avec deux fils.
    procedure Tester_Supprimer is
        Annuaire : T_ABR;
    begin
        Put("Tester_Supprimer...");
        New_Line;

        Construire_Exemple_Arbre (Annuaire);

        for i in 1..Nb_Donnees loop
            Put_Line ("Suppression de " & Cles (i) & " :");

            Supprimer (Annuaire, Cles (i));

            Afficher_Debug (Annuaire); 
            New_Line;

        end loop;

        Vider (Annuaire);

        Put_Line ("Procédure Tester_Supprimer est exécuté avec succès.");
                New_Line;
    end Tester_Supprimer;

begin
    Tester_Exemple_Arbre;
    --Tester_Supprimer_Inverse;
    --Tester_Supprimer;
end Test_ABR;

Please, help me to solve this problem


1 Answers1

4

You don’t say what the compiler complains about in your code. However, I see something seriously wrong in your design, indicated by the compiler reporting

hamza.ada:82:09: generic type cannot have a completion

(it’s complaining about the fact that you have a full declaration of T_Noeud in the private part of package ABR).

Your generic package should take at least a formal parameter (in English, perhaps Item) to correspond to the type of object that you want to store in it. You might want to have a formal parameter for equality, typically

with function "=" (L, R : Item) return Boolean is <>;

Your generic package should then declare a public type to correspond to tree instances, e.g.

type Tree (<>) is private;

(or perhaps Arbre) and then in the private part you should declare all the supporting types (T_Noeud, T_ABR) needed to build Tree.

It should never be up to the user of your package to declare the types used to implement the abstraction.


Part of the problem instantiating ABR in the code as it stands is that the full declaration of T_Noeud thoroughly confuses the compiler, to the point where it rejects the instantiation, saying

designated type of actual does not match that of formal "T_ABR"
Simon Wright
  • 25,108
  • 2
  • 35
  • 62