Passer au forum
Arbre binaire de re...
 
Notifications
Retirer tout

[Fermé] Arbre binaire de recherche en C (aide)

70 Messages
11 Utilisateurs
0 Réactions
5,757 Vues
Tchenou
Inscrit : 10.05.2008
Elite Grinder

Yop, pour un devoir d'info je dois implémenter un arbre binaire de recherche en C et j'ai un peu de mal (pas trop suivi les labos j'avoue :D )

Si y a queulqu'un de doué en C et qui s'y connait un peu en arbre, à qui ca ne prendrait pas trop de temps de m'expliquer vite fait deux trois trucs (suis à la bourre ) je suis preneur

Merci :D

A titre d'info voila le code que j'ai recu et que je dois compléter

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

struct node {
struct node *lChild; //Pointeur vers le fils gauche.
struct node *rChild; //Pointeur vers le fils droit.
int value; //Valeur, ou cle, du noeud.
};

struct tree {
struct node *root; //Pointeur vers l'element racine;
};

struct tree* constructNewTree()
{
//Fonction qui alloue un arbre vide.
struct tree *T=malloc(sizeof(struct tree));
T->root=NULL;

return T;
}

void insertKey(int i, struct tree *T)
{
//Completer la fonction pour qu'elle insere l'element i dans l'arbre T.

}

}

bool findKey(int i, struct tree *T)
{
//Completer la fonction pour qu'elle retourne true si i est dans l'arbre T, et false sinon.
}

void deleteKey(int i, struct tree *T)
{
//Completer la fonction pour qu'elle supprime l'element i dans l'arbre T.
}

void inOrder(struct tree *T)
{
//Completer la fonction pour obtenir un parcour recursif "en-ordre" de l'arbre T.
}

void deleteTree(struct tree *T)
{
//Ecrire les instructions pour supprimer l'arbre T:
//1) effacer tous les noeuds encore presents dans l'arbre
//2) faire un free() du pointeur T
//3) mettre T à NULL

}

int main()
{
struct tree *T;
T=constructNewTree();

insertKey(5,T);
insertKey(2,T);
insertKey(9,T);
insertKey(1,T);

inOrder(T);

deleteTree(T);
return 0;
}

J'ai surtout du mal avec les variables tree et constructNewTree, j'ai un peu du mal a voir leur utilité et ce que ca change pour après.

C'est surtout la fonction insertNewKey qui me pose défaut, dès que je la trouve, le reste devrait aller tout seul c'est assez semblable.


69 réponses
djeeNiva
Inscrit : 18.03.2008
PokerStrategist

La insertKey doit insérer dans le premier noeud vide ? a droite ? a gauche ?
Toutes les fonctions doivent être récursives ?
InserKey :
Test si T->root est null
Si oui
struct node *N=malloc(sizeof(struct node));
N->i=i
N->lChild=null
N->rChild=null
T->root=N
Sinon
//la je sais pas si faut inserer dans sous arbre droit ou gauche ou parcourir //pour trouver le premier noeud droit ou gauche null d'un mem niveau ??
//insérer a droite :
insertKey(i, T->root->lchild)
//a gauche
insertKey(i, T->root->rchild)
// un parcours pour trouver le premier null a gauche ou droite est plus compliqué, faudrais faire une fonction récursive je pense
fi

pas plus d'info ?

la findkey est facile en recursive ...


Tchenou Auteur du sujet
Tchenou
Inscrit : 10.05.2008
Elite Grinder

La première partie de ce projet consiste à compléter le code source ci-joint, qui contient
déjà les types structurés nécessaires pour implémenter un arbre binaire de recherche classique.
Nous vous demandons, en particulier, d’implémenter les opérations suivantes :
void insertKey(int i, struct tree *T) qui insère l’entier i dans l’arbre binaire de
recherche T. N’oubliez pas que l’insertion s’effectue en feuille.
void deleteKey(int i, struct tree *T) qui supprime l’entier i dans l’arbre binaire de
recherche, pour peu que celui-ci soit présent dans l’arbre. Utilisez la méthode vue au cours :
si le noeud contenant i dispose d’un fils gauche et d’un fils droit, il faut trouver un remplaçant
pour i.
bool findKey(int i, struct tree *T) qui retourne true (=vrai) ou false (=faux)
selon que l’élément i se trouve effectivement dans l’arbre.
1
void inOrder(struct tree *T) qui affiche un parcours de l’arbre "en-ordre" de façon
récursive, comme vue au cours.
Pour chacune de ces opérations, le rapport décrira votre méthode, et indiquera la complexité,
en notation grand-O(). Exprimez la complexité dans le pire cas en fonction de la
hauteur de l’arbre h et/ou en fonction de n (le nombre d’éléments dans l’arbre), si cela est
pertinent.

Pas d'info sur la récursivité, pas sur qu'on l'ait vu au cours mais ca me parait aussi le plus naturel ici.


chika78
Inscrit : 06.08.2009
PokerStrategist

Voilà un lien vers un cours sur le sujet en c++
http://www.cprogramming.com/tutorial/lesson18.html

Les concepts sont les mêmes, tu peux t'en inspirer.

