diff --git a/README.md b/README.md
index bb7e0a562e3c3fc9bb9213abda6894ac177be360..c4c144fd5b1a296ac305040e0fd0f8279a5ddfa0 100644
--- a/README.md
+++ b/README.md
@@ -3,17 +3,17 @@
 Die ersten beiden Aufgaben dienen zur Vertiefung Ihrer praktischen Erfahrungen in Rust. Sie implementieren einen Stack und eine Baumstruktur.
 
 ## Allgemeine Hinweise
-Für diese und alle folgenden Praktikumsaufgaben gilt, dass Einsendungen, die in der jeweils mitgegebenen Testumgebung nicht laufen, mit null Punkten bewertet werden! Das beinhaltet insbesondere alle Programme, die sich nicht fehlerfrei kompilieren lassen. Da Cargo für die Ausführung verantwortlich ist, sollte das Projekt bei Ihnen am Ende mit `cargo test` ohne Fehler und Warnungen durchlaufen. 
+Für diese und alle folgenden Praktikumsaufgaben gilt, dass Einsendungen, die in der jeweils mitgegebenen Testumgebung nicht laufen, mit null Punkten bewertet werden! Das beinhaltet insbesondere alle Programme, die sich nicht fehlerfrei kompilieren lassen. Da Cargo für die Ausführung verantwortlich ist, sollte das Projekt bei Ihnen am Ende mit `cargo test` ohne Fehler und Warnungen durchlaufen.
 
 
 ## Abgabemodus
-Die Lösung ist in einem eigenen Git-Repository abzugeben. 
-Sie können in ihrer Lösung jedoch beliebige Hilfstypen und Module selbst definieren. 
-Die grundlegende Struktur des hier mitgegebenen Templates sollte jedoch nicht verändert werden. 
-Insbesondere ist es wichtig, dass die öffentliche Schnittstelle der Library, welche über die Signaturen der Methoden und Funktionen und deren absoluten Pfad definiert wird. 
+Die Lösung ist in einem eigenen Git-Repository abzugeben.
+Sie können in ihrer Lösung jedoch beliebige Hilfstypen und Module selbst definieren.
+Die grundlegende Struktur des hier mitgegebenen Templates sollte jedoch nicht verändert werden.
+Insbesondere ist es wichtig, dass die öffentliche Schnittstelle der Library, welche über die Signaturen der Methoden und Funktionen und deren absoluten Pfad definiert wird.
 
 Zur Lösung der Aufgaben steht für Sie dieses Repository mit
-- vorgegebenen Modulen [stack](src/stack.rs) und [syntree](src/syntree.rs)
+- vorgegebenen Modulen [stack](src/stack.rs) und [syntax_tree](src/syntax_tree.rs)
 - der vorgegebenen Schnittstelle der Library in [lib](src/lib.rs)
 - eine Reihe von Testfällen (Unit-Tests) innerhalb der Module
 
@@ -65,29 +65,46 @@ Implementieren Sie eine Datenstruktur, die beliebig verzweigte Bäume speichern
 Die hier von Ihnen zu implementierende Datenstruktur dient der Repräsentation eines abstrakten Syntaxbaumes.
 
 ```rust
-struct SynTree;
-
-impl<'a, T> SynTree<T> {
-    /// Initialisiert einen neuen Syntaxbaum
-    pub fn new(value: T, id: ID) -> Syntree<T> { todo!() }
-
-    /// Fügt dem angegebenen Elternknoten den mitgegebenen Syntaxbaum als letztes Kind hinzu
-    pub fn push_node(&mut self, parent_id: ID, new_node: Syntree<T>) -> Result<(), String> { todo!() }
-
-    /// Fügt dem angegebenen Elternknoten den mitgegebenen Syntaxbaum als erstes Kind hinzu
-    pub fn prepend_node(&mut self, parent_id: ID, new_node: Syntree<T>) -> Result<(), String> { todo!() }
-
-    /// Fügt dem angegebenen Elternknoten den mitgegebenen Syntaxbaum als Kind an der indizierten Stelle hinzu
-    pub fn insert_node(
+struct SyntaxTree;
+
+impl<T> SyntaxTree<T> {
+    /// Create a SyntaxTree with a root node that carries the given value
+    pub fn new(value: T) -> SyntaxTree<T> {
+        todo!()
+    }
+
+    /// Add another SyntaxTree as last child of this tree
+    pub fn push_node(&mut self, new_node: SyntaxTree<T>) {
+        todo!()
+    }
+
+    /// Add another SyntaxTree as first child of this tree
+    pub fn prepend_node(&mut self, new_node: SyntaxTree<T>) {
+        todo!()
+    }
+    
+    /// Insert the given SyntaxTree into the children of this tree at the given index
+    pub fn insert_node(&mut self, index: usize, new_node: SyntaxTree<T>) {
+        todo!()
+    }
+    
+    /// Perform a depth-first search with the given predicate.
+    /// The method returns a reference to the first SyntaxTree instance for which the predicate
+    /// return true. If no instance is found, None is returned.
+    pub fn find_node(&self, predicate: fn(&SyntaxTree<T>) -> bool) -> Option<&SyntaxTree<T>> {
+        todo!()
+    }
+
+    /// Perform a depth-first search with the given predicate.
+    /// The method returns a mutable reference to the first SyntaxTree instance for which the predicate
+    /// return true. If no instance is found, None is returned.
+    pub fn find_node_mut(
         &mut self,
-        parent_id: ID,
-        index: usize,
-        new_node: Syntree<T>,
-    ) -> Result<(), String> { todo!() }
-
-    /// Suche nach dem ersten Knoten mit der angegebenen ID und liefere eine mutable Referenz zurück
-    pub fn seek_node_mut(&'a mut self, id: &ID) -> Option<&'a mut Syntree<T>> { todo!() }
+        predicate: fn(&SyntaxTree<T>) -> bool,
+    ) -> Option<&SyntaxTree<T>> {
+        todo!()
+    }
 }
 ```
-- Die zu implementierende Datenstruktur Syntree soll Baumknoten in beliebig komplexen Konfigurationen speichern können und davon beliebig viele.
-- Vervollständigen Sie die Implementierung in der Datei [syntree.rs](src/syntree.rs).
\ No newline at end of file
+- Die zu implementierende Datenstruktur SyntaxTree soll Baumknoten in beliebig komplexen Konfigurationen speichern können und davon beliebig viele.
+- Vervollständigen Sie die Implementierung in der Datei [syntax_tree](src/syntax_tree.rs).
\ No newline at end of file
diff --git a/src/lib.rs b/src/lib.rs
index ca4ec44d94f8db00fe591fea55ef517985bf2eae..c77fcf98db95014f044f3457696358926e1d6793 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,5 +1,5 @@
 mod stack;
-mod syntree;
+mod syntax_tree;
 
 pub trait Stack {
     fn init() -> Self;
@@ -14,8 +14,8 @@ pub trait Stack {
 }
 
 pub use stack::ListStack;
-pub use syntree::Syntree;
-pub use syntree::ID;
+pub use syntax_tree::SyntaxTree;
+pub use syntax_tree::ID;
 
 #[cfg(test)]
 mod tests {}
diff --git a/src/syntax_tree.rs b/src/syntax_tree.rs
new file mode 100644
index 0000000000000000000000000000000000000000..6d70c912f364f845191a0e13e53c1a110f3a2733
--- /dev/null
+++ b/src/syntax_tree.rs
@@ -0,0 +1,229 @@
+use std::fmt::{Display, Formatter};
+
+pub type ID = usize;
+
+static mut LAST_ID: usize = 0;
+
+#[derive(Clone, Debug, PartialEq)]
+pub struct SyntaxTree<T> {
+    id: ID,
+    value: T,
+    children: Vec<SyntaxTree<T>>,
+}
+
+/// Simple ID provider
+fn next_id() -> ID {
+    unsafe {
+        let id = LAST_ID;
+        LAST_ID += 1;
+        id
+    }
+}
+
+impl<T> SyntaxTree<T> {
+    /// Create a SyntaxTree with a root node that carries the given value
+    pub fn new(value: T) -> SyntaxTree<T> {
+        todo!()
+    }
+
+    /// Add another SyntaxTree as last child of this tree
+    pub fn push_node(&mut self, new_node: SyntaxTree<T>) {
+        todo!()
+    }
+
+    /// Create a new SyntaxTree with a root node that carries the given value. Add the created tree
+    /// as last child of this tree.
+    pub fn push_value(&mut self, value: T) {
+        self.push_node(SyntaxTree::new(value));
+    }
+
+    /// Add another SyntaxTree as first child of this tree
+    pub fn prepend_node(&mut self, new_node: SyntaxTree<T>) {
+        todo!()
+    }
+
+    /// Create a new SyntaxTree with a root node that carries the given value. Add the created tree
+    /// as first child of this tree.
+    pub fn prepend_value(&mut self, value: T) {
+        self.prepend_node(SyntaxTree::new(value));
+    }
+
+    /// Insert the given SyntaxTree into the children of this tree at the given index
+    pub fn insert_node(&mut self, index: usize, new_node: SyntaxTree<T>) {
+        self.children.insert(index, new_node);
+    }
+
+    /// Create a new SyntaxTree with a root node that carries the given value.
+    /// Insert the created SyntaxTree into the children of this tree at the given index
+    pub fn insert_value(&mut self, index: usize, value: T) {
+        self.insert_node(index, SyntaxTree::new(value));
+    }
+
+    /// Perform a depth-first search with the given predicate.
+    /// The method returns a reference to the first SyntaxTree instance for which the predicate
+    /// return true. If no instance is found, None is returned.
+    pub fn find_node(&self, predicate: fn(&SyntaxTree<T>) -> bool) -> Option<&SyntaxTree<T>> {
+        if predicate(self) {
+            Some(self)
+        } else {
+            todo!()
+        }
+    }
+
+    /// Perform a depth-first search with the given predicate.
+    /// The method returns a mutable reference to the first SyntaxTree instance for which the predicate
+    /// return true. If no instance is found, None is returned.
+    pub fn find_node_mut(
+        &mut self,
+        predicate: fn(&SyntaxTree<T>) -> bool,
+    ) -> Option<&SyntaxTree<T>> {
+        todo!()
+    }
+
+    /// Return a reference to the value carried by the root of this tree
+    pub fn value(&self) -> &T {
+        &self.value
+    }
+
+    /// Return the id of the root of this tree
+    pub fn id(&self) -> ID {
+        self.id
+    }
+
+    /// Return a reference to the children of this tree
+    pub fn children(&self) -> &Vec<SyntaxTree<T>> {
+        &self.children
+    }
+}
+
+impl<T: Display> SyntaxTree<T> {
+    pub fn print(&self) -> String {
+        if self.children.is_empty() {
+            format!("{}", self.value)
+        } else {
+            format!(
+                "{}\n[\n{}\n]",
+                self.value,
+                &self
+                    .children
+                    .iter()
+                    .map(|tn| tn.print_inner(1))
+                    .collect::<Vec<String>>()
+                    .join(",\n")
+            )
+        }
+    }
+
+    pub fn print_inner(&self, indent: usize) -> String {
+        let mut indentation = String::new();
+        for _ in 0..indent {
+            indentation.push_str("  ");
+        }
+        if self.children.is_empty() {
+            format!("{}{}", &indentation, self.value)
+        } else {
+            format!(
+                "{}{}\n{}[\n{}\n{}]",
+                &indentation,
+                self.value,
+                &indentation,
+                &self
+                    .children
+                    .iter()
+                    .map(|tn| tn.print_inner(indent + 1))
+                    .collect::<Vec<String>>()
+                    .join(",\n"),
+                indentation,
+            )
+        }
+    }
+}
+
+impl<T: Display> Display for SyntaxTree<T> {
+    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+        write!(f, "({})", self.print())
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    fn fill_tree_numbers() -> SyntaxTree<i32> {
+        let mut tree = SyntaxTree::new(0);
+
+        for child in 1..3 {
+            let mut child = SyntaxTree::new(child);
+            for grandchild in 1..3 {
+                let id = grandchild * 10;
+                child.prepend_node(SyntaxTree::new(id));
+            }
+            tree.push_node(child);
+        }
+        tree
+    }
+
+    fn fill_tree_words() -> SyntaxTree<String> {
+        let mut tree = SyntaxTree::new(to_s("root"));
+
+        for (child_id, child) in ["first", "second", "third"].iter().map(to_s).enumerate() {
+            let child_id = child_id;
+            let mut child = SyntaxTree::new(child);
+            if child_id == 0 {
+                let mut descendant1 = SyntaxTree::new(to_s("A"));
+                let mut descendant2 = SyntaxTree::new(to_s("B"));
+                let descendant3 = SyntaxTree::new(to_s("C"));
+                descendant2.push_node(descendant3);
+                descendant1.push_node(descendant2);
+                child.push_node(descendant1);
+            }
+            tree.push_node(child);
+        }
+        tree
+    }
+
+    #[test]
+    fn number_tree() -> Result<(), String> {
+        let tree = fill_tree_numbers();
+
+        println!("{}", tree);
+        assert_eq!(
+            String::from(
+                "0\n[\n  1\n  [\n    20,\n    10\n  ],\n  2\n  [\n    20,\n    10\n  ]\n]"
+            ),
+            tree.print()
+        );
+        Ok(())
+    }
+
+    #[test]
+    fn word_tree() -> Result<(), String> {
+        let tree = fill_tree_words();
+
+        println!("{}", tree);
+        assert_eq!(
+            String::from("root\n[\n  first\n  [\n    A\n    [\n      B\n      [\n        C\n      ]\n    ]\n  ],\n  second,\n  third\n]"),
+            tree.print()
+        );
+        Ok(())
+    }
+
+    #[test]
+    fn find_node_by_value() -> Result<(), String> {
+        let tree = fill_tree_numbers();
+
+        assert!(tree.find_node(|n| n.value == 0).is_some());
+        let left = tree.find_node(|n| n.value == 1).unwrap();
+        assert!(left.find_node(|n| n.value == 10).is_some());
+        assert!(left.find_node(|n| n.value == 20).is_some());
+
+        let right = tree.find_node(|n| n.value == 2).unwrap();
+        assert!(right.find_node(|n| n.value == 10).is_some());
+        assert!(right.find_node(|n| n.value == 20).is_some());
+        Ok(())
+    }
+
+    fn to_s<T: Display>(value: T) -> String {
+        format!("{}", value)
+    }
+}
diff --git a/src/syntree.rs b/src/syntree.rs
deleted file mode 100644
index 8f6b4564bda6772b343387aadbf1577ea7486ef2..0000000000000000000000000000000000000000
--- a/src/syntree.rs
+++ /dev/null
@@ -1,145 +0,0 @@
-use std::fmt::{Display, Formatter};
-
-#[derive(Clone, Copy, Debug, Default, PartialEq)]
-pub struct ID(usize);
-
-#[derive(Debug, PartialEq)]
-pub struct Syntree<T> {
-    id: ID,
-    value: T,
-    children: Vec<Syntree<T>>,
-}
-
-// Complete the implementation
-// Hint: Start with seek_node_mut
-impl<'a, T> Syntree<T> {
-    pub fn new(value: T, id: ID) -> Syntree<T> {
-        todo!()
-    }
-
-    pub fn push_node(&mut self, parent_id: ID, new_node: Syntree<T>) -> Result<(), String> {
-        todo!()
-    }
-
-    pub fn prepend_node(&mut self, parent_id: ID, new_node: Syntree<T>) -> Result<(), String> {
-        todo!()
-    }
-
-    pub fn insert_node(
-        &mut self,
-        parent_id: ID,
-        index: usize,
-        new_node: Syntree<T>,
-    ) -> Result<(), String> {
-        todo!()
-    }
-
-    // Anmerkung: `'a` Is ein Lebenszeit angabe für die Referenzen
-    // Hier wird einfach nur explizit gesagt: Solange `self` lebt, lebt auch die Referenz im Rückgabewert
-    pub fn seek_node(&'a self, id: &ID) -> Option<&'a Syntree<T>> {
-        if self.id == *id {
-            Some(self)
-        } else {
-            for child in &self.children {
-                if let Some(result) = child.seek_node(id) {
-                    return Some(result);
-                }
-            }
-            None
-        }
-    }
-
-    pub fn seek_node_mut(&'a mut self, id: &ID) -> Option<&'a mut Syntree<T>> {
-        todo!()
-    }
-}
-
-impl<T: Display> Syntree<T> {
-    pub fn print(&self) -> String {
-        if self.children.is_empty() {
-            format!("{}", self.value)
-        } else {
-            format!(
-                "{}-[{}]",
-                self.value,
-                &self
-                    .children
-                    .iter()
-                    .map(|tn| tn.print())
-                    .collect::<Vec<String>>()
-                    .join(",")
-            )
-        }
-    }
-}
-
-impl<T: Display> Display for Syntree<T> {
-    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
-        write!(f, "({})", self.print())
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-
-    #[test]
-    fn fill_tree() -> Result<(), String> {
-        let mut tree = Syntree::new(0, ID(0));
-
-        for child in 1..3 {
-            let child_id = ID(child);
-            let mut child = Syntree::new(child, child_id);
-            for grandchild in 1..3 {
-                let id = grandchild * 10;
-                child.prepend_node(child_id, Syntree::new(id, ID(id)))?;
-            }
-            tree.push_node(ID(0), child)?;
-        }
-        println!("{}", tree);
-        assert_eq!(String::from("0-[1-[20,10],2-[20,10]]"), tree.print());
-        Ok(())
-    }
-
-    #[test]
-    fn fill_tree_words() -> Result<(), String> {
-        let mut tree = Syntree::new(to_s("root"), ID(0));
-
-        for (child_id, child) in ["first", "second", "third"].iter().map(to_s).enumerate() {
-            let child_id = ID(child_id);
-            let mut child = Syntree::new(child, child_id);
-            if child_id.0 == 0 {
-                let descendant = Syntree::new(to_s("A"), ID(4));
-                child.push_node(child_id, descendant)?;
-                let descendant = Syntree::new(to_s("B"), ID(5));
-                child.push_node(ID(4), descendant)?;
-                let descendant = Syntree::new(to_s("C"), ID(6));
-                child.push_node(ID(5), descendant)?;
-            }
-            tree.push_node(ID(0), child)?;
-        }
-        println!("{}", tree);
-        assert_eq!(
-            String::from("root-[first-[A-[B-[C]]],second,third]"),
-            tree.print()
-        );
-        Ok(())
-    }
-
-    fn to_s<T: Display>(value: T) -> String {
-        format!("{}", value)
-    }
-
-    #[test]
-    fn node_id_not_found() -> Result<(), String> {
-        let mut tree = Syntree::new(0, ID(0));
-        let child_id = ID(1);
-        let child = Syntree::new(1, child_id);
-        tree.push_node(ID(0), child)?;
-
-        let child_id = ID(2);
-        let child = Syntree::new(3, child_id);
-        assert!(tree.push_node(ID(5), child).is_err());
-        Ok(())
-    }
-}