Binärbäume

Baumstrukturen werden aus Knoten aufgebaut, die einen Zeiger auf einen linken und rechten Teilbaum enthalten:

Binärbäume

Ein Baumknoten kann durch den Datentyp CKnoten dargestellt werden:

struct CKnoten {
  int data;       // die Nutzdaten sind in diesem Beispiel nur Zahlen
  CKnoten* left;
  CKnoten* right;
};

Der Zeiger auf den obersten Knoten des Baums wird oft als root bezeichnet:

CKnoten *root=0;

Musterbeispiel

//---------------------------------------------------------------------------
 
#include <vcl.h>
#pragma hdrstop
 
#include "Baum1Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
 
struct CKnoten{
   int data;   // Nutzdaten
   CKnoten *left;
   CKnoten *right;
};
 
CKnoten *root=0;
 
 
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
	: TForm(Owner)
{
}
//---------------------------------------------------------------------------
 
void ausgabevonoben(CKnoten *h,int k)
{AnsiString einr="";
 if (h!=0)
 {ausgabevonoben(h->right,k+1);
  for (int i=0;i<k;i++) einr=einr+"     ";
  Form1->Memo1->Lines->Add(einr+IntToStr(h->data));
  ausgabevonoben(h->left,k+1);
 }
}
 
void __fastcall TForm1::Button2Click(TObject *Sender)
{ausgabevonoben(root,0);
}
//---------------------------------------------------------------------------
 
void einhaengen(CKnoten *&pos, CKnoten *h)
{ // Der neue Knoten wird an der richtigen Stelle in den Baum eingehängt
  if (pos==0) pos=h;
  else
	if (h->data<=pos->data)  einhaengen(pos->left,h);
	else                     einhaengen(pos->right,h);
}
 
void __fastcall TForm1::Button1Click(TObject *Sender)
{ // Ein neuer Knoten wird errichtet und mit Daten gefüllt
  CKnoten *h = new CKnoten;
  h->data=StrToInt(Edit1->Text);
  h->left=0; h->right=0;
  einhaengen(root,h);
 
  Memo1->Clear(); ausgabevonoben(root,0);
  Edit1->Text="";
  Edit1->SetFocus();
}
//---------------------------------------------------------------------------
CKnoten *suche(CKnoten *h, int k)
{bool gefunden = false ;
 while (h!=0 && !gefunden){
	   if(h->data==k) gefunden=true;
	   else if(k<h->data) h=h->left;
			else h=h->right;
			}
 
 
 if(gefunden)ShowMessage("Gefunden!");
 else        ShowMessage("Nicht gefunden!");
 return h;
}
 
 
void __fastcall TForm1::Button3Click(TObject *Sender)
{CKnoten *p;
 int k=StrToInt(Edit1->Text); // Zahl die in Baumgesucht wird
 p = suche(root,k);
 Memo1->Lines->Add(IntToStr(p->data));
}
//---------------------------------------------------------------------------

Suchen rekursiv

CKnoten *suche(CKnoten *h,int k){
 
if(h!=0){
	if(k<h->data)suche(h->left, k);
	if(k>h->data)suche(h->right, k);
	if(k==h->data){ShowMessage("Gefunden!");return h;}
	}
else {ShowMessage("Nicht Gefunden!");return 0;}
}

Einhängen eines neuen Knotens

void einhaengen(CKnoten *&tiefer, CKnoten *neu)
{
	if (tiefer==0)
	{ tiefer=neu;
	}
	else
	{
		if (neu->data<=tiefer->data)
		{
		einhaengen(tiefer->left,neu);
		}
		else
		{
		einhaengen(tiefer->right,neu);
		}
	}
}
 
void __fastcall TForm3::Button1Click(TObject *Sender)
{
CKnoten *neu = new CKnoten;
 if (Edit1->Text!="")
 {  neu->data=StrToInt(Edit1->Text);
	neu->left=0;
	neu->right=0;
	Edit1->Text="";
	einhaengen(root,neu);
 }
 Edit1->Focused();
}

Löschen eines Knotens

Variante 1

void loeschen(CKnoten *&h)
{
if (h!=0) {
  if (StrToInt(Form1->Edit3->Text) <= h->data) loeschen(h->left);
  else if (StrToInt(Form1->Edit3->Text) > h->data) loeschen(h->right);
  if (StrToInt(Form1->Edit3->Text) == h->data) {
	 if (h->left==0 && h->right==0) {   //Blatt
	 delete(h);
	 h=0;
	 }
	 else if (h->left!=0&&h->right==0) {    //Halbblatt  links
	// CKnoten *h1=h;
	// h=h->left;
	 delete(h);   //delete(h1) if not works
	 h=h->left;   //to delete if not works
	 }
	 else if (h->left==0&&h->right!=0) {    //Halbblatt rechts
	// CKnoten *h1=h;
	// h=h->right;
	 delete(h);   //delete(h1) if not works
	 h=h->right;   //to delete if not works
   //	 return;
	 }
	 else if (h->left!=0&&h->right!=0) {   //2 Kinder
	 CKnoten *h1=h;     //Hilfsknoten
	 CKnoten *h2=h->left;
	 h=h->right;              //größerer Teil rückt nach oben
	 delete(h1);
	 h1=h;
	 while (h1->left!=0) h1=h1->left;  //weiterwandern, immer links bis 0
	 h1->left=h2;
	// return;
	 }
  }
  }
 
}
 
void __fastcall TForm1::Button5Click(TObject *Sender)
{
loeschen(root);
}

Variante 2

