next up previous contents
suivant: Knapsack par recherche exhaustive monter: Corrigés des programmes précédent: Tas binomiaux   Table des matières

AVL

avl.c


#include<stdio.h>
#include<malloc.h>
#include"avl.h"

/*------------------------------------------------------*/

/*
  Noeud de l'ABR.
 */

typedef struct nd
{
  /*
    key est la cle du noeud courant.
   */
  int key;

  /*
    pointeur vers l'element de cle key
   */
  void* data;

  /*
    hauteur du sous-arbre : 
    0 si ce noeud est une feuille. 
   */
  int height;
  
  /*
    Pointeur vers le sous-arbre droit.
   */
  struct nd * left;

  /*
    Pointeur vers le sous-arbre gauche.
   */
  struct nd * right;  
}node;

/*------------------------------------------------------*/

/*
  Retourne la hauteur de l'arbre de racine l, 
  -1 si l est vide.
 */

int getHeight(node* l)
{
  if (l == NULL)
    return -1;
  return l->height;
}

/*------------------------------------------------------*/

/*
  Retourne la plus grande des deux valeurs i et j.
 */

int max(int i, int j)
{
  if (i < j)
    return j; 
  return i;
}

/*------------------------------------------------------*/

/*
  Met a jour la hauteur de la racine l en fonction des 
  hauteurs des racines des deux sous-arbres.
 */

void setHeight(node* l)
{
  if (l != NULL)
    {
        l->height = 1 + max(getHeight(l->left), getHeight(l->right));
    }
}

/*------------------------------------------------------*/

/*
  Cree un noeud contenant la donnee data, 
  ayant pour sous-arbre gauche l et 
  pour sous-arbre droit r.
*/

node* nodeCreate(int (*getKey)(void*), node* l, void* data, node* r)
{
  node* n = (node*)malloc(sizeof(node));
  if (n == NULL)
    error();
  n->data = data;
  n->left = l;
  n->right = r;
  n->key = getKey(data);
  setHeight(n);
  return n;
}

/*------------------------------------------------------*/

/*
  Retourne un avl vide
*/

avl* avlCreate(int (*getKey)(void*), void (*freeData)(void*))
{
  avl* a = (avl*)malloc(sizeof(avl));
  if (!a)
    error();
  a->getKey = getKey;
  a->freeData = freeData;
  a->root = NULL;
  return a;
}

/*------------------------------------------------------*/

/*
  Fait de freeData la fonction de destruction des donnees.
*/

void avlSetFreeFunction(avl* a, void (*freeData)(void*))
{
  a->freeData = freeData;
}

/*------------------------------------------------------*/

/*
  Affiche toutes les cles du sous-arbre de racine n dans 
  l'ordre croissant.
*/

void nodePrintKeys(node* n)
{
  if(n)
    {
      printf("(");
      nodePrintKeys(n->left);
      printf(", %d, ", n->key );
      nodePrintKeys(n->right);
      printf(")");
    }
}

/*------------------------------------------------------*/

/*
  Affiche pour tous les noeuds du sous-arbre de racine n
  la difference entre les hauteurs du sous-arbre droit et 
  gauche.
*/

void nodePrintLevels(node* n)
{
  if(n)
    {
      printf("(");
      nodePrintLevels(n->left);
      printf(", %d, ", getHeight(n->left)- getHeight(n->right));
      nodePrintLevels(n->right);
      printf(")");
    }
}

/*------------------------------------------------------*/

/*
  Effectue une rotation droite de l'arbre de racine x, 
  retourne la racine de l'arbre apres rotation.
 */

node* rotateRight(node* x)
{
  node* y = x->left;
  node* b = y->right;
  y->right = x;
  x->left = b;
  setHeight(x);
  setHeight(y);  
  return y;
}

/*------------------------------------------------------*/

/*
  Effectue une rotation gauche de l'arbre de racine x, 
  retourne la racine de l'arbre apres rotation.
 */

node* rotateLeft(node* x)
{
  node* y = x->right;
  node* b = y->left;
  y->left = x;
  x->right = b;
  setHeight(x);
  setHeight(y);  
  return y;
}

/*------------------------------------------------------*/

