Prof. Dr. R. Laue                                                                                                                                  SS00
                                Informatik II
                                Übungsblatt 8












Lösung Aufgabe 17 (14 Programmierpunkte - Abgabe per email)

}/* aufgabe 17 */
#define FEHLER 1000
#include <stdio.h>
static insert_baum_000000_co();
static print_baum_000000_co();
static delete_baum_000000_co();

struct knoten {
         struct knoten *links;
         struct knoten *rechts;
         int wert;
         int rang;
         };

#define RECHTERNACHFOLGERSCHWARZ(a) \
                ( ((*a) -> rechts == NULL) || \
                  ((*a)->rechts->rang < ((*a)->rang)) )
#define LINKERNACHFOLGERSCHWARZ(a) \
                ( ((*a) -> links == NULL) || \
                  ((*a)->links->rang < ((*a)->rang)) )

struct knoten *new_knoten(int wert)
         {
         struct knoten *hilf;
         hilf = (struct knoten *) calloc(1,sizeof(struct knoten));
         if (hilf == NULL)
                 return hilf;
         hilf -> links = NULL;
         hilf -> rechts = NULL;
         hilf -> wert = wert;
         hilf -> rang = 0;
         return hilf;
         }
 

delete_baum_000000(struct knoten **wurzel, int wert)
// rueckgabe 0 = ohne fehler
//           2 = wert war nicht drin
//           FEHLER sonst
        {
        return delete_baum_000000_co(NULL,wurzel,wert);
        }
 

static delete_baum_000000_co(
        struct knoten **papa,
        struct knoten **wurzel,
        int wert)
        {
        int res;
        struct knoten **neu;
        struct knoten **bruder;
        if (*wurzel == NULL) /* wert nicht gefunden  */ return 2;
 

        // suchen
        if ((*wurzel) ->wert == wert) // gefunden
                {
                struct knoten *zeiger;
                if (
                        (papa != NULL) &&
                        (((*wurzel) ->rechts) == NULL)  &&
                        (((*wurzel) ->links) == NULL) &&
                        (((*papa)->rang) == 1)
                   )
                // es wird ein schwarzes blatt geloescht
                // das gibt ein rang problem
                        {
                        free(*wurzel);
                        *wurzel = NULL;
                        return 1;
                        }
                else if (
                        (((*wurzel) ->rechts) == NULL)  &&
                        (((*wurzel) ->links) == NULL)
                   )
                   // es wird ein rotes blatt geloescht
                  // oder die alleinige wurzel
                        {
                        free(*wurzel);
                        *wurzel = NULL;
                        return 0; // fertig
                        }
                else if ( (((*wurzel) ->links) == NULL))
                        // vater eines blattes
                        {
                        zeiger = (*wurzel) ->rechts;
                        free(*wurzel);

                        *wurzel = zeiger;
                        return 0; // fertig
                        }
                 else if ( (((*wurzel) ->rechts) == NULL))
                        // vater eines blattes
                        {
                        zeiger = (*wurzel) ->links;
                        free(*wurzel);
                        *wurzel = zeiger;
                        return 0; // fertig
                        }
                // es muss der austausch wert gefunden werden
                zeiger = (*wurzel) ->rechts;
                while (zeiger != NULL)
                        {
                        wert = zeiger->wert;
                        zeiger = zeiger->links;
                        }
                (*wurzel) ->wert = wert; // der austausch;
                neu =  &  ((*wurzel) ->rechts);
                }
        else if ((*wurzel) ->wert > wert) {
                neu =  &  ((*wurzel) ->links);
                }
        else    {
                neu =  &  ((*wurzel) ->rechts);
                }
        res =  delete_baum_000000_co( wurzel, neu,wert);
 

#define RANG(a) (((*a) == NULL) ? -1 : ((*a)->rang))

        if (res == 2) return 2;
        if (res == 0) return 0;
        if (res == FEHLER) return FEHLER;

        if (wurzel == NULL) return 0; // leerer baum

// hier werden die rangstoerungen behoben
// zwischen neu und wurzel muss sie liegen

        if ((RANG(wurzel) - RANG(neu)) == 1) return 0;
        /* in der rekursion muss nicht weiter gemacht werden  */
        if ((RANG(wurzel) - RANG(neu)) !=  2)
                {
                return FEHLER; // sollte nicht sein
                }

// zuerst der fall dass sich die rangstoerung fortsetzt
// d.h. es gibt zu neu keinen roten bruder
// und der schwarze bruder hat keine roten nachfolger

// bruder zeiger
        bruder = ( neu ==  &((*wurzel)->links) ) ?  &((*wurzel)->rechts) : &((*wurzel)->links)  ;

// bruder kann nicht der nullzeiger sein
        if (bruder == NULL) {
                return FEHLER; // sollte nicht sein
                }

        if (RANG(bruder) < RANG(wurzel))
                if (RANG(bruder) >  RANG(& ((*bruder)->rechts)))
                if (RANG(bruder) >  RANG(& ((*bruder)->links)))
                        {(*wurzel)->rang --; return 1;}
// das war der einfache fall, dass sich die rangerniedrigung fortsetzt

// alle anderen faelle werden hier geloest und die delete routine mit return 0 beendet
 

#define BRUDERRECHTSROT() (( neu == &((*wurzel)->links) ) &&  (RANG(wurzel) == RANG(& ((*wurzel)->rechts))))
#define BRUDERLINKSROT() (( neu == &((*wurzel)->rechts) ) &&  (RANG(wurzel) == RANG(& ((*wurzel)->links))))
 

        if (BRUDERRECHTSROT()) { rot_links(wurzel);
                                papa = wurzel;
                                wurzel = & ((*wurzel)->links);
                                bruder =  & ((*wurzel)->rechts);
                                }
        else if (BRUDERLINKSROT()) { rot_rechts(wurzel);
                                papa = wurzel;
                                wurzel= & ((*wurzel)->rechts);
                                bruder =  & ((*wurzel)->links);
                                }

// die rangdifferenz besteht immer noch
// der (neue) bruder ist jetzt schwarz und kein blatt (wg rang)
        if (bruder == NULL) {
                return FEHLER; // sollte nicht sein
                }

#define OHNEROTEBRUEDER(a) ( (RANG(a) > RANG(& ((*a)->links) ))  && (RANG(a) > RANG(& ((*a)->rechts))))
#define ZWEIROTEBRUEDER(a) ( (RANG(a) == RANG(& ((*a)->links) ))  && (RANG(a) == RANG(& ((*a)->rechts))))
#define LINKERROTEBRUEDER(a) ( (RANG(a) == RANG(& ((*a)->links) )) )
#define RECHTERROTEBRUEDER(a) ( (RANG(a) == RANG(& ((*a)->rechts) )) )

        // printf("rangstoerung teil 2\n");
// jetzt nur noch faelle wo der bruder schwarz ist
// der rang der wurzel wird erniedrigt

        ((*wurzel) -> rang) --;
        if (neu == &((*wurzel)->links))
                {
                if (OHNEROTEBRUEDER(bruder))
                        {
                        return 0;
                        }
                if (ZWEIROTEBRUEDER(bruder))
                        {
                        rot_links(wurzel); // fertig
                         ((*wurzel) -> rang) ++;
                        return 0;
                        }
                if (LINKERROTEBRUEDER(bruder))
                        {
                        doppel_rot_rechtslinks(wurzel); // fertig
                         ((*wurzel) -> rang) ++;
                        return 0;
                        }
                if (RECHTERROTEBRUEDER(bruder))
                        {
                        rot_links(wurzel); // fertig
                         ((*wurzel) -> rang) ++;
                        return 0;
                        }
                }
        else    {
                if (OHNEROTEBRUEDER(bruder))
                        {
                        return 0;
                        }
                if (ZWEIROTEBRUEDER(bruder))
                        {
                        rot_rechts(wurzel); // fertig
                         ((*wurzel) -> rang) ++;
                        return 0;
                        }
                if (RECHTERROTEBRUEDER(bruder))
                        {
                        doppel_rot_linksrechts(wurzel); // fertig
                         ((*wurzel) -> rang) ++;
                        return 0;
                        }

                if (LINKERROTEBRUEDER(bruder))
                        {
                        rot_rechts(wurzel); // fertig
                         ((*wurzel) -> rang) ++;
                        return 0;
                        }
                }

        }
 

insert_baum_000000(struct knoten **wurzel, int wert)
// rueckgabe 0 = ohne fehler
//           2 = war schon drin
//           FEHLER sonst
        {
        return insert_baum_000000_co(NULL,NULL,wurzel,wert);
        }
 

static insert_baum_000000_co(
        struct knoten **opa,
        struct knoten **papa,
        struct knoten **wurzel,
        int wert)
         {
         int res;
         struct knoten **neu;
         if (*wurzel == NULL)
                 /* der baum ist noch leer */
                 {
                 *wurzel = new_knoten(wert);
                 if (*wurzel == NULL)
                         return FEHLER;
                 return 1;
                 }
 
 

         if ((*wurzel) ->wert == wert) return 2; // schon da;
         if ((*wurzel) ->wert > wert)
                neu =  &  ((*wurzel) ->links);
         else if ((*wurzel) ->wert < wert)
                neu =  &  ((*wurzel) ->rechts);

         res =  insert_baum_000000_co( papa, wurzel, neu,wert);

         if (res == 0) return 0; // keine rang korrektur mehr
         if (res == 2) return 2; // schon da
         if (res == FEHLER)  return FEHLER; // Fehler
         if (res == 1) // rang ueberpruefung
                {
                if (papa == NULL) return 0;
                if ((*papa)->rang != (*neu)->rang) return 1; // hier keine korrektur
                /* rotation rechts */
                        if (
                         RECHTERNACHFOLGERSCHWARZ(papa) && RECHTERNACHFOLGERSCHWARZ(wurzel)
                           )
                        return rot_rechts(papa);
                /* rotation  links */
                        if (
                         LINKERNACHFOLGERSCHWARZ(papa) && LINKERNACHFOLGERSCHWARZ(wurzel)
                           )
                        return rot_links(papa);
                /* doppel links rechts */
                        if (
                         RECHTERNACHFOLGERSCHWARZ(papa) && LINKERNACHFOLGERSCHWARZ(wurzel)
                           )
                        return doppel_rot_linksrechts(papa);
                /* doppel rechts links */
                        if (
                         LINKERNACHFOLGERSCHWARZ(papa) && RECHTERNACHFOLGERSCHWARZ(wurzel)
                           )
                        return doppel_rot_rechtslinks(papa);

                /* sonst rangerhoehung */
                (*papa)->rang ++;
                return 1;
                }
         // kann nicht sein
         }

print_baum_000000(struct knoten *wurzel)
        {
        print_baum_000000_co(wurzel,0);
        printf("\n");
        }
static print_baum_000000_co(struct knoten *wurzel,int level)
         {
         int i;
         if (wurzel != NULL)
                 {
                  print_baum_000000_co(wurzel->links,level+1);
                 for (i=0;i<3*level;i++) printf(" ");
                 printf("(%d:%d:%d \n",level,wurzel->rang,wurzel->wert);
                  print_baum_000000_co(wurzel->rechts,level+1);
                 }
         }

free_baum_000000(struct knoten *wurzel)
         {
         if (wurzel != NULL)
                 {
                  free_baum_000000(wurzel->links);
                  free_baum_000000(wurzel->rechts);
                  free(wurzel);
                 }
         }
 

rot_rechts(struct knoten **wurzel)
        {
        int wert;
        struct knoten * hilf;

        if (*wurzel == NULL) return FEHLER;
        wert =(*wurzel)->wert;
        hilf = *wurzel;
        *wurzel = (*wurzel)->links;
        hilf->links = (*wurzel)->rechts;
        (*wurzel)->rechts = hilf;
        return 0;
        }

rot_links(struct knoten **wurzel)
        {
        int wert;
        struct knoten * hilf;

        if (*wurzel == NULL) return FEHLER;
        wert =(*wurzel)->wert;
        hilf = *wurzel;
        *wurzel = (*wurzel)->rechts;
        hilf->rechts = (*wurzel)->links;
        (*wurzel)->links = hilf;
        return 0;
        }

doppel_rot_linksrechts(struct knoten **wurzel)
        {
        int wert;
        struct knoten * hilf;
        if (*wurzel == NULL) return FEHLER;
        wert =(*wurzel)->wert;
        if ( (*wurzel)->links == NULL) return FEHLER;
        hilf = (*wurzel)->links->rechts;
        (*wurzel)->links->rechts = hilf->links;
        hilf->links = (*wurzel)->links;
        (*wurzel)->links = hilf->rechts;
        hilf->rechts = (*wurzel);
        *wurzel = hilf;
        return 0;
        }

doppel_rot_rechtslinks(struct knoten **wurzel)
        {
        int wert;
        struct knoten * hilf;
        if (*wurzel == NULL) return FEHLER;
        wert =(*wurzel)->wert;
        if ( (*wurzel)->rechts == NULL) return FEHLER;
        hilf = (*wurzel)->rechts->links;
        (*wurzel)->rechts->links = hilf->rechts;
        hilf->rechts = (*wurzel)->rechts;
        (*wurzel)->rechts = hilf->links;
        hilf->links = (*wurzel);
        *wurzel = hilf;
        return 0;
        }
 
 

main()
{
        struct knoten *wurzel = NULL,*z;
        int i,wert;
        int n;

        scanf("%d",&n);

        for (i=0;i<n;i++)
                insert_baum_000000(&wurzel,rand()%n);
 

        print_baum_000000(wurzel);

        for (i=0;i<n;i++)
                {
 
                wert = i;
                printf("delete wert = %d\n",wert);
                delete_baum_000000(&wurzel,wert);
                }

        print_baum_000000(wurzel);

        free_baum_000000(wurzel);

}