|
|
|
@@ -29,236 +29,246 @@
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
public class BinarySearchTree<ContentType extends ComparableContent<ContentType>> {
|
|
|
|
public class BinarySearchTree<ContentType extends ComparableContent<ContentType>> {
|
|
|
|
|
|
|
|
|
|
|
|
/* --------- Anfang der privaten inneren Klasse -------------- */
|
|
|
|
/* --------- Anfang der privaten inneren Klasse -------------- */
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* Durch diese innere Klasse kann man dafuer sorgen, dass ein leerer Baum
|
|
|
|
* Durch diese innere Klasse kann man dafuer sorgen, dass ein leerer Baum
|
|
|
|
* null ist, ein nicht-leerer Baum jedoch immer eine nicht-null-Wurzel sowie
|
|
|
|
* null ist, ein nicht-leerer Baum jedoch immer eine nicht-null-Wurzel sowie
|
|
|
|
* nicht-null-Teilbaeume hat.
|
|
|
|
* nicht-null-Teilbaeume hat.
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
private class BSTNode<CT extends ComparableContent<CT>> {
|
|
|
|
private class BSTNode<CT extends ComparableContent<CT>> {
|
|
|
|
|
|
|
|
|
|
|
|
private CT content;
|
|
|
|
private CT content;
|
|
|
|
private BinarySearchTree<CT> left, right;
|
|
|
|
private BinarySearchTree<CT> left, right;
|
|
|
|
|
|
|
|
|
|
|
|
public BSTNode(CT pContent) {
|
|
|
|
public BSTNode(CT pContent) {
|
|
|
|
// Der Knoten hat einen linken und rechten Teilbaum, die
|
|
|
|
// Der Knoten hat einen linken und rechten Teilbaum, die
|
|
|
|
// beide von null verschieden sind. Also hat ein Blatt immer zwei
|
|
|
|
// beide von null verschieden sind. Also hat ein Blatt immer zwei
|
|
|
|
// leere Teilbaeume unter sich.
|
|
|
|
// leere Teilbaeume unter sich.
|
|
|
|
this.content = pContent;
|
|
|
|
this.content = pContent;
|
|
|
|
left = new BinarySearchTree<CT>();
|
|
|
|
left = new BinarySearchTree<CT>();
|
|
|
|
right = new BinarySearchTree<CT>();
|
|
|
|
right = new BinarySearchTree<CT>();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ----------- Ende der privaten inneren Klasse -------------- */
|
|
|
|
/* ----------- Ende der privaten inneren Klasse -------------- */
|
|
|
|
|
|
|
|
|
|
|
|
private BSTNode<ContentType> node;
|
|
|
|
private BSTNode<ContentType> node;
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* Der Konstruktor erzeugt einen leeren Suchbaum.
|
|
|
|
* Der Konstruktor erzeugt einen leeren Suchbaum.
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
public BinarySearchTree() {
|
|
|
|
public BinarySearchTree() {
|
|
|
|
this.node = null;
|
|
|
|
this.node = null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* Diese Anfrage liefert den Wahrheitswert true, wenn der Suchbaum leer ist,
|
|
|
|
* Diese Anfrage liefert den Wahrheitswert true, wenn der Suchbaum leer ist,
|
|
|
|
* sonst liefert sie den Wert false.
|
|
|
|
* sonst liefert sie den Wert false.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* @return true, wenn der binaere Suchbaum leer ist, sonst false
|
|
|
|
* @return true, wenn der binaere Suchbaum leer ist, sonst false
|
|
|
|
*
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
public boolean isEmpty() {
|
|
|
|
public boolean isEmpty() {
|
|
|
|
return this.node == null;
|
|
|
|
return this.node == null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* Falls der Parameter null ist, geschieht nichts.<br />
|
|
|
|
* Falls der Parameter null ist, geschieht nichts.<br />
|
|
|
|
* Falls ein bezueglich der verwendeten Vergleichsmethode isEqual mit
|
|
|
|
* Falls ein bezueglich der verwendeten Vergleichsmethode isEqual mit
|
|
|
|
* pContent uebereinstimmendes Objekt im geordneten binaeren Suchbau
|
|
|
|
* pContent uebereinstimmendes Objekt im geordneten binaeren Suchbau
|
|
|
|
* enthalten ist, passiert nichts. <br />
|
|
|
|
* enthalten ist, passiert nichts. <br />
|
|
|
|
* Achtung: hier wird davon ausgegangen, dass isEqual genau dann true
|
|
|
|
* Achtung: hier wird davon ausgegangen, dass isEqual genau dann true
|
|
|
|
* liefert, wenn isLess und isGreater false liefern. <br />
|
|
|
|
* liefert, wenn isLess und isGreater false liefern. <br />
|
|
|
|
* Andernfalls (isLess oder isGreater) wird das Objekt pContent entsprechend
|
|
|
|
* Andernfalls (isLess oder isGreater) wird das Objekt pContent entsprechend
|
|
|
|
* der vorgegebenen Ordnungsrelation in den BinarySearchTree eingeordnet.
|
|
|
|
* der vorgegebenen Ordnungsrelation in den BinarySearchTree eingeordnet.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* @param pContent
|
|
|
|
* @param pContent
|
|
|
|
* einzufuegendes Objekt vom Typ ContentType
|
|
|
|
* einzufuegendes Objekt vom Typ ContentType
|
|
|
|
*
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
public void insert(ContentType pContent) {
|
|
|
|
public void insert(ContentType pContent) {
|
|
|
|
if (pContent != null) {
|
|
|
|
if (pContent != null) {
|
|
|
|
if (isEmpty()) {
|
|
|
|
if (isEmpty()) {
|
|
|
|
this.node = new BSTNode<ContentType>(pContent);
|
|
|
|
this.node = new BSTNode<ContentType>(pContent);
|
|
|
|
} else if (pContent.isLess(this.node.content)) {
|
|
|
|
} else if (pContent.isLess(this.node.content)) {
|
|
|
|
this.node.left.insert(pContent);
|
|
|
|
this.node.left.insert(pContent);
|
|
|
|
} else if(pContent.isGreater(this.node.content)) {
|
|
|
|
} else if(pContent.isGreater(this.node.content)) {
|
|
|
|
this.node.right.insert(pContent);
|
|
|
|
this.node.right.insert(pContent);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* Diese Anfrage liefert den linken Teilbaum des binaeren Suchbaumes. <br />
|
|
|
|
* Diese Anfrage liefert den linken Teilbaum des binaeren Suchbaumes. <br />
|
|
|
|
* Wenn er leer ist, wird null zurueckgegeben.
|
|
|
|
* Wenn er leer ist, wird null zurueckgegeben.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* @return den linken Teilbaum (Objekt vom Typ BinarySearchTree<ContentType>)
|
|
|
|
* @return den linken Teilbaum (Objekt vom Typ BinarySearchTree<ContentType>)
|
|
|
|
* bzw. null, wenn der Suchbaum leer ist
|
|
|
|
* bzw. null, wenn der Suchbaum leer ist
|
|
|
|
*
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
public BinarySearchTree<ContentType> getLeftTree() {
|
|
|
|
public BinarySearchTree<ContentType> getLeftTree() {
|
|
|
|
if (this.isEmpty()) {
|
|
|
|
if (this.isEmpty()) {
|
|
|
|
return null;
|
|
|
|
return null;
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
return this.node.left;
|
|
|
|
return this.node.left;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* Diese Anfrage liefert das Inhaltsobjekt des Suchbaumes. Wenn der Suchbaum
|
|
|
|
* Diese Anfrage liefert das Inhaltsobjekt des Suchbaumes. Wenn der Suchbaum
|
|
|
|
* leer ist, wird null zurueckgegeben.
|
|
|
|
* leer ist, wird null zurueckgegeben.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* @return das Inhaltsobjekt vom Typ ContentType bzw. null, wenn der aktuelle
|
|
|
|
* @return das Inhaltsobjekt vom Typ ContentType bzw. null, wenn der aktuelle
|
|
|
|
* Suchbaum leer ist
|
|
|
|
* Suchbaum leer ist
|
|
|
|
*
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
public ContentType getContent() {
|
|
|
|
public ContentType getContent() {
|
|
|
|
if (this.isEmpty()) {
|
|
|
|
if (this.isEmpty()) {
|
|
|
|
return null;
|
|
|
|
return null;
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
return this.node.content;
|
|
|
|
return this.node.content;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* Diese Anfrage liefert den rechten Teilbaum des binaeren Suchbaumes. <br />
|
|
|
|
* Diese Anfrage liefert den rechten Teilbaum des binaeren Suchbaumes. <br />
|
|
|
|
* Wenn er leer ist, wird null zurueckgegeben.
|
|
|
|
* Wenn er leer ist, wird null zurueckgegeben.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* @return den rechten Teilbaum (Objekt vom Typ BinarySearchTree<ContentType>)
|
|
|
|
* @return den rechten Teilbaum (Objekt vom Typ BinarySearchTree<ContentType>)
|
|
|
|
* bzw. null, wenn der aktuelle Suchbaum leer ist
|
|
|
|
* bzw. null, wenn der aktuelle Suchbaum leer ist
|
|
|
|
*
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
public BinarySearchTree<ContentType> getRightTree() {
|
|
|
|
public BinarySearchTree<ContentType> getRightTree() {
|
|
|
|
if (this.isEmpty()) {
|
|
|
|
if (this.isEmpty()) {
|
|
|
|
return null;
|
|
|
|
return null;
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
return this.node.right;
|
|
|
|
return this.node.right;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* Falls ein bezueglich der verwendeten Vergleichsmethode mit
|
|
|
|
* Falls ein bezueglich der verwendeten Vergleichsmethode mit
|
|
|
|
* pContent uebereinstimmendes Objekt im binaeren Suchbaum enthalten
|
|
|
|
* pContent uebereinstimmendes Objekt im binaeren Suchbaum enthalten
|
|
|
|
* ist, wird dieses entfernt. Falls der Parameter null ist, aendert sich
|
|
|
|
* ist, wird dieses entfernt. Falls der Parameter null ist, aendert sich
|
|
|
|
* nichts.
|
|
|
|
* nichts.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* @param pContent
|
|
|
|
* @param pContent
|
|
|
|
* zu entfernendes Objekt vom Typ ContentType
|
|
|
|
* zu entfernendes Objekt vom Typ ContentType
|
|
|
|
*
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
public void remove(ContentType pContent) {
|
|
|
|
public void remove(ContentType pContent) {
|
|
|
|
if (isEmpty() || pContent == null ) {
|
|
|
|
if (isEmpty() || pContent == null ) {
|
|
|
|
// Abbrechen, da kein Element zum entfernen vorhanden ist.
|
|
|
|
// Abbrechen, da kein Element zum entfernen vorhanden ist.
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (pContent.isLess(node.content)) {
|
|
|
|
if (pContent.isLess(node.content)) {
|
|
|
|
// Element ist im linken Teilbaum zu loeschen.
|
|
|
|
// Element ist im linken Teilbaum zu loeschen.
|
|
|
|
node.left.remove(pContent);
|
|
|
|
node.left.remove(pContent);
|
|
|
|
} else if (pContent.isGreater(node.content)) {
|
|
|
|
} else if (pContent.isGreater(node.content)) {
|
|
|
|
// Element ist im rechten Teilbaum zu loeschen.
|
|
|
|
// Element ist im rechten Teilbaum zu loeschen.
|
|
|
|
node.right.remove(pContent);
|
|
|
|
node.right.remove(pContent);
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
// Element ist gefunden.
|
|
|
|
// Element ist gefunden.
|
|
|
|
if (node.left.isEmpty()) {
|
|
|
|
if (node.left.isEmpty()) {
|
|
|
|
if (node.right.isEmpty()) {
|
|
|
|
if (node.right.isEmpty()) {
|
|
|
|
// Es gibt keinen Nachfolger.
|
|
|
|
// Es gibt keinen Nachfolger.
|
|
|
|
node = null;
|
|
|
|
node = null;
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
// Es gibt nur rechts einen Nachfolger.
|
|
|
|
// Es gibt nur rechts einen Nachfolger.
|
|
|
|
node = getNodeOfRightSuccessor();
|
|
|
|
node = getNodeOfRightSuccessor();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (node.right.isEmpty()) {
|
|
|
|
} else if (node.right.isEmpty()) {
|
|
|
|
// Es gibt nur links einen Nachfolger.
|
|
|
|
// Es gibt nur links einen Nachfolger.
|
|
|
|
node = getNodeOfLeftSuccessor();
|
|
|
|
node = getNodeOfLeftSuccessor();
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
// Es gibt links und rechts einen Nachfolger.
|
|
|
|
// Es gibt links und rechts einen Nachfolger.
|
|
|
|
if (getNodeOfRightSuccessor().left.isEmpty()) {
|
|
|
|
if (getNodeOfRightSuccessor().left.isEmpty()) {
|
|
|
|
// Der rechte Nachfolger hat keinen linken Nachfolger.
|
|
|
|
// Der rechte Nachfolger hat keinen linken Nachfolger.
|
|
|
|
node.content = getNodeOfRightSuccessor().content;
|
|
|
|
node.content = getNodeOfRightSuccessor().content;
|
|
|
|
node.right = getNodeOfRightSuccessor().right;
|
|
|
|
node.right = getNodeOfRightSuccessor().right;
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
BinarySearchTree<ContentType> previous = node.right
|
|
|
|
BinarySearchTree<ContentType> previous = node.right
|
|
|
|
.ancestorOfSmallRight();
|
|
|
|
.ancestorOfSmallRight();
|
|
|
|
BinarySearchTree<ContentType> smallest = previous.node.left;
|
|
|
|
BinarySearchTree<ContentType> smallest = previous.node.left;
|
|
|
|
this.node.content = smallest.node.content;
|
|
|
|
this.node.content = smallest.node.content;
|
|
|
|
previous.remove(smallest.node.content);
|
|
|
|
previous.remove(smallest.node.content);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* Falls ein bezueglich der verwendeten Vergleichsmethode isEqual mit
|
|
|
|
* Falls ein bezueglich der verwendeten Vergleichsmethode isEqual mit
|
|
|
|
* pContent uebereinstimmendes Objekt im binaeren Suchbaum enthalten ist,
|
|
|
|
* pContent uebereinstimmendes Objekt im binaeren Suchbaum enthalten ist,
|
|
|
|
* liefert die Anfrage dieses, ansonsten wird null zurueckgegeben. <br />
|
|
|
|
* liefert die Anfrage dieses, ansonsten wird null zurueckgegeben. <br />
|
|
|
|
* Falls der Parameter null ist, wird null zurueckgegeben.
|
|
|
|
* Falls der Parameter null ist, wird null zurueckgegeben.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* @param pContent
|
|
|
|
* @param pContent
|
|
|
|
* zu suchendes Objekt vom Typ ContentType
|
|
|
|
* zu suchendes Objekt vom Typ ContentType
|
|
|
|
* @return das gefundene Objekt vom Typ ContentType, bei erfolgloser Suche null
|
|
|
|
* @return das gefundene Objekt vom Typ ContentType, bei erfolgloser Suche null
|
|
|
|
*
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
public ContentType search(ContentType pContent) {
|
|
|
|
public ContentType search(ContentType pContent) {
|
|
|
|
if (this.isEmpty() || pContent == null) {
|
|
|
|
if (this.isEmpty() || pContent == null) {
|
|
|
|
// Abbrechen, da es kein Element zu suchen gibt.
|
|
|
|
// Abbrechen, da es kein Element zu suchen gibt.
|
|
|
|
return null;
|
|
|
|
return null;
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
ContentType content = this.getContent();
|
|
|
|
ContentType content = this.getContent();
|
|
|
|
if (pContent.isLess(content)) {
|
|
|
|
if (pContent.isLess(content)) {
|
|
|
|
// Element wird im linken Teilbaum gesucht.
|
|
|
|
// Element wird im linken Teilbaum gesucht.
|
|
|
|
return this.getLeftTree().search(pContent);
|
|
|
|
return this.getLeftTree().search(pContent);
|
|
|
|
} else if (pContent.isGreater(content)) {
|
|
|
|
} else if (pContent.isGreater(content)) {
|
|
|
|
// Element wird im rechten Teilbaum gesucht.
|
|
|
|
// Element wird im rechten Teilbaum gesucht.
|
|
|
|
return this.getRightTree().search(pContent);
|
|
|
|
return this.getRightTree().search(pContent);
|
|
|
|
} else if (pContent.isEqual(content)) {
|
|
|
|
} else if (pContent.isEqual(content)) {
|
|
|
|
// Element wurde gefunden.
|
|
|
|
// Element wurde gefunden.
|
|
|
|
return content;
|
|
|
|
return content;
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
// Dieser Fall sollte nicht auftreten.
|
|
|
|
// Dieser Fall sollte nicht auftreten.
|
|
|
|
return null;
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ----------- Weitere private Methoden -------------- */
|
|
|
|
/* ----------- Weitere private Methoden -------------- */
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* Die Methode liefert denjenigen Baum, dessen linker Nachfolger keinen linken
|
|
|
|
* Die Methode liefert denjenigen Baum, dessen linker Nachfolger keinen linken
|
|
|
|
* Nachfolger mehr hat. Es ist also spaeter moeglich, in einem Baum im
|
|
|
|
* Nachfolger mehr hat. Es ist also spaeter moeglich, in einem Baum im
|
|
|
|
* rechten Nachfolger den Vorgaenger des linkesten Nachfolgers zu finden.
|
|
|
|
* rechten Nachfolger den Vorgaenger des linkesten Nachfolgers zu finden.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
private BinarySearchTree<ContentType> ancestorOfSmallRight() {
|
|
|
|
private BinarySearchTree<ContentType> ancestorOfSmallRight() {
|
|
|
|
if (getNodeOfLeftSuccessor().left.isEmpty()) {
|
|
|
|
if (getNodeOfLeftSuccessor().left.isEmpty()) {
|
|
|
|
return this;
|
|
|
|
return this;
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
return node.left.ancestorOfSmallRight();
|
|
|
|
return node.left.ancestorOfSmallRight();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private BSTNode<ContentType> getNodeOfLeftSuccessor() {
|
|
|
|
private BSTNode<ContentType> getNodeOfLeftSuccessor() {
|
|
|
|
return node.left.node;
|
|
|
|
return node.left.node;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private BSTNode<ContentType> getNodeOfRightSuccessor() {
|
|
|
|
private BSTNode<ContentType> getNodeOfRightSuccessor() {
|
|
|
|
return node.right.node;
|
|
|
|
return node.right.node;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public void printInOrder() {
|
|
|
|
public List<ContentType> getInOrder() {
|
|
|
|
//TODO
|
|
|
|
List<ContentType> inOrder = new List<>();
|
|
|
|
}
|
|
|
|
getPartTree(this, inOrder);
|
|
|
|
|
|
|
|
return inOrder;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private void getPartTree(BinarySearchTree<ContentType> tree, List<ContentType> inOrder) {
|
|
|
|
|
|
|
|
if (tree != null && tree.getContent() != null) {
|
|
|
|
|
|
|
|
getPartTree(tree.getLeftTree(), inOrder);
|
|
|
|
|
|
|
|
inOrder.append(tree.getContent());
|
|
|
|
|
|
|
|
getPartTree(tree.getRightTree(), inOrder);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|