/*
  Effectue une rotation gauche-droite de l'arbre de racine x, 
  retourne la racine de l'arbre apres rotation.
 */

node* rotateLeftRight(node* x)
{
  x->left = rotateLeft(x->left);
  return rotateRight(x);
}

/*------------------------------------------------------*/

/*
  Effectue une rotation droite-gauche de l'arbre de racine x, 
  retourne la racine de l'arbre apres rotation.
 */

node* rotateRightLeft(node* x)
{
  x->right = rotateRight(x->right);
  return rotateLeft(x);
}

/*------------------------------------------------------*/

/*
  Reequilibre l'arbre de racine x, retourne la racine de 
  l'arbre apres reequilibrage. On part du principe 
  que les hauteurs des sous-arbres droit et gauche different 
  de au plus 1.
*/

node* balance(node* x)
{
  if (x != NULL)
    {
      setHeight(x);
      if (getHeight(x->left) + 2 == getHeight(x->right))
	{
	  if(getHeight(x->left) + 1 == getHeight(x->right->right))
	    return rotateLeft(x);
	  else
	    return rotateRightLeft(x);
	}
      if (getHeight(x->left) == getHeight(x->right) + 2)
	{
	  if(getHeight(x->left->left) == getHeight(x->right) + 1)
	    return rotateRight(x);
	  else
	    return rotateLeftRight(x);
	}
    }
  return x;
}

/*------------------------------------------------------*/

/*
  Insere la donnee v dans l'arbre de racine n 
  et reequilibre l'arbre, retourne la racine de 
  l'arbre apres insertion et reequilibrage.
 */

node* nodeInsert(int (*key)(void*), node* n, void* v)
{
  if(n == NULL)
    return nodeCreate(key, NULL, v, NULL);
  if(key(v) == n->key)
    return n;
  if(key(v) < n->key)
    n->left = nodeInsert(key, n->left, v);
  else
    n->right = nodeInsert(key, n->right, v);
  return balance(n);
}

/*------------------------------------------------------*/

/*
  Insere la donnee v dans l'arbre a, O(log n).
*/

void avlInsert(avl* a, void* v)
{
  a->root = nodeInsert(a->getKey, (node*)a->root, v);
}

/*------------------------------------------------------*/
 
/*
  Affiche les cles de l'AVL a dans l'ordre croissant, O(n)
*/

void avlPrintKeys(avl* a)
{
  nodePrintKeys((node*)a->root);
  printf("\n");
}

/*------------------------------------------------------*/
 
/*
  Affiche pour chaque noeud la difference entre les hauteurs 
  des sous-arbres droit et gauche de l'AVL. 
*/

void avlPrintLevels(avl* a)
{
  nodePrintLevels((node*)a->root);
  printf("\n");
}

/*------------------------------------------------------*/

/*
  Retourne la donnee de cle k si elle se trouve dans le sous-arbre 
  de racine n, NULL sinon.
*/

void* findNode(node* n, int k)
{
  if (n == NULL)
    return NULL;
  if (n->key == k)
    return n->data;
  if (k < n->key)
    return findNode(n->left, k);
  else
    return findNode(n->right, k);
}
 
/*------------------------------------------------------*/
 
/*
  Retourne la donnee de cle x si elle se trouve dans l'AVL a,
  NULL sinon, O(log n)
*/

void* avlFind(avl* a, int x)
{
  return findNode((node*)a->root, x);
}

/*------------------------------------------------------*/

/*
  Fait pointer *max vers le noeud de cle maximale dans 
  le sous-arbre de racine n, detache le noeud *max de l'arbre
  et retourne la racine de l'arbre apres suppression.
*/

node* removeMax(node* n, node** max)
{
  if (n == NULL)
    {
      *max = NULL;
      return NULL;
    }
  if (n->right == NULL)
    {
      *max = n;
      return NULL;
    }
  n->right = removeMax(n->right, max);
  return balance(n);
}

/*------------------------------------------------------*/

/*
  Fait pointer *min vers le noeud de cle minimale dans 
  le sous-arbre de racine n, detache le noeud *min de l'arbre
  et retourne la racine de l'arbre apres suppression.
*/

