0

I am having a bit of a hard time with a recursive insert function that I been studying through zybooks data structures.I didn't have any issues with a normal insert but with the recursive it is confusing me a lot. The function is gathering the tree information as a parameter. The keys are the names which are all unique. I haven't inserted anything in the parameter to put in the function in the else statement. Would appreciate some pointers if possible.

class Star:

    def __init__(self, hvg_db, name, mag, spectral, habit, dist):
        self.hvg_db = hvg_db 
        self.display_name = name  #
        self.magnitude = mag 
        self.spectral_class = spectral  
        self.habitable = habit  #
        self.distance_parsecs = dist 

class TreeNode:
    def __init__(self, star):
        self.left = None
        self.right = None
        self.star_info = star
        self.name = "N" + str(self.star_info.hvg_db)
        self.key = star.display_name

class Tree:
    def __init__(self, name):
        self.name = name
        self.node_num = 0
        self.node_list = []
        self.root = None

       def insert_rec(self, star):  # method receives star info (star, magnitude, habitable, etc

        star = TreeNode(star)

        if self.root is None:
            self.root = star
            print("Parent Activated")

        parent = self.root

        if star.key < parent.key:
            if parent.left is None:
                print("Left is Empty")
                parent.left = star
            else:
                print("Else Left")
                self.insert_rec(star)

            if parent.right is None:
                print("Right is Empty")
                parent.right = star
            else:
                print("Else Right")
                self.insert_rec(star)
def main():
    # Instantiate Binary Tree to hold the stars
    star_tree = Tree("Star Catalog")

    with open('HabHYG_short.csv', 'r') as csvfile:
        lines = csv.reader(csvfile, delimiter=',')

        # skip header row
        next(csvfile)

        # get time in nanoseconds -- maybe OS-specific?
        # See https://docs.python.org/3/library/time.html

        t0 = time.perf_counter_ns()

        obs_processed = 0

        for row in lines:
            # hvg_db, name, mag, spectral, habit, dist)
            this_star = Star(row[0], row[3], row[16], row[11], row[2], row[12])
            star_tree.insert_rec(this_star)
            
Jay
  • 7
  • 1
  • 5
  • Hi Jay, see [this Q&A](https://stackoverflow.com/a/66340109/633183) for an extensive write-up on the topic. Let me know if that helps :D – Mulan Jul 09 '23 at 17:34

1 Answers1

0

A nice way to handle recursive operations in an object-oriented tree structure is to implement them in the nodes themselves. Create an insert method of TreeNode that recursively inserts a new node somewhere underneath that node. This only requires two decisions:

  1. Is the new node going somewhere in my left or right subtree?
  2. Does the subtree already exist (in which case we want to insert it underneath that node) or am I creating it?
class TreeNode:
    def __init__(self, key):
        self.key = key
        self.left = None
        self.right = None

    def insert(self, node):
        if node.key < self.key:
            # Insert in left subtree, or create it.
            if self.left:
                self.left.insert(node)
            else:
                self.left = node
        else:
            # Insert in right subtree, or create it.
            if self.right:
                self.right.insert(node)
            else:
                self.right = node

Then you can build a tree by doing something like:

root = TreeNode(5)
root.insert(TreeNode(3))
root.insert(TreeNode(8))
root.insert(TreeNode(1))
root.insert(TreeNode(4))
root.insert(TreeNode(6))
root.insert(TreeNode(9))

which builds a tree like:

                  5
                /   \
               3     8
              / \   / \
             1   4 6   9

Writing a function that'll print out a nice tree representation like that is left as an exercise to the reader, but it's easy to mess around with it in the REPL:

>>> from test import *
>>> root.left.left.key
1
>>> root.key
5
>>> root.right.key
8
>>> root.right.right.key
9

The idea of recursion is that you don't need to write a loop that traverses the tree; all you need to do is figure out whether you (the self that insert was called on) know exactly where the new node needs to go, or if you need to hand it off to another node (one of your subtrees) to figure out.

The iteration happens implicitly as each node calls the next one in the chain. Each recursive call just needs to move the execution flow one step closer to where it needs to get.

Samwise
  • 68,105
  • 3
  • 30
  • 44
  • Samwise thank you, I included the Tree code on the top. There is more but I wanted to focus only on the recursion method let me know if that answers your questions. – Jay Jul 09 '23 at 15:38
  • I didn't require any clarification, I was just trying to explain the way the code works. Although looking at the code you added I can see a problem that has nothing to do with recursion, which is that `root` attribute not being defined anywhere. I'll update my example code a bit so it doesn't assume that there's any such thing as a separate "tree" class, which actually simplifies it a lot. – Samwise Jul 09 '23 at 15:57
  • Sam look at the pseudo code above. I actually needed to follow it, can you provide me some information on that pseudo code also. Thank yoU! – Jay Jul 09 '23 at 16:10
  • Your pseudocode looks exactly like what I implemented (it's a very standard way of doing insertions in a sorted tree) and then also explained in three different ways in my answer, so I'm not sure what else you're looking for. Did you actually read the answer and find it completely confusing, or are you asking followup questions *before* reading the post you're asking questions about? – Samwise Jul 09 '23 at 16:13
  • Your post was very clear and I appreciate you taking your time Sam. I updated the code with the rest of the classes. I was able to get this to easily work with a normal insert method which I didn't included to not waste your time but the recursive method is giving me problems. Let me know if I am making a mistake – Jay Jul 09 '23 at 18:43
  • Verify the added classes and maybe it may make sense where I am being stuck. – Jay Jul 09 '23 at 18:50
  • You should look at the error messages that your code is producing when you run it; those will help get you pointed in the right direction: Hint: my `insert` function always expects to take a `TreeNode` value and it always calls itself recursively with that `TreeNode` value. What type of object is `star` in your function? – Samwise Jul 09 '23 at 19:21
  • line 37, in __init__ self.name = "N" + str(self.star_info.hvg_db) ^^^^^^^^^^^^^^^^^^^^^ AttributeError: 'TreeNode' object has no attribute 'hvg_db' – Jay Jul 09 '23 at 21:09
  • added the function in the notes again with updated code – Jay Jul 09 '23 at 21:09
  • Your error message is telling you that `self.star_info` is a `TreeNode` instead of a `Star` as you probably expect. Does that seem right? How might you have ended up with a `TreeNode` instead of a `Star`? (hint: what type of object is `star` after you do `star = TreeNode(star)`?) – Samwise Jul 09 '23 at 21:17
  • It becomes a tree object – Jay Jul 09 '23 at 22:07
  • I dont know what else to do im already mentally tired I tried everything. – Jay Jul 10 '23 at 03:08
  • 1
    I think i know what is happening. It is not the tree that we want is the information in Star_info. The problem i am having now is making sure I am using the proper paramenter. If we use the current star it will keep sending the same information. – Jay Jul 10 '23 at 15:14
  • Indeed. If you take a star as your arg, then you need to create the node when it’s time to add it to the tree (ie in the non-recursive case). Otherwise, you could always do it like I did in my answer, and create the node outside the insert function entirely. – Samwise Jul 10 '23 at 16:22
  • In general you want to avoid ever doing something like `star = TreeNode(star)` where you change the type of a variable IMO; it makes it hard to keep track of what type it has in each part of your function. – Samwise Jul 10 '23 at 16:24
  • what do you suggest instead? – Jay Jul 10 '23 at 18:38
  • There are two suggestions in my previous comment; just pick the one you like best. You could also look at how the code in my answer avoids this problem. – Samwise Jul 10 '23 at 18:43