Forum: PC-Programmierung Binärer Baum Ausgabe


von dulli (Gast)


Lesenswert?

hallo miteinander,

ich habe hier den code zum erstellen eines binären baumes, allerdings 
weiß ich aufgrund von der Rekursion nicht genau, wann ich die Werte der 
knoten ausgeben lassen muss.

Wäre freundlich, wenn ihr mir weiterhelfen könnt.
---------------------------------------------------------
1
#include<stdlib.h>
2
#include<stdio.h>
3
4
5
struct my_tree{
6
  int value;
7
  struct my_tree *left;
8
  struct my_tree *right;
9
};
10
11
struct my_tree *start = NULL;
12
13
---------------------------------------------------------
14
struct my_tree *create_tree(int *feld, int anzahl){
15
  
16
  struct my_tree *adr;
17
  int mitte;
18
19
  mitte = anzahl / 2;
20
  adr = (struct my_tree*) malloc(sizeof(struct my_tree));
21
  adr->value = feld[mitte];
22
23
  if (anzahl > 1){
24
    
25
    adr->left = create_tree(feld, mitte);  
26
    
27
  }
28
  else{
29
    adr->left = NULL;
30
  }
31
  
32
  if (anzahl > 1){
33
    
34
    adr->right = create_tree(feld + mitte + 1, anzahl - mitte - 1);
35
    
36
  }
37
  else{
38
    adr->right = NULL;
39
  }
40
41
  return adr;
42
}
43
44
---------------------------------------------------------
45
int main()
46
{
47
  int mynumbers[] = { 4, 12, 9, 10, 7, 13, 18, 6, 15, 24, 5 };
48
  int *feld = NULL;
49
  int anzahl = 11;
50
51
  feld = mynumbers;
52
  create_tree(feld,anzahl);
53
54
55
  system("pause");
56
  return 0;
57
}
---------------------------------------------------------------

: Bearbeitet durch User
von Klaus W. (mfgkw)


Lesenswert?

Wieso musst du sie ausgeben?

von dulli (Gast)


Lesenswert?

will den baum am ende ja auch irgendwie ausgeben.

Also mit ausgeben, meine ich in der Konsole anzeigen (printf)

von Pandur S. (jetztnicht)


Lesenswert?

Ich empfehl das Programm mal per Singlesteppen zu debuggen.

von dulli (Gast)


Lesenswert?

Das Problem: Haben den code so bekommen und verstehe ihn nicht wirklich, 
habbe das single debugging auch schon versucht.

Hätte jetzt gern eine ausgabe der einzelnen knoten, damit ich das 
Programm besser nachvollziehen kann.

von Jay (Gast)


Lesenswert?

dulli schrieb:
> Das Problem: Haben den code so bekommen

Siehst du, und da ist dein Problem. Schreib ihn selber. Dann verstehst 
du ihn auch.

> und verstehe ihn nicht
> wirklich,

Eben.

> habbe das single debugging auch schon versucht.
>
> Hätte jetzt gern eine ausgabe der einzelnen knoten, damit ich das
> Programm besser nachvollziehen kann.

Ausgaben aller Art können dir nicht mehr anzeigen als du beim Debuggen 
auch siehst. Wenn du unbedingt eine Ausgabe machen willst bietet sich an 
die Knoten direkt depth-first bei Aufbau des Baums auszugeben, oder eine 
nachfolgende Depth-first-, Breadth-first- oder andere Suche 
durchzuführen.

von Karl H. (kbuchegg)


Lesenswert?

Zumal eine Baumausgabe erschreckend trivial ist, solange man damit leben 
kann, dass er 'auf die Seite gelegt' ausgegeben wird.

Es gibt 3 Möglichkeiten
* postorder. Dabei wird von jedem Knoten zuerst sein linker Teilbaum,
  dann sein rechter Teilbaum und dann der Knoten selbst ausgegeben
* inorder: linker Teilbaum, Knoten, rechter Teilbaum
* preorder: Knoten, linker Teilbaum, rechter Teilbaum