Et sinon en effet, la récursivité est quasi incontournable pour un b-tree.


Tchenou Auteur du sujet
Tchenou
Inscrit : 10.05.2008
Elite Grinder

Ce que je ne saisis pas dans le lien, et dans ton code djeeNiva, c'est que dans le code source que mon prof m'a envoyé, la fonction intsertNewKey demande une valeur int et une valeur de type struct tree, pas une valeur de type node (dans le lien C++ c'est çà, et dans ton code, quand root =/= de NULL tu passes une node en argument non ?)

Ou alors j'ai pas tout compris :P


djeeNiva
Inscrit : 18.03.2008
PokerStrategist

Message original de Tchenou
Ce que je ne saisis pas dans le lien, et dans ton code djeeNiva, c'est que dans le code source que mon prof m'a envoyé, la fonction intsertNewKey demande une valeur int et une valeur de type struct tree, pas une valeur de type node (dans le lien C++ c'est çà, et dans ton code, quand root =/= de NULL tu passes une node en argument non ?)

Ou alors j'ai pas tout compris :P

Oui, mais la strcture tree c'est juste un pointeur sur un node en fait, donc tu peut passer le pointeur de pointeur node (passer donc &N en fait je crois) en le castant en pointeur tree, pas de soucis.

A priori y'a tout dans le lien que t'as filé chicka...
En fait faut surement insérer avec un ordre non ? genre le plus petit i au debut de l'arbre et ptet meme les pair a gauche et impair a droite ?


Tchenou Auteur du sujet
Tchenou
Inscrit : 10.05.2008
Elite Grinder

Arbe binaire de recherche :

Chaque noeud contient une valeur.

Le sous arbre gauche contient des valeurs plus petites.

Le sous abre droit contient des valeurs plus grandes.

Sinon pour le pointeur sur une node, je dois mal coder çà mais je me prends plein d'erreurs du type 'struct tree has no member name rChild' donc je dois foire quelque chose dans le pointage.

Exemple pour deleteTree

void deleteTree(struct tree *T)
{
//Ecrire les instructions pour supprimer l'arbre T:
//1) effacer tous les noeuds encore presents dans l'arbre
//2) faire un free() du pointeur T
//3) mettre T à NULL

if (T != NULL){
deleteTree(T->lChild);
deleteTree(T->rChild);
free(T);
}

}
J'ai droit à :

C:\Users\Session\Documents\INGENIEUR\DSA\ProjetInfo1\main.c||In function 'deleteTree :|
C:\Users\Session\Documents\INGENIEUR\DSA\ProjetInfo1\main.c|98|error: 'struct tree' has no member named 'lChild'|
C:\Users\Session\Documents\INGENIEUR\DSA\ProjetInfo1\main.c|99|error: 'struct tree' has no member named 'rChild'|
||=== Build finished: 2 errors, 0 warnings ===|


chika78
Inscrit : 06.08.2009
PokerStrategist

Ya un petit souci de fond, c'est que la struct tree ne contient qu'un pointeur vers une struct node (*root)

en gros elle ne sert à rien, autant travailler directement avec des struct node* partout

sinon ça ferait :

void deleteTree(struct tree *T)
{
//Ecrire les instructions pour supprimer l'arbre T:
//1) effacer tous les noeuds encore presents dans l'arbre
//2) faire un free() du pointeur T
//3) mettre T à NULL

if (T!=NULL && T->root != NULL){
deleteNode(T->root->lChild);
deleteNode(T->root->rChild);
free(T->root);
free(T);
T=NULL;
}

}

mais bon, ca oblige à écrire un deleteNode() recursif en +


Tchenou Auteur du sujet
Tchenou
Inscrit : 10.05.2008
Elite Grinder

Le problème c'est que

*Je suis quasiment sur que l'on ne peut pas modifier le code de base (ca sous entend les fonctions et leurs arguments)

*On ne peut pas rajouter des fonctions...


Tchenou Auteur du sujet
Tchenou
Inscrit : 10.05.2008
Elite Grinder

Et je trouve aussi qu'il a une drole de manière d'implémenter un arbre, parce que pour les versions que j'ai vue sur Internet ca a l'air beaucoup plus simple...


chika78
Inscrit : 06.08.2009
PokerStrategist

Regarde par là alors :

http://www.c.happycodings.com/Data_Structures/code2.html

Mais implémenter des fonctions directement sur le tree ok, il reste nécessaire d'avoir des fonctions sur les nodes... ?!?


Tchenou Auteur du sujet
Tchenou
Inscrit : 10.05.2008
Elite Grinder

(je t'ai envoyé une demande ami)

Ok donc apparemment il est permis de rajouter des fonctions mais tu ne peux pas toucher au main, donc on doit garder les fonctions qui font appel à l'arbre, et donc rajouter d'autres qui font appel a des nodes pour nous aider.

Tu ferais comment alors du coup la fonction InsertNewKey ?

Parce que quoi que je fasse j'ai des sales erreurs que j'arrive pas a corriger du style, mauvais type de fonction, machin attend un type x et tu lui donne un y, etc... X(


Tchenou Auteur du sujet
Tchenou
Inscrit : 10.05.2008
Elite Grinder

void insertKey(int i, struct tree *T)
{
//Completer la fonction pour qu'elle insere l'element i dans l'arbre T.

struct tree *pTree;
struct node* newNode;
newNode = (struct node*)malloc(sizeof(struct node));
newNode->value = i;
newNode->lChild = NULL;
newNode->rChild = NULL;

pTree = T;
if (T->root == NULL){
T->root = newNode;
printf("%d", T->root->value);
}

else {
if (T->root->value > i ) {

if (T->root->lChild == NULL){

T->root->lChild = newNode;
printf("%d", newNode->value);

}
else{

pTree->root = T->root->lChild;
insertKey(i, pTree);

}

}

if (T->root->value < i ) {

if (T->root->rChild == NULL){

T->root->rChild = newNode;
printf("%d", newNode->value);

}
else{

pTree->root = T->root->rChild;
insertKey(i, pTree);

}

}

}

}

Ca m'a l'air correct, et je n'ai rien changé au code de base en plus (les printf c'était pour vérifier que ca marchait)


djeeNiva
Inscrit : 18.03.2008
PokerStrategist

effectivement, me suis planté tu peux pas appeler l'insertkey de base avecun pointeur sur node ...
le mieux est d'en faire une avec comme param un node et dans l'insertkey initiale tu appel juste cette nouvelle avec t-root comme param


/inutile

je ne comprends rien.

/inutile

Bon courage!


jivjav
Inscrit : 20.02.2007
Elite Grinder

La structure tree et la fonction constructNewTree ne font certes pas grand chose mais imo elles sont là pour avoir un semblant de paradigme objet dans un contexte C qui ne l'exige pas. Bref, je trouve qu'elles sont plutôt judicieuses.

Le code de base est pas vraiment adapté à la récurrence je trouve (à cause de la structure Tree) même si c'est facile de l'adapter comme tu as fait.

Sans récurrence tu peux faire comme ça sinon. J'ai testé, ça marche.

void insertKey(int i, struct tree *T)
{
//Completer la fonction pour qu'elle insere l'element i dans l'arbre T.

struct node **cNode;
struct node* newNode;
newNode = (struct node*)malloc(sizeof(struct node));
newNode->value = i;
newNode->lChild = NULL;
newNode->rChild = NULL;

if (T->root == NULL){
T->root = newNode;
return;
}

cNode = &T->root;
while((*cNode) != NULL) {

if (i < (*cNode)->value) {
cNode = &((*cNode)->lChild);
}
else {
cNode = &((*cNode)->rChild);
}
}

(*cNode) = newNode;

}


toonnniii000
Inscrit : 01.12.2010
Elite Grinder

_o: _o: _o: :f_o: :f_o: :f_o:

Bonne chance, je comprends rien lol.


Tchenou Auteur du sujet
Tchenou
Inscrit : 10.05.2008
Elite Grinder

Apparemment il exige pour certaines des fonctions la récurrence donc je pense qu'elle est conseillée dans toute, tu peux me dire si d'après toi cet algorithme récurrent peut marcher ?

Je m'explique, ca compile et tout, mais pour certaines fonctiond dont je suis quasi sur du code, ca affiche de mauvais résultats (particulièrement une fonction plutôt simple qui dit si lélément se trouve dans l'arbre ou non, ca foire une fois sur deux)

Voila le code de mon InsertNewKey :
void insertKey(int i, struct tree *T)
{
//Completer la fonction pour qu'elle insere l'element i dans l'arbre T.

struct tree *pTree;
struct node* newNode;
newNode = (struct node*)malloc(sizeof(struct node));
newNode->value = i;
newNode->lChild = NULL;
newNode->rChild = NULL;

pTree = T;
if (T->root == NULL){
T->root = newNode;
}

else {
if (T->root->value > i ) {

if (T->root->lChild == NULL){

T->root->lChild = newNode;
}
else{

pTree->root = T->root->lChild;
insertKey(i, pTree);

}

}

if (T->root->value < i ) {

if (T->root->rChild == NULL){

T->root->rChild = newNode;
}
else{

pTree->root = T->root->rChild;
insertKey(i, pTree);

}

}

}

}

EDIT : pour être sur que tu te prennes pas la tête pour comprendre facilement : pTree c'est un élément de type pointeur sur arbre qui sert a parcourir ce dernier lors de la récurrence.


jivjav
Inscrit : 20.02.2007
Elite Grinder

Je vois au moins un problème dans cette fonction. C'est au niveau des comparaisons avec i. Tu regardes si c'est < ou si c'est > mais jamais si c'est =. A moins qu'il soit spécifié que chacune des valeurs d'un arbre de recherche doit être unique, ça pourrait poser problème.


jivjav
Inscrit : 20.02.2007
Elite Grinder

Message original de Tchenou
EDIT : pour être sur que tu te prennes pas la tête pour comprendre facilement : pTree c'est un élément de type pointeur sur arbre qui sert a parcourir ce dernier lors de la récurrence.

T'inquiètes, j'ai lu ton code, cf. la fonction que je t'ai codé dans le premier post.