node* removeMin(node* n, node** min)
{
 if (n == NULL)
    {
      *min = NULL;
      return NULL;
    }
  if (n->left == NULL)
    {
      *min = n;
      return NULL;
    }
  n->left = removeMin(n->left, min);
  return balance(n);
}

/*------------------------------------------------------*/

/*
  Supprime le noeud de cle k du sous-arbre de racine n,
  applique la fonction de destruction a la donnee de ce noeud,
  et retourne la racine de l'arbre apres la suppression.  
*/

node* removeNode(node* n, int k, void (*freeData)(void*))
{
  node* p;
  if (n == NULL)
    return NULL;
  if (k == n->key)
    {
      p = NULL;
      n->left = removeMax(n->left, &p);
      if (p == NULL)
	n->right = removeMin(n->right, &p);
      if (p != NULL)
	{
	  p->left = n->left;
	  p->right = n->right;
	}
      freeData(n->data);
      free(n);
      return balance(p);
    }
  if (k < n->key)
    n->left = removeNode(n->left, k, freeData);
  else
    n->right = removeNode(n->right, k, freeData);
  return balance(n);
}

/*------------------------------------------------------*/
 
/*
  Supprime le noeud de cle k de l'AVL a, applique la fonction 
  de destruction a la donnee de cle k, O(log n).
*/

void avlRemove(avl* a, int k)
{
  a->root = removeNode((node*)a->root, k, a->freeData);
}

/*------------------------------------------------------*/

/*
  Place dans la liste chainee l toutes les donnees 
  du sous-arbre de racine n dans l'ordre croissant.
 */

void nodeToList(node* n, linkedList* l)
{
  if (n != NULL)
    {
      nodeToList(n->left, l);
      linkedListAppend(l, n->data);
      nodeToList(n->right, l);      
    }
}

/*------------------------------------------------------*/

/*
  Retourne une liste chainee contenant toutes les donnees
  de l'AVL a disposees dans l'ordre croissant, O(n).
 */

linkedList* avlToList(avl* a)
{
  linkedList* l = linkedListCreate();
  nodeToList((node*)a->root, l);
  return l;
}

/*------------------------------------------------------*/

/*
  Detruit tous les noeuds du sous-arbre de racine n, 
  applique la fonction de destruction fr a toutes les 
  donnees du sous-arbre.
*/

void nodeDestroy(node* n, void (*fr)(void*))
{
  if (n != NULL)
    {
      nodeDestroy(n->left, fr);
      nodeDestroy(n->right, fr);      
      fr(n->data);
      free(n);
    }
}
  
/*------------------------------------------------------*/

/*
  Detruit l'AVL a, applique la fonction de destruction a 
  toutes les donnees du sous-arbre, O(n).
*/

void avlDestroy(avl* a)
{
  nodeDestroy((node*)a->root, a->freeData);
  free(a);
}

/*------------------------------------------------------*/
/*------------------------------------------------------*/

/*
Pour tester les algorithmes
*/

void destroyInt(void* i)
{
  free((int*)i);
}

int getIntKey(void* i)
{
  return *((int*)i);
}

void doNothing()
{
  
}

int main()
{
  int i;
  int* d;
  linkedList* l;
  link* m;
  avl* a = avlCreate(getIntKey, destroyInt);
  for (i = 0 ; i < 40 ; i++)
    {
      d = (int*)malloc(sizeof(int));
      *d = i;
      avlInsert(a, d);
    }
  avlPrintKeys(a);
  avlPrintLevels(a);
  for(i = 0 ; i < 40 ; i+=5)
    avlRemove(a, i);
  avlPrintKeys(a);
  avlPrintLevels(a);
  l = avlToList(a);
  for(m = linkedListGetFirst(l); m != NULL ; m = m->next)
    printf("%d -> ", *(int*)(m->data));  
  printf("\n");
  linkedListDestroy(l, doNothing);
  avlSetFreeFunction(a, destroyInt);
  avlDestroy(a);
  return 0;
}


next up previous contents
suivant: Knapsack par recherche exhaustive monter: Corrigés des programmes précédent: Tas binomiaux   Table des matières
klaus 2010-08-05