Ich empfehle für den Anfang mal 'inorder'.

Um also einen Baum auszugeben, muss man einen Baum ausgeben können 
(wegen der Teilbäume). Klingt trivial und irgendwie selbstbezüglich, bis 
man realisiert, dass ein Teilbaum ja wohl kleiner sein wird, als der 
ganze Baum.
D.h. aber auch, die sich stellenden Teilprobleme werden (weil ja der 
Baum immer kleiner wird) auch immer einfacher. Bis man beim trivialen 
Fall angelangt ist, der da lautet: wie gibt man keinen Baum aus? Und die 
Antwort drauf ist simpel: indem man einfach gar nichts tut.
1
void printTree( my_tree* tree )
2
{
3
  if( tree == NULL )  // gibt es überhaupt einen Baum?
4
    return;           // Nope es gibt keine
5
6
  printTree( tree->left );        // linken Teilbaum ausgeben
7
  printf( "%d\n", tree->value );  // dann den Knoten selber
8
  printTree( tree->right );       // rechten Teilbaum ausgeben
9
}

und das wars dann auch schon.
Einen kleinen Twist sollte man noch machen: mit jedem Teilbaum sollte 
man eine Einrückungstiefe erhöhen, sonst ist es ein wenig schwer, die 
Baumstruktur an der Ausgabe zu erkennen.
Aber das lass ich als Übung für dich.

War doch gar nicht so schwer. Oder?
Gewöhn dich daran, Rekursion ist bei Bäumen etwas alltägliches. Das 
Prinzip ist immer das gleiche: Um eine Operation auf einen ganzen Baum 
anzuwenden, wendet man die Operation auf den linken Teilbaum an (da 
steckt eine Rekursion), auf den Knoten selbst und auf den rechten 
Teilbaum (da steckt eine weitere Rekursion). Und natürlich kommt noch 
der Trivialfall dazu: auf einen leeren Baum kann man keine Operation 
anwenden.

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Ach du bist das!
Der lineare Listen und Baum-Balanzierer

Dann wird mir alles klar.
Du übernimmst dich zur Zeit. Du willst zu viel auf einmal. Drum kriegst 
du auch nichts hin.

von Karl H. (kbuchegg)


Lesenswert?

dulli schrieb:
> Das Problem: Haben den code so bekommen und verstehe ihn nicht wirklich,
> habbe das single debugging auch schon versucht.
>
> Hätte jetzt gern eine ausgabe der einzelnen knoten, damit ich das
> Programm besser nachvollziehen kann.

Das wird dir da nicht viel helfen.
Single Steppen wird dir auch nicht viel helfen, da verfranst an sich im 
Debugger gerne in den Rekursionen.

Was dir aber unter Umständen was helfen würde, das ist, wenn die die 
Funktion einfach mal mit printf spicken würdest. Gerne auch mit 
Einrückungen in den Ausgaben, die dir die Schachtelungstiefen anzeigen. 
Zumindest mir hat das am Anfang sehr geholfen, wenn mir das Programm 
selbst erzählt hat, warum es was gemacht hat.

von dulli (Gast)


Lesenswert?

Hast du mal drübergeschaut ob die funktion create_tree stimmt?

Kann ich die Ausgabe wie bei den linearen Listen machen? Also, dass ich 
einen Start pointer auf die Wurzel habe und dann immer weiter im Baum 
durchgehe?

Denn wie man einen Teilbaum ausgibt war mir klar (trotzdem danke),
aber mir fällt nichts ein, wie ich den Baum als ganzes Ausgabe.

von Karl H. (kbuchegg)


Lesenswert?

Karl Heinz schrieb:

> Was dir aber unter Umständen was helfen würde, das ist, wenn die die
> Funktion einfach mal mit printf spicken würdest. Gerne auch mit
> Einrückungen in den Ausgaben, die dir die Schachtelungstiefen anzeigen.
> Zumindest mir hat das am Anfang sehr geholfen, wenn mir das Programm
> selbst erzählt hat, warum es was gemacht hat.