void Del(CKnoten* h, CKnoten* i, int nr)
{
		if (h!=0)
		{
			Del(h->left, h, nr);
 
			if (h->data == nr)
			{
				if (h->right == 0 && h->left == 0)
				{
					if (i->right == h)	i->right = 0;
					else if (i->left == h)	i->left = 0;
				}
				else if (h->right == 0)
				{
					if (i->right == h)	i->right = h->left;
					else if (i->left == h)	i->left = h->left;
				}
				else if (h->left == 0)
				{
					if (i->left == h)	i->left = h->right;
					else if (i->right == h)	i->right = h->right;
				}
				else
				{
					CKnoten* temp1 = h->left;
					CKnoten* temp2 = h->right;
 
					while (temp1->right != 0)
					{
						temp1 = temp1->right;
					}
 
					temp1->right = temp2;
 
					if (i->left == h)	i->left = h->left;
					else if (i->right == h)	i->right = h->left;
 
                }
			}
 
			Del(h->right, h, nr);
		}
 
}
 
void __fastcall TForm1::btnBlattLoeschenClick(TObject *Sender)
{
	int nr=StrToInt(InputBox("Blatt löschen","Zahl des zu löschenden Blattes?",""));
 
	if (root->data == nr)
	{
		if (root->left != 0)
		{
			CKnoten* h=root->left;
			CKnoten* i=root->right;
 
			while (h->right!=0)
			{
				h = h->right;
			}
 
			h->right = i;
			root = root->left;
		}
		else if (root->right != 0 && root->left == 0)
		{
			root = root->right;
		}
		else if (root->right == 0 && root->left == 0)
		{
        	root = 0;
		}
	}
 
	Del(root, 0, nr);
 
}

Variante 3

 void loeschen(CKnoten *h, CKnoten *h2, int loesch)
{
	if (h!=0) {
		loeschen(h->left, h, loesch); //h2 ist immer 1 über h
		 if (h->data==loesch) {   //wenn gefunden
 
			   if (h==root) {      //Fall: zu löschendes ist root
 
				   if (h->left!=0 && h->right==0) {   //Fall: nur 1 Kind, left
					  root=h->left;
					 delete(h);
				   }
				   else if (h->left==0 && h->right!=0) {   //Fall: nur 1 Kind, right
					  root=h->right;
					 delete(h);
				   }
 
				   else if (h->left==0 && h->right==0) {
						root=0;
						delete(h);
				   }
 
				  else{        //Fall beide Kinder
 
				  root=h->right;
 
				   CKnoten *h3;
					   h3=h->right;
					while (h3->left!=0) {
						h3=h3->left;     //durchgehen bis zum letzten linken ast des rechten Astes
					   }
					h3->left=h->left;
					delete(h);
				   }
			   }
 
				else if (h->left!=0 && h->right==0)//Fall: 1 Kind - links
				  {
					if (h2->left==h) {  //wenn das kind des zu löschenden links ist
						h2->left=h->left;
					}else h2->right=h->left;
 
					delete (h);
				  }
				else if (h->left==0 && h->right!=0) {  //Fall: 1 Kind - rechts
 
				   if (h2->left==h) {  //wenn das kind des zu löschenden links ist
						h2->left=h->right;
					}else h2->right=h->right;
 
					delete (h);
				}
 
			   else if (h->left==0 && h->right==0) {   //Fall: letztes Glied      ACHTUNG-->wenn nur ein einziger eintrag-> abfangen
					if (h2->right==h) {   //der right/left zeiger des oberen muss gelöscht werden
						h2->right=0;
					}else h2->left=0;
 
					delete(h);
			   }
 
			   else    //Fall: 2 Kinder
			   {
					if (h2->left==h) {        //wenn das zu löschende ein linkes kind ist
					   h2->left=h->right;
					}
					else h2->right=h->right; //rechtes kind
 
					  CKnoten *h3;
					   h3=h->right;
					while (h3->left!=0) {
						h3=h3->left;     //durchgehen bis zum letzten linken ast des rechten Astes
					   }
 
					h3->left=h->left;
 
					delete(h);
			   }
		 }
		loeschen(h->right,h, loesch);

Variante 4

void loeschen(CKnoten *&h, CKnoten *prev)
{
 if (h!=0)
	{
	 loeschen(h->left, h);
	 loeschen(h->right, h);
	 if (h->data==StrToInt(Form1->Edit3->Text))
		{
		 CKnoten *h1=h->left;
		 CKnoten *h2=h->right;
 
		 if (h1==0 && h2==0)
			{
			 delete(h);
			 h=0;
			}
 
		 else if (h1!=0 && h2==0)
			{
			 delete(h);
			 h=h1;
			}
 
		 else if (h1==0 && h2!=0)
			{
			 delete(h);
			 h=h2;
			}
 
		 else
			{
			 if (prev!=0)
				{
				 if (prev->left==h)
					{
					 h1=h->right;
					 while(h1->left!=0)
						h1=h1->left;
					 h1->left=h->left;
					 prev->left=h->right;
					}
				 else
					{
					 h1=h->left;
					 while(h1->right!=0)
						h1=h1->right;
					 h1->right=h->right;
					 prev->right=h->left;
					}
				}
			}
		}
	}
}
 
void __fastcall TForm1::Button5Click(TObject *Sender)
{
 if (root->data==Edit3->Text && root->right!=0 && root->left)
	{
	 CKnoten *h=root->left, *h1=root->right;
	 while (h1->left!=0)
		h1=h1->left;
	 h1->left=h;
	 root=root->right;
	}
 loeschen(root, 0);
 Edit3->Clear();
}