I'm trying to learn python with some data-structure. I'm trying to create a binary tree.
So I've created a node like:
class Node(object):
def __init__(self,value,left,right):
self.value = value
self.left = left
self.right = right
Then I've created a tree like:
class Tree(object):
def __init__(self):
self.node = None
def insert(self,node,element):
if node == None:
node = Node(element,None,None)
return
elif element <= node.value:
self.insert(node.left, element)
else:
self.insert(node.right, element)
When I'm trying to insert element to the tree, it doesn't work. There is a stack call for that insert and the node==None is hitting and new Node is being created. But the Tree is not updating.
The line
node = Node(element,None,None)
will create a method local variable, which is only visible in the scope of that method. Thus it will not affect the Tree instance in any way. To create an instance variable, use
self.node = Node(element,None,None)
Related
I have a Linked Lists assignment for school although I am just getting the hang of class constructors. I am trying to simply get the basics of the linked list data structure down, and I understand the basic concept. I have watched lots of Youtube tutorials and the like, but where I am failing to understand is how to print out the cargo or data in my nodes using a loop.
I have written something along these lines:
class Node:
def __init__(self, value, pointer):
self.value = value
self.pointer = pointer
node4 = Node(31, None)
node3 = Node(37, None)
node2 = Node(62, None)
node1 = Node(23, None)
Now...I understand that each node declaration is a call to the class constructor of Node and that the list is linked because each node contains a pointer to the next node, but I simply don't understand how to print them out using a loop. I've seen examples using global variables for the "head" and I've seen subclasses created to accomplish the task. I'm old and dumb. I was wondering if someone could take it slow and explain it to me like I'm 5. If anyone out there has the compassion and willingness to hold my hand through the explanation, I would be greatly obliged. Thank you in advance, kind sirs.
First of all, your nodes should be created something like this :
node4 = Node(31, node3)
node3 = Node(37, node2)
node2 = Node(62, node1)
node1 = Node(23, None)
Now, i am sure you can see that the last node in the list would point to None. So, therefore, you can loop through the list until you encounter None. Something like this should work :
printhead = node4
while True:
print(printhead.value)
if printhead.pointer is None:
break;
else :
printhead = printhead.pointer
This is a very basic linked list implementation for educational purposes only.
from __future__ import print_function
"""The above is needed for Python 2.x unless you change
`print(node.value)` into `print node.value`"""
class Node(object):
"""This class represents list item (node)"""
def __init__(self, value, next_node):
"""Store item value and pointer to the next node"""
self.value = value
self.next_node = next_node
class LinkedList(object):
"""This class represents linked list"""
def __init__(self, *values):
"""Create nodes and store reference to the first node"""
node = None
# Create nodes in reversed order as each node needs to store reference to next node
for value in reversed(values):
node = Node(value, node)
self.first_node = node
# Initialize current_node for iterator
self.current_node = self.first_node
def __iter__(self):
"""Tell Python that this class is iterable"""
return self
def __next__(self):
"""Return next node from the linked list"""
# If previous call marked iteration as done, let's really finish it
if isinstance(self.current_node, StopIteration):
stop_iteration = self.current_node
# Reset current_node back to reference first_node
self.current_node = self.first_node
# Raise StopIteration to exit for loop
raise stop_iteration
# Take the current_node into local variable
node = self.current_node
# If next_node is None, then the current_node is the last one, let's mark this with StopIteration instance
if node.next_node is None:
self.current_node = StopIteration()
else:
# Put next_node reference into current_node
self.current_node = self.current_node.next_node
return node
linked_list = LinkedList(31, 37, 62, 23)
for node in linked_list:
print(node.value)
This doesn't handle many cases properly (including break statement in the loop body) but the goal is to show minimum requirements for linked list implementation in Python.
I understand how to insert using recursion. I also understand why this code doesn't work as expected because while I'm updating the variable "current" in the "insert" method, I'm only attaching the name label "current" to some node, copy that node to "current" and modify "current", but not the actual node in the binary search tree.
So how can I actually modify the node in the binary search tree using the iterative concept here? And more generally speaking, how can I make a "shallow copy" to any object I created and actually modify that object? A "list" object in Python is an example that has the desired property. What code in "list" makes it behave this way? Thanks in advance.
class Node:
def __init__(self, data, left=None, right=None):
self.data = data
self.left = left
self.right = right
class BinarySearchTree:
def __init__(self, root=None):
self.root = root
def insert(self, data):
if self.root:
current = self.root
while current:
if data < current.data:
current = current.left
elif data > current.data:
current = current.right
current = Node(data)
else:
self.root = Node(data)
bst = BinarySearchTree()
bst.insert(2)
bst.insert(1)
bst.insert(3)
I am trying to understand binary trees, but doing so has brought me to confusion about how class instances interact, how does each instance link to another?
My Implementation:
class Node(object):
def __init__(self, key):
self.key= key
self.L = None
self.R = None
class BinaryTree(object):
def __init__(self):
self.root = None
def get_root(self):
return self.root
def insert(self, key):
if self.get_root()==None:
self.root = Node(key)
else:
self._insert(key, self.root)
def _insert(self, key, node):
if key < node.key:
if node.L == None:
node.L = key
else:
self._insert(key, Node(node.L))
if key > node.key:
if node.R == None:
node.R = key
else:
self._insert(key, Node(node.R))
myTree= BinaryTree()
A Scenario
So lets say I want to insert 10, I do myTree.insert(10) and this will instantiate a new instance of Node(), this is clear to me.
Now I want to add 11, I would expect this to become the right node of the root node; i.e it will be stored in the attribute R of the root node Node().
Now here comes the part I don't understand. When I add 12, it should become the child of the root nodes right child. In my code this creates a new instance of Node() where 11 should the be key and 12 should be R.
So my question is 2-fold: what happens to the last instance of Node()? Is it deleted if not how do I access it?
Or is the structure of a binary tree to abstract to think of each Node() connected together like in a graph
NB: this implementation is heavily derived from djra's implementation from this question How to Implement a Binary Tree?
Make L and R Nodes instead of ints. You can do this by changing the parts of your _insert function from this:
if node.L == None:
node.L = key
to this:
if node.L == None:
node.L = Node(key)
There is also a problem with this line:
self._insert(key, Node(node.L))
The way you're doing it right now, there is no way to access that last reference of Node() because your _insert function inserted it under an anonymously constructed node that has no parent node, and therefore is not a part of your tree. That node being passed in to your insert function is not the L or R of any other node in the tree, so you're not actually adding anything to the tree with this.
Now that we changed the Ls and Rs to be Nodes, you have a way to pass in a node that's part of the tree into the insert function:
self._insert(key, node.L)
Now you're passing the node's left child into the recursive insert, which by the looks of thing is what you were originally trying to do.
Once you make these changes in your code for both the L and R insert cases you can get to the last instance of Node() in your
10
\
11
\
12
example tree via myTree.root.R.R. You can get its key via myTree.root.R.R.key, which equals 12.
Most of you're questions come from not finishing the program; In your current code after myTree.insert(11) you're tree is setting R equal to a int rather than another Node.
If the value isn't found then create the new node at that point. Otherwise pass the next node into the recursive function to keep moving further down the tree.
def _insert(self, key, node):
if key < node.key:
if node.L == None:
node.L = Node(key)
else:
self._insert(key, node.L)
if key > node.key:
if node.R == None:
node.R = Node(key)
else:
self._insert(key, node.R)
P.S. This isn't finished you're going to need another level of logic testing incase something is bigger than the current Node.key but smaller than the next Node.
I am brushing up on some data structures and algorithms with Python, so I am implementing an Unordered Linked list. Within the same file I first wrote a Node class followed by a List class. What I don't get is how the "current" variable in my search_item() method seems to be a node object or at least able to access the Node class methods and attributes. I noticed that if I comment out my add_node() method then "current" no longer has access to Node's methods. Now I am not explicitly using neither inheritance nor composition, so I am having a hard time seeing how current just gets to call get_next() the way the code is written below. I would think I'd have to declare current as: current = Node(self.head) but just current = self.head seems to work?
Your help would be greatly appreciated.
class Node:
def __init__(self, data):
self.data = data
self.next = None
def get_data(self):
return self.data
def set_data(self, d):
self.data = d
def get_next(self):
return self .next
def set_next(self, n):
self.next = n
class UnorderedList:
def __init__(self):
self.head = None
def add_node(self, item):
tmp = Node(item)
tmp.set_next(self.head)
self.head = tmp
def search_item(self, item):
current = self.head
# current = Node(self.head)
found = False
while current != None and not found:
if current.get_data() == item:
found = True
else:
current = current.get_next()
return found
Well if you comment out add_node then you do not add nodes to your linked list any longer therefore search_item will always see the initial value of self.head which is None.
Calling current.get_next() just works because via add_node you always ensure that self.head points either to None or to an instance of Node as tmp is created by tmp = Node(item) and then assigned to self.head = tmp. Therefore when setting current = self.head it will already refer to an instance of Node (or None) so you do not need to call current = Node(self.head).
I just recently came across the concept of duck typing and this old post of mine came to mind. It seems that this is what's at play and just didn't understand it at the time. 'current' is set to None by default, by when invoking any of the methods defined in the Node class, it is automatically defined as Node object.
Basically I want to be able to have each node of type tree have a Data field and a list of branches. This list should contain a number of objects of type Tree.
I think I have the actual implementation of the list down, but I get strange behavior when I try using the getLeaves method. Basically it calls itself recursively and never returns, and the way that happens is somehow the second node of the tree gets it's first branch set as itself (I think).
class Tree:
"""Basic tree graph datatype"""
branches = []
def __init__(self, root):
self.root = root
def addBranch (self, addition):
"""Adds another object of type Tree as a branch"""
self.branches += [addition]
def getLeaves (self):
"""returns the leaves of a given branch. For leaves of the tree, specify root"""
print (len(self.branches))
if (len(self.branches) == 0):
return self.root
else:
branchSum = []
for b in self.branches:
branchSum += b.getLeaves()
return (branchSum)
Your 'branches' variable is a class member, not an instance member. You need to initialize the 'branches' instance variable in the constructor:
class Tree:
"""Basic tree graph datatype"""
def __init__(self, root):
self.branches = []
self.root = root
The rest of your code looks good.
Is self.root the parent of said tree? In that case, getLeaves() should return self if it has no branches (len(self.branches)==0) instead of self.root as you have it there. Also, if you do have child branches you should include self within branchSum.
Possible solution (your source code with small changes):
class Tree:
def __init__(self, data):
"""Basic tree graph datatype"""
self.data = data
self.branches = []
def addBranch (self, addition):
"""Adds another object of type Tree as a branch"""
self.branches.append(addition)
def getLeaves (self):
"""returns the leaves of a given branch. For
leaves of the tree, specify data"""
if len(self.branches) == 0:
return self.data
else:
branchSum = []
for b in self.branches:
branchSum.append(b.getLeaves())
return branchSum
## Use it
t0 = Tree("t0")
t1 = Tree("t1")
t2 = Tree("t2")
t3 = Tree("t3")
t4 = Tree("t4")
t0.addBranch(t1)
t0.addBranch(t4)
t1.addBranch(t2)
t1.addBranch(t3)
print(t0.getLeaves())
Output:
[['t2', 't3'], 't4']
Remarks:
Looks that some formatting is broken in your code.
Not really sure if this is what you want. Do you want all the leaves in one level of the list? (If so the source code has to be adapted.)