Objektorientierte Programmierung OOP

KE6 Algorithmus und Datenstrukturen

KE6 Algorithmus und Datenstrukturen


S. H.
Diese Lernkarten behandeln fortgeschrittene Konzepte der objektorientierten Programmierung (OOP) auf Universitätsniveau, mit Fokus auf Datenstrukturen wie Bäume und Listen. Sie erklären Methoden zur Suche und Manipulation von Knoten, Elementen und Feldern, sowie die Implementierung von Suchstrategien wie Breiten- und Tiefensuche. Die Karteikarten sind besonders nützlich für Studierende der Informatik, die ihre Kenntnisse in der Programmierung vertiefen und praktische Anwendungen von OOP-Konzepten verstehen möchten.
Cartes-fiches
106
Utilisateurs
8
Langue
Allemand
Catégorie
Informatique
Niveau
Université
Créé / Mis à jour
15.01.2013 / 18.05.2022

Cartes-fiches

Entwickeln Sie die Anweisungen, um den Baum aus  der Abbildung darzustellen.

 

    BinaryTreeNode a         = new BinaryTreeNode(6, null, new BinaryTreeNode(5));    BinaryTreeNode b         = new BinaryTreeNode(2, new BinaryTreeNode(9), a);    BinaryTreeNode c         = new BinaryTreeNode(1, new BinaryTreeNode(4),                                 new BinaryTreeNode(8));    BinaryTreeNode root = new BinaryTreeNode(7, b, c);    BinaryTree bt = new BinaryTree(root);

Welche Suchmethoden sind bei Binärbäumen anwendbar.

 

Rekursive Methoden sind gut geeignet, einen Baum zu durchsuchen und zu verändern, wenn man eine der ersten drei Durchquerungsstrategien pre-, post-, oder in-order benutzt. Diese Verfahren spiegeln die rekursive Struktur eines Baumes, der aus linken und rechten Unterbäumen besteht, wider.

Im Gegensatz dazu ist die level-order-Durchquerung für ein rekursives Verarbeitungsschema weniger gut geeignet, da sie den Verknüpfungen eines Baums nicht folgt, sondern sie quer durchschneidet.

Wir wollen nun eine Methode printPreorder() in der Klasse BinaryTree implementieren, die die Knoten in der Reihenfolge ausgibt, in der sie mit Hilfe der pre-order-Strategie besucht werden. Auch hier benutzen wir wieder eine private Hilfsmethode.

 

