W3151 Trees

From Coder Merlin
Revision as of 11:03, 24 January 2022 by Tatsat-jha (talk | contribs) (→‎Quiz)
Within these castle walls be forged Mavens of Computer Science ...
— Merlin, The Coder
A Magnolia Tree

Prerequisites[edit]

Introduction[edit]

In Computer Science, Trees are a hierarchal data structure that are very commonly used. At its core, the Tree is a series of nodes where each node contains some data and references one or multiple other nodes called Children. These structures are called Trees because of the visual resemblance between the data structure and a tree's roots. It's because of this that the top most Node is called the root.

The use of Trees as Data Structures can be seen everywhere: file systems, relationship hierarchies, visual displays and GUIs and many more. This is why developers ought to understand this data structure and how to apply it.

Structure[edit]

As has been mentioned, the structure of a Tree is made entirely of Nodes where each node has some data that's being stored and references to other Nodes lower in the tree. If you look at a Node in a tree, it will likely be referencing one or several Nodes beneath it. These Nodes that are being referenced are called the Children or Child Nodes while the Node they come from is their Parent.

Its important to understand that in a General Tree, a Node can only have One Parent but multiple children.

Now, looking at the Structure of a tree, it starts with The Root. The root is the very top of a Tree's hierarchy and can be recognized because it is the only Node that is not referenced to by another Node. Conversely, a Tree will end with Leaves. Leaves are simply the Nodes that do not reference any other Node.

In fact, the idea of The Root and Leaves lends itself into the idea of a Node's Degree. The Degree of a Node, when discussing Trees, simply refers to how many children does a Node have plus the Number of children each of those Nodes have and so on until you reach a Leaf. Said in another way, The Degree of a given Node is the number of Nodes that can call that given Node one of its roots. This means that if there are a total of twenty Nodes in a Tree, the top Root will have a Degree of 20.

Additionally, in Trees there's the concept of Level. The Root will always be Level 0 and its immediate Children will be Level 1, their children will be level 2 and so on. Note that a Leaf can come up in any Level greater than 0, not just the lowest level in the tree.

For clarification on a Tree's Structure, consult the following diagram.

Structure of a Binary Tree

Quiz[edit]

1 What is the name for a Node without a Parent?

The Leaf
The Root
Every Node must have a Parent
The Height

2 What is the name of a Node without Children?

The Depth
A Leaf
The Root
The Lowest Level

3 True or False: A Tree's Leaves must be at its lowest Level

True
False

4 True or False: A General Tree can have any number of Nodes as Children

True
False

Usages[edit]

As we mentioned, Trees have many Usages in the real-world. Most notably, they're used for storing data that lends itself to be hierarchal. The common example being, of course, a file system. This is why the base of a file system is often called The Root. Indeed, Hierarchies are present in many day-to-day examples. Games may have hierarchies implemented into collectible items, Websites have tree-like hierarchies in terms of its URL, Enterprise applications in CAD or Digital Art Software may store its file data as a Tree, Large Data companies often contain much of their data in hierarchies for quicker response times when executing commands.

In fact, the General Tree can be used to implement more specialized data structures such as Binary Trees, which are often used for applications where time complexity is very important specifically in searching algorithms. This has made the usages of Tree Data structures very common and is why knowing Trees algorithms is so important.

Quiz[edit]

1 What relationship do Trees represent in their method of storing data?

A Hierarchical Relationship
A Lack of a Relationship
A Dynamic Relationship
A Linear Relationship

2 How do trees differ from a data structure such as a Graph?

Graphs provide a statistical understanding of data while Trees show relationships between data
Graphs show relationships between data while Trees represent data hierarchically
Graphs provide a Hierarchical view of data while Trees organize them based on an arbitrary relationships
Graphs store data in a non-linear fashion while Trees store data linearly

3 True or False: General Trees are primarily used to create more complex trees

True
False

4 True or False: Trees are implemented in many Systems in some capacity whether it be as general trees or as one of their evolutions

True
False


Swift Implementation[edit]

Here, we'll be implementing a general tree, this means we won't be putting in any limits on how many children a Node can have or anything like that, which means this should be rather straight forward to implement. As always, we'll start by making a Node class to handle all of our nodes.

class Node {
  var value: String
  var children: [Node] = []
  var parent: Node?

  init(value: String){
    self.value = value
  }
}

As you can see, every Node will have a value, in this tree we will use exclusively Strings to start off, additionally we have to other variables: a list of children and a parent. Note that the Parent may be nil for some Nodes, specifically the root. We also have it set so that a Node has no children by default. Finally, we have a simple init.

Now, we'll make a Tree class to handle the data structure and all of the methods it needs to have.

 
class Tree {

  var root: Node

  init(root: Node){
    self.root = root
  }
}

We will start by having a simple class where we must define the root Node upon defining the Tree. Now, we'll want to add a function that allows us to add a value wherever we want into the tree. A simple implementation of this is as follows.

  func add(parent: Node, child: Node){
    parent.children.add(child)
    child.parent = parent
  }

Here, all we're doing is asking for a Parent Node and the Child Node and then making a connection between them. Then we take the parent and add the child node to the parent's list of children. We'll then take the child node and set its parent value to the given parent Node.

Now, we'll want to be able to see our tree, so to do that, we'll implement an Extension on the Node class to allow us the ability to print Node classes

extension Node: CustomStringConvertible {
    var description: String {
      
      var text = "\(value)"

      if children.isEmpty{ return text}
      
      text += " {" + children.map { $0.description }.joined(separator: ", ") + "} "     
      return text
    }
  }

Finally, we can test our general tree. In the following we'll use our tree to implement the taxonomy of a Wolf, a Coyote, and a Tiger. Taxonomy is use in biology as a hierarchy of living creatures that is represented with trees.

var anamalia = Node(value:"Anamalia")
var chordata = Node(value:"Chordata")
var manamalia = Node(value:"Manamalia")
var carnivora = Node(value:"Carnivora")

var caridae = Node(value: "Caridae")
var felidae = Node(value: "Felidae")

var canis = Node(value: "Canis")
var panthera = Node(value: "Panthera")

var lupin = Node(value: "Lupin")
var latrans = Node(value: "Latrans")
var tigris = Node(value: "Tigris") //finish declaring our Nodes

var taxonomy = Tree(root: anamalia) //declare tree

taxonomy.add(parent: anamalia, child: chordata)
taxonomy.add(parent: chordata, child: manamalia)
taxonomy.add(parent: manamalia, child: carnivora)

taxonomy.add(parent: carnivora, child: caridae)
taxonomy.add(parent: carnivora, child: felidae)

taxonomy.add(parent: caridae, child: canis)
taxonomy.add(parent: felidae, child: panthera)

taxonomy.add(parent: canis, child: lupin)
taxonomy.add(parent: canis, child: latrans)
taxonomy.add(parent: panthera, child: tigris) //finish adding Nodes into Tree

print(anamalia) //print the root Node to see it and all its children

When we run this code, we would have made a successful Tree, however, it's a little clunky and inefficient. As an Exercise, think of how you can optimize the classes function so so that the Tree is filled in a more efficient manner. In the meanwhile, we can implement a Search function into our Tree. To do this, we'll add a recursive method in the Node class.

func search(value:String) ->Node?{
    if value == self.value {
      return self
    }
    for child in self.children {
      let found = child.search(value: value)
    
      if found != nil  {
        return found
      }
    }
    return nil
  }

All we're doing is looking at any given Node and seeing if that Node's value is the value we are searching for. If it isn't, we will look at the Node's children and search them, if that doesn't work we know that the Node is not in the tree. For consistency we will put this function into the taxonomy class as well where it will start searching from the root node by default.

We can test out the function by writing the following

print(taxonomy.search(value: "Lupin")!) //unpack the given optional Node to print it, will print "Lupin"

The following Tree Diagram shows the Tree we've made.

Implemented Tree.png

Think about what functions you can add or how you can customize the data structure for higher efficiency.

Beyond Basic Trees[edit]

From what you've learned about basic trees, you will soon be able to make more complicated, specialized tress (such as binary trees) which can be used for several algorithms and handling data. Among the most popular forms of trees are binary trees, AVL Trees, and Red Black Trees. More specialized tress can be used for their time and space complexity as alternatives to data structures such as Arrays and Linked Lists, providing situational advantages. Begin thinking about how more specialized trees may work.

Key Concepts[edit]

Key ConceptsKeyConceptsIcon.png
  • Trees are data structures meant to show hierarchical relationships and are composed of Nodes where each Node has a single parent and a list of children
  • The Root is the top of a tree and has no parents whereas the Leaves are the end of a Tree and have no children
  • General Trees can be used to make more specialized trees that offer improved time and space complexities in certain operations

Exercises[edit]

ExercisesExercisesIcon.png
  • Look at the code sample above, try to improve the efficiency of filling a tree with a recursive function, refactor given code if necessary
  • Try to implement Levels to each Node, then try to make a method that finds all the Leaves of a tree and print its value with its level
  • Try to implement limits on how many children each Node may have, see how this effects the Tree

References[edit]