Das sieht dann zb so aus
1
#include "stdafx.h"
2
#include <stdio.h>
3
#include <stdlib.h>
4
5
struct my_tree{
6
  int value;
7
  struct my_tree *left;
8
  struct my_tree *right;
9
};
10
11
void printIndent( int n )
12
{
13
  int i;
14
  for( i = 0; i < n; i++ )
15
    printf( " " );
16
}
17
18
struct my_tree *create_tree(int *feld, int anzahl, int indent){
19
  
20
  struct my_tree *adr;
21
  int mitte;
22
  int i;
23
24
  printIndent( indent );
25
  printf( "Erzeuge Baum fuer [ " );
26
  for( i = 0; i < anzahl; i++ )
27
    printf( "%d ", feld[i] );
28
  printf( "]\n" );
29
30
  mitte = anzahl / 2;
31
32
  printIndent( indent );
33
  printf( "mittleres Element bei %d\n", mitte );
34
35
  adr = (struct my_tree*) malloc(sizeof(struct my_tree));
36
  adr->value = feld[mitte];
37
38
  printIndent( indent );
39
  printf( "Knoten erzeugen für %d\n", feld[mitte] );
40
41
  if (anzahl > 1){
42
    printIndent( indent );
43
    printf( "linken Teilbaum erzeugen\n" );
44
45
    adr->left = create_tree(feld, mitte, indent + 2);      
46
  }
47
  else{
48
    adr->left = NULL;
49
  }
50
  
51
  if (anzahl > 1){
52
    printIndent( indent );
53
    printf( "rechten Teilbaum erzeugen\n" );
54
    
55
    adr->right = create_tree(feld + mitte + 1, anzahl - mitte - 1, indent + 2 );
56
    
57
  }
58
  else{
59
    adr->right = NULL;
60
  }
61
  
62
  return adr;
63
}
64
65
66
int main()
67
{
68
  int mynumbers[] = { 4, 12, 9, 10, 7, 13, 18, 6, 15, 24, 5 };
69
  int *feld = NULL;
70
  int anzahl = 11;
71
72
  feld = mynumbers;
73
  create_tree(feld,anzahl,0);
74
75
76
  system("pause");
77
  return 0;
78
}

und wie man an der Ausgabe des Programms sehen kann
1
Erzeuge Baum fuer [ 4 12 9 10 7 13 18 6 15 24 5 ]
2
mittleres Element bei 5
3
Knoten erzeugen f³r 13
4
linken Teilbaum erzeugen
5
  Erzeuge Baum fuer [ 4 12 9 10 7 ]
6
  mittleres Element bei 2
7
  Knoten erzeugen f³r 9
8
  linken Teilbaum erzeugen
9
    Erzeuge Baum fuer [ 4 12 ]
10
    mittleres Element bei 1
11
    Knoten erzeugen f³r 12
12
    linken Teilbaum erzeugen
13
      Erzeuge Baum fuer [ 4 ]
14
      mittleres Element bei 0
15
      Knoten erzeugen f³r 4
16
    rechten Teilbaum erzeugen
17
      Erzeuge Baum fuer [ ]
18
      mittleres Element bei 0
19
      Knoten erzeugen f³r 9
20
  rechten Teilbaum erzeugen
21
    Erzeuge Baum fuer [ 10 7 ]
22
    mittleres Element bei 1
23
    Knoten erzeugen f³r 7
24
    linken Teilbaum erzeugen
25
      Erzeuge Baum fuer [ 10 ]
26
      mittleres Element bei 0
27
      Knoten erzeugen f³r 10
28
    rechten Teilbaum erzeugen
29
      Erzeuge Baum fuer [ ]
30
      mittleres Element bei 0
31
      Knoten erzeugen f³r 13
32
rechten Teilbaum erzeugen
33
  Erzeuge Baum fuer [ 18 6 15 24 5 ]
34
  mittleres Element bei 2
35
  Knoten erzeugen f³r 15
36
  linken Teilbaum erzeugen
37
    Erzeuge Baum fuer [ 18 6 ]
38
    mittleres Element bei 1
39
    Knoten erzeugen f³r 6
40
    linken Teilbaum erzeugen
41
      Erzeuge Baum fuer [ 18 ]
42
      mittleres Element bei 0
43
      Knoten erzeugen f³r 18
44
    rechten Teilbaum erzeugen
45
      Erzeuge Baum fuer [ ]
46
      mittleres Element bei 0
47
      Knoten erzeugen f³r 15
48
  rechten Teilbaum erzeugen
49
    Erzeuge Baum fuer [ 24 5 ]
50
    mittleres Element bei 1
51
    Knoten erzeugen f³r 5
52
    linken Teilbaum erzeugen
53
      Erzeuge Baum fuer [ 24 ]
54
      mittleres Element bei 0
55
      Knoten erzeugen f³r 24
56
    rechten Teilbaum erzeugen
57
      Erzeuge Baum fuer [ ]
58
      mittleres Element bei 0
59
      Knoten erzeugen f³r 1638280
60
Drücken Sie eine beliebige Taste . . .

ist der Code fehlerhaft

von Karl H. (kbuchegg)


Lesenswert?

dulli schrieb:

> Denn wie man einen Teilbaum ausgibt war mir klar (trotzdem danke),
> aber mir fällt nichts ein, wie ich den Baum als ganzes Ausgabe.

Das widerspricht sich aber.
WEnn du einen Teilbaum ausgeben kannst, dann kannst du auch einen Baum 
als ganzes ausgeben. Nix von dem 5 Zeiler da oben verstanden?

Sorry. Aber in meinen Augen bist du ein Schaumschläger.

: Bearbeitet durch User
von Karl H. (kbuchegg)


Angehängte Dateien:

Lesenswert?

Viel Spass beim analysieren

1
           4
2
       12
3
           9
4
   9
5
           10
6
       7
7
           13
8
13
9
           18
10
       6
11
           15
12
   15
13
           24
14
       5
15
           1638280

Der Knoten 9 ist 2 mal im Baum und der Knoten 163820 (offensichtlich ein 
Array Zugriff out of bounds) gehört da nicht hin. 13 ist ebenfalls 
doppelt im Baum. Genauso wie 15.

(Die Wurzel des Baumes ist am linken Rand. Der Knoten '13'. Der linke 
Teilbaum sitzt jeweils darüber, der rechte darunter. Der Baum ist also 
nicht ganz einfach nur um 90° nach links gedreht. Das soll aber dem 
Analysespass keinen Abbruch tun und wenn du dir leichter tust, na dann 
verändere halt die Ausgabe)

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

So wäre der Baum richtig
1
            4
2
        12
3
    9
4
            10
5
        7
6
13
7
            18
8
        6
9
    15
10
            24
11
        5

nur stimmt das recht offensichtlich nicht mit dem überein, was die 
unmodifizierte Funktion liefert
1
            4
2
        12
3
            9
4
    9
5
            10
6
        7
7
            13
8
13
9
            18
10
        6
11
            15
12
    15
13
            24
14
        5
15
            1638280

und wenn man den Aktions-Trace von weiter oben studiert, ist auch sofort 
klar, was da schief läuft.
Bei komplexen Datenstrukturen kann ein Mittracen manchmal sehr erhellend 
sein. Und vor allen Dingen geht es viel schneller und reproduzierbarer 
als mit jedem Debugger. Also unterschätz mir bloss nicht, was man mit 
ein paar printf alles anstellen kann.

: Bearbeitet durch User
von dulli (Gast)


Lesenswert?

Erzeuge Baum fuer [ ]
      mittleres Element bei 0
      Knoten erzeugen f³r 9

Das wird das Problem sein, aber wie kommt es dazu, denn ich habe doch 
eigentlich die if-Verzweigung if (anzahl > 1){

von Karl H. (kbuchegg)


Lesenswert?

Dann solltest du mal schnell überlegen.

Oder, wenn du nicht drauf kommst, noch ein paar printf mit einbauen.

Wie sieht denn die Situation beim Aufrufer aus, die letztendlich dazu 
führt, dass create_tree aufgefordert wird, einen Baum für eine leere 
'Liste' zu bauen? Steig halt mal im Aktion-Tree eine Ebene raus und sieh 
dir an, wie dort die Situation aussieht. Und: keine Annahmen treffen! Es 
zählt nur das was Sache ist und nicht das was du dir denkst, dass 
passieren sollte.

: Bearbeitet durch User
von PittyJ (Gast)


Lesenswert?

Diese Hausaufgaben sind pillepalle zu dem, was einem später begegnet.
Wenn es schon Probleme gibt, einfach mal einen printf einzubauen und zu 
schauen, was da passiert, dann ist es Zeit sich grundlegende Gedanken zu 
machen.
Z.B. ob es nicht Gebiete gibt, wo man Stärken hat, und diese Gebiete 
dann bei seiner Berufswahl berücksichtigen.

Klingt jetzt hart, aber wenn ich sehe, wie man schon bei den einfachsten 
Sachen nicht weiter kommt....

von Pandur S. (jetztnicht)


Lesenswert?

Fuer solche Algorithmen gibt es Buecher, mit Erklaerungen, mit 
Kommentaren. Wie zB den "Nicklaus Wirth, Algorithmen und 
Datenstrukturen". Und dann sieht man, der oben zusammengestueckelte Code 
ist nicht vollstaendig. Ist Quatsch.

Irgendwie sollte klar sein, dass ein Buch nicht einfach gratis ist. Und 
es sollte auch klar sein, dass Code der im Web auffindbar ist, (mit 
Glueck) das macht was er sollte und die uebrige, wuenschbare 
Funktionalitaet weglaesst. Und sowieso nicht kommentiert ist, da davon 
ausgegangen werden kann, dass der Benutzer das konzept kennt.

Was im obigen Code fehlt : insert(), delete(), such(), .. , Nutzdaten

also nochmals Neu von/auf Feld Eins.

Aeh.. ich musste den balancierten Baum auch zwei Mal abschreiben, bis 
ich durchgestiegen bin. Und koennte ihn nicht ausm Kopf, waehrend ein 
normaler Baum ausm Kopf geht.

von Karl H. (kbuchegg)


Lesenswert?

PittyJ schrieb:
> Diese Hausaufgaben sind pillepalle zu dem, was einem später begegnet.

Mich würde ja interessieren, was da dahinter steckt. Denn das passt 
alles hinten und vorne nicht zusammen.
Er will/soll/muss Aufgaben lösen, die in einem 300 Seiten Lehrbuch 
irgendwo bei Seite 250 angesiedelt sind, scheitert aber an 
Detailproblemen, die bereits bei Seite 40 hätten beherrscht werden 
sollen.

Wenn ich sowas schon sehe
1
int main()
2
{
3
  int mynumbers[] = { 4, 12, 9, 10, 7, 13, 18, 6, 15, 24, 5 };
4
  int *feld = NULL;
5
  int anzahl = 11;
6
7
  feld = mynumbers;
8
  create_tree(feld,anzahl);
wird mir schlecht. Alleine in diesen 5 Zeilen ist so dermassen viel 
Unwissen und nicht Verstandenes erkennbar, dass mir Angst und Bang wird. 
Für einen Neuling wäre das ok. Neulinge schreiben gerne mal unnötig 
komplexen und unflexiblen Code, der dann auch noch um einiges länger 
ist, als die simple flexible Lösung und bauen dumme Fehler ein die sie 
nicht bemerken, obwohl er förmlich "bitte hier!" schreit. Aber ein 
Neuling versucht sich nicht an dynamischen Datenstrukturen.

Hmm. Wenn ich mirs recht überlege: Nein, ich wills gar nicht wissen.

: Bearbeitet durch User
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.