public class BinaryTree {    private BinaryTreeNode root;        // ...        public void printPreorder() {        // start with root        printPreorder(root);    }        private void printPreorder(BinaryTreeNode tn) {        // base case: empty subtree        if (tn == null) {            return;        }        // visit current node        System.out.print(tn.getEntry() + " ");        // visit left child        printPreorder(tn.getLeftChild());        // visit right child        printPreorder(tn.getRightChild());    }}

Entwickeln Sie analog zur Methode printPreorder() die Methoden printInorder() und printPostorder() für die KlasseBinaryTree.

 

public class BinaryTree {    Private BinaryTreeNode root;        / / ...        public void printInorder () {        / / Mit Root starten        printInorder (root);    }        private void printInorder (BinaryTreeNode tn) {        / / Base case: empty Teilbaum        if (tn == null) {            zurück;        }        / / Besuch linke Kind        printInorder (tn.getLeftChild ());        / / Besuch aktuellen Knoten        System.out.print (tn.getEntry () + "");        / / Besuch rechte Kind        printInorder (tn.getRightChild ());    }        public void printPostorder () {        / / Mit Root starten        printPostorder (root);    }        private void printPostorder (BinaryTreeNode tn) {        / / Base case: empty Teilbaum        if (tn == null) {            zurück;        }        / / Besuch linke Kind        printPostorder (tn.getLeftChild ());        / / Besuch rechte Kind        printPostorder (tn.getRightChild ());        / / Besuch aktuellen Knoten        System.out.print (tn.getEntry () + "");    }    }

Entwickeln Sie eine Methode public contains(int x), die überprüft, ob der Baum den Wert x enthält. Geben Sie an, welche Suchstrategie Ihre Methode verwendet.

 

public class BinaryTree {    Private BinaryTreeNode root;        / / ...        public boolean contains (int x) {        Rückkehr enthält (Wurzel, x);    }        private boolean contains (BinaryTreeNode tn, int x) {        / / Base case 1: leere Teilbaum        if (tn == null) {            return false;        }        / / Search in preorder        / / Vergleichen x mit aktuellen Knoten        if (tn.getEntry () == x) {    / / Base case 2: x gefunden            return true;        }        / / Search in der linken und in der rechten Teilbaum        Rückkehr enthält (tn.getLeftChild (), x)                 | | Enthält (tn.getRightChild (), x);    }}

Entwickeln Sie eine Methode public contains(int x), die überprüft, ob der Baum den Wert x enthält. Geben Sie an, welche Suchstrategie Ihre Methode verwendet.

 

public class BinaryTree {    Private BinaryTreeNode root;        / / ...        public boolean contains (int x) {        Rückkehr enthält (Wurzel, x);    }        private boolean contains (BinaryTreeNode tn, int x) {        / / Base case 1: leere Teilbaum        if (tn == null) {            return false;        }        / / Search in preorder        / / Vergleichen x mit aktuellen Knoten        if (tn.getEntry () == x) {    / / Base case 2: x gefunden            return true;        }        / / Search in der linken und in der rechten Teilbaum        Rückkehr enthält (tn.getLeftChild (), x)                 | | Enthält (tn.getRightChild (), x);    }}

Nach welchem Schema ist ein Suchbaum aufgebaut?

Der Wert, der im linken Kind gespeichert ist, ist immer kleiner als der Wert des Elternknotens, und der Wert des rechten Kindes ist immer größer als der Wert des Elternknotens. Ein Baum, dessen Elemente diese Eigenschaft aufweisen, wird auch Suchbaum genannt. In einem solchen Suchbaum kann jedes Element maximal einmal vorkommen.

Zeichnen Sie den Suchbaum, der entsteht, wenn Sie der Reihe nach die Werte 7, 12, 20, 3, 5, 1, 6, 9 einfügen.

Suchbaum

Beschreiben Sie das Verfahren der Tiefensuche.

Bei der Tiefensuche hingegen wird erst ein Nachbar gewählt und anschließend von diesem Nachbarn wieder ein Nachbar ausgewählt. Es wird solange diese Strategie angewendet, bis ein Knoten keine Nachbarn hat oder all seine Nachbarn schon besucht wurden. Ist dies der Fall, geht man einen Schritt zurück und schaut, ob dieser Knoten noch andere unbesuchte Knoten aufweist. Diese Strategie des Zurückgehens wird auch als Backtracking bezeichnet. Bei der Tiefensuche geht man ähnlich wie in einem Labyrinth so lange weiter, bis man in eine Sackgasse gelangt, arbeitet sich dann wieder ein Stück zurück und versucht eine andere Abzweigung. Man sucht also zunächst in der Tiefe des Graphen. Die Abbildung veranschaulicht dieses Vorgehen. Die Nummern zeigen an, in welcher Reihenfolge die Knoten besucht werden.

 

Um eine Breitensuche systematisch durchführen zu können, benötigen wir eine Warteschlange.

1.

Füge den Startknoten in die Warteschlange ein.

2.

Entnehme solange den ersten, also ältesten Knoten aus der Warteschlange, bis du einen unbesuchten erhältst.

3.

Vergleiche den Wert des Knotens mit dem gesuchten Knoten.

4.

Sind sie identisch, so ist der gesuchte Knoten gefunden und die Suche kann beendet werden.

5.

Sind sie nicht identisch, so wird der Knoten als besucht gekennzeichnet.

6.

Füge alle noch nicht besuchten Nachbarn des Knotens in die Warteschlange ein.

7.

Ist die Warteschlange leer, so konnte der Knoten nicht gefunden werden und die Suche kann beendet werden.

8.

Fahre mit Schritt 2 fort.

 

Erläutern Sie der Verfahren der Breitensuche.

Die beiden Verfahren unterscheiden sich darin, in welcher Reihenfolge sie die Knoten durchsuchen. Beide Verfahren müssen speichern, welche Knoten schon besucht wurden, um nicht im Kreis zu laufen. Die BreitensucheBreitensucheBreitensuche betrachtet zunächst alle direkten Nachbarn des aktuellen Knotens. Wenn das gesuchte Element nicht dabei ist, so werden als nächstes die Nachbarn der Nachbarn betrachtet und so weiter. In welcher Reihenfolge die direkten Nachbarn untersucht werden, spielt keine Rolle. Man tastet sich bei der Suche also in der vollen Breite immer weiter vor. Abb.  36.5-1 veranschaulicht dieses Vorgehen. Die Nummern zeigen an, in welcher Reihenfolge die Knoten besucht werden.

 

Für die Tiefensuche können wir das folgende systematische Verfahren verwenden:

1.

Überprüfe ob der aktuelle Knoten der gesuchte Knoten ist.

2.

Sind die Knoten identisch, so ist der gesuchte Knoten gefunden und die Suche kann beendet werden.

3.

Sind sie nicht identisch, so wird der Knoten als besucht gekennzeichnet.

4.

Hat der Knoten keine unbesuchten Nachbarn, so muss die Suche hier erfolgreich abgebrochen werden und zum Vorgänger zurückgekehrt werden.

5.

Wähle einen unbesuchten Nachbarn des aktuellen Knotens aus und suche von dort rekursiv mit diesem Verfahren weiter.

6.

Wird ohne Erfolg vom besuchten Nachbarn hierher zurückgekehrt, so fahre mit Schritt 4 fort.

 

Étudier