BST problems in python - python

class BST:
"""A Binary Search Tree."""
def __init__(self: 'BST', container: list =None) -> None:
"""
Initialize this BST by inserting the items from container (default [])
one by one, in the order given.
"""
# Initialize empty tree.
self.root = None
# Insert every item from container.
if container:
for item in container:
self.insert(item)
def insert(self: 'BST', item: object) -> None:
"""
Insert item into this BST.
"""
# Find the point of insertion.
parent, current = None, self.root
while current:
if item < current.item:
parent, current = current, current.left
else: # item > current.item
parent, current = current, current.right
# Create a new node and link it in appropriately.
new_node = _BSTNode(item)
if parent:
if item < parent.item:
parent.left = new_node
else: # item > parent.item
parent.right = new_node
else:
self.root = new_node
this is the code that I built for the BST class, I would like implement a max_node function that finds the maximum node without using recursion , how am I suppose to do that?

In a BST, the maximum node is simply the right-most node, so start at the head and just keep taking right children until you hit a node with no right child. This can easily be done iteratively (and in fact, that's probably how I would do it anyway).
In pseudocode:
max_node = head
while hasRightChild(max_node)
max_node = max_node.right_child;

Related

Inserting at the head of a linked list in python

I'm trying to create a function that takes in a head of a linked list and a value, create a node with that value, set node.next to head, and then update the the new node to be the head. I got it to work but I feel like I'm doing this very inefficiently by returning values, so I was wondering if there is a more elegant way to do this.
Here's the code I'm using:
#!/usr/bin/env python3
"""
This module is a linked list implementation.
"""
class Node:
"""
Node structure to be used in our linked list.
"""
def __init__(self, value):
self.value = value
self.next = None
def linked_insert(head, value):
"""
Insert new node to the tail of the linked list.
Time Complexity: O(n)
"""
current = head
while current.next is not None:
current = current.next
current.next = Node(value)
def linked_insert2(head, value):
"""
Insert new node to the head of the linked list, making sure to update head.
Time Complexity: O(1)
"""
to_insert = Node(value)
to_insert.next = head
head = to_insert
return head
def linked_extract(head):
"""
Extract the last element in the linked list
"""
current = head
while current.next.next is not None:
current = current.next
tail = current.next
current.next = None
return tail
def linked_display(head):
"""
Print all node values in the linked list
"""
current = head
while current is not None:
print(current.value)
current = current.next
# Test Program
head = Node(5)
# linked_insert(head, 1)
# linked_insert(head, 2)
# linked_insert(head, 3)
#
# print(linked_extract(head).value)
head = linked_insert2(head, 1)
head = linked_insert2(head, 2)
head = linked_insert2(head, 3)
linked_display(head)
Is there a way to do this without having to return the value of head and setting head = returned value in the test program?
The function in question is linked_insert2(). The whole program is meant to be a linked list implementation in python.
Implementation using linked list class:
#!/usr/bin/env python3
"""
This module is a linked list implementation.
"""
class Node:
"""
Node class to be used in our linked list.
"""
def __init__(self, value):
self.value = value
self.next = None
class Linkedlist:
"""
Linked list implementation that supports functions including inserting
at head, inserting at tail, extracting elements, and displaying all
elements in the ist
"""
def __init__(self, head):
self.head = Node(head)
def insert(self, value):
"""
Insert new node to the tail of the linked list.
Time Complexity: O(n)
"""
current = self.head
while current.next is not None:
current = current.next
current.next = Node(value)
def insert2(self, value):
"""
Insert new node to the head of the linked list, making sure to update head.
Time Complexity: O(1)
"""
to_insert = Node(value)
to_insert.next = self.head
self.head = to_insert
def extract(self):
"""
Extract the last element in the linked list
"""
current = self.head
while current.next.next is not None:
current = current.next
tail = current.next
current.next = None
return tail
def display(self):
"""
Print all node values in the linked list
"""
current = self.head
while current is not None:
print(current.value)
current = current.next
# Test Program
head = Linkedlist(5)
# linked_insert(head, 1)
# linked_insert(head, 2)
# linked_insert(head, 3)
head.insert2(1)
head.insert2(2)
head.insert2(3)
head.display()

Walk through nodes in linked list python

I'm set to do a binary tree search like the one here. I have a problem to set the nodes correctly.
The problem:
When a new node should be created, the root node seems to be overwriten. First time
Bintree.put(newValue)
is called a new node is created at the Bintree.root. The second time, the root node seems to be overwriten in the functioncall Bintree.put(newValue).
Does these lines below change the root node when it is executed?
node = root
node = node.left # Left is a node below node
node = Node()
The lines below is the code for my program.
# Node for binary tree
class Node():
def __init__(self):
self.data = None
self.left = None
self.right = None
class Bintree:
def __init__(self):
self.root = None
def put(self, newvalue):
'''Sends the new value into the correct position in the Bintree
:param newvalue: The data that's sent to storage'''
self.root = push(self.root, newvalue)
def push(root, value):
# This function puts the value in the correct position in the bintree
# Not to be used by user.
node = root
while node is not None:
if node.data < value:
node = node.left
else:
node = node.right
node = Node()
node.value = value
return node
Yeah you're right I screwed it up a little bit.
class Node():
def init(self):
self.data = None
self.left = None
self.right = None
class Bintree:
def init(self):
self.root = None
def put(self, newvalue):
'''Sends the new value into the correct position in the Bintree
:param newvalue: The data that's sent to storage'''
if self.root is None:
self.root = Node()
self.root.data = newvalue
else:
self.push(self.root, newvalue)
def push(self, node, value):
# This function puts the value in the correct position in the bintree
# Not to be used by user.
if value < node.data:
if node.left is not None:
self.push(node.left,value)
else:
node.left = Node()
node.left.data = value
else:
if node.right is not None:
self.push(node.right,value)
else:
node.right = Node()
node.right.data = value
I did it from scratch with recursive. It's simpler.
Of course it didn't work because in your first attempt you always set root to none and in the second you only update root all the time (my bad)

How could I make this singly linked list into a doubly linked list?

I've created a linked list in Python, and it is singly linked. This works perfectly fine, but I want to implement it so it's doubly linked, but I'm having trouble figuring out how to do it.
# node class
class node:
def __init__(self):
self.data = None # contains the data
self.next = None # contains the reference to the next node
# linked list class
class linked_list:
def __init__(self):
self.cur_node = None
def add_node(self, data):
new_node = node() # create a new node
new_node.data = data
new_node.next = self.cur_node # link the new node to the 'previous' node.
self.cur_node = new_node # set the current node to the new one.
def list_print(self):
node = self.cur_node # cant point to ll!
while node:
print(node.data)
node = node.next
I know I need to add self.previous to the node class, and I think I need to add something to the linked list constructor and add_node function, but I'm not sure where to start.
I don't actually need to use this functionality in a program, I'm just trying to learn about how linked lists are implemented at a lower level.
It's not so much a coding problem as a conceptual problem. You need to figure out how you want your code to behave. Implementing the desired behavior is not (in this case) at all difficult.
Say we want these behaviors:
# construction
dlist = DoublyLinkedList()
# access to head and tail nodes
dlist.head # should return the head node
dlist.tail # should return the tail node
dlist.head.prev is None # should be True
dlist.tail.next is None # should be True
# adding nodes at both ends
dlist.add_head()
dlist.add_tail()
# iteration in both directions
for node in dlist:
# do something to the node
for node in reversed(dlist):
# do something to the node
When you have written out the desired behavior like this, you'll also have got some test code ready.
Now let's start by modifying the Node class (you should use CamelCase for class names):
class Node:
def __init__(self, data=None, prev=None, next=None):
self.data = data
self.prev = prev
self.next = next
def __repr__(self):
return '<{}, {}>'.format(self.data, self.next)
We add prev since that's obviously needed. But we also improve on your original version by having data and next as parameters, so you can have these values set when a node is created. And __repr__ is always nice to have, for debugging if not for anything else.
Now for the list itself. The key is, (a) instead of one cur_node, you need two handles on the list, which I've been calling head and tail, and (b) when adding nodes, the very first node is a special case where we have to make changes to both head and tail.
class DoublyLinkedList:
def __init__(self):
self.head = None
self.tail = None
def __repr__(self):
return '<DoublyLinkedList {}>'.format(self.head)
def add_head(self, data=None):
if self.head is None:
self.head = self.tail = Node(data) # the very fist node
else:
new_head = Node(data=data, next=self.head) # prev is None
self.head.prev = self.head = new_head
def add_tail(self, data=None):
if self.tail is None:
self.head = self.tail = Node(data) # the very first node
else:
new_tail = Node(data=data, prev=self.tail) # next is None
self.tail.next = self.tail = new_tail
# implements iteration from head to tail
def __iter__(self):
current = self.head
while current is not None:
yield current
current= current.next
# implements iteration from tail to head
def __reversed__(self):
current = self.tail
while current is not None:
yield current
current = current.prev
Let's test this
>>> dlist = DoublyLinkedList()
>>> print(dlist)
<DoublyLinkedList None>
>>> dlist.add_head(1)
>>> dlist.add_tail(2)
>>> dlist.add_tail(3)
>>> dlist.add_head(0)
>>> print(dlist) # __repr__ is such a nice thing to have
<DoublyLinkedList <0, <1, <2, <3, None>>>>>
>>> print(dlist.head)
<0, <1, <2, <3, None>>>>
>>> print(dlist.tail)
<3, None>
>>> print(dlist.head.prev is None, dlist.tail.next is None)
True, True
>>> print(dlist.tail.prev.next is dlist.tail)
True
>>> [node.data for node in dlist]
[0, 1, 2, 3]
>>> for node in reversed(dlist):
... print(node.data, node)
3 <3, None>
2 <2, <3, None>>
1 <1, <2, <3, None>>>
0 <0, <1, <2, <3, None>>>>
For a doubly linked list, you should have, each node should have a reference to the previous node. This means that you will need to modify your add and remove methods to also assign this reference.

Error when deleting a node in a Linked List <ListNode.ListNode object at 0x0000000267320>

I am making a linkedlist, and I had to add in some different functions such as max, min , count and index for my list. I now have to add a remove function which is this snippet of code.
def removeItem(self, position):
''' removeItem removes a selected, because python has a built in "garbage remover",
you don't have to physically delete the node, you only have to skip that node link and python will destroy it
by it self.'''
currentNode = self.head
previousNode = None
count = 0
while count != position:
#This is a quick check to make sure the next node isn't empty.
if currentNode.link is None:
print("Position Invalid")
return None
previousNode = currentNode
currentNode = currentNode.link
count += 1
#Node.Link should link to the next node in the sequence.
previousNode.link = currentNode.link
return currentNode
I am basically just trying to link over the next node in the sequence, so that the built-in garbage remover will remove that node from the sequence. However, I am getting the following error message, which I know has to do something with my instance.
C:\Python33\python.exe "C:/Users/koopt_000/Desktop/College/Sophomore Semester 2/Computer Science 231/Chapter4/Test.py"
900
1
1
2
<ListNode.ListNode object at 0x0000000002679320>
Process finished with exit code 0
Why is it printing out this weird ListNode.ListNode object at the end?
Here is my testing code:
from ListNode import ListNode
from LinkedList import LinkedList
node1 = ListNode(1)
node2 = ListNode(900)
node3 = ListNode(3)
node4 = ListNode(99)
node1.link = node2
node2.link = node3
node3.link = node4
linked_list = LinkedList((1, 900, 3, 99))
print(linked_list.__max__())
print(linked_list.__min__())
print(linked_list.getCount(900))
print(linked_list.getIndex(3))
print(linked_list.removeItem(3))
This is my code for my ListNode class:
# ListNode.py
class ListNode(object):
def __init__(self, item = None, link = None):
'''creates a ListNode with the specified data value and link
post: creates a ListNode with the specified data value and link'''
self.item = item
self.link = link
This is my code for my LinkedList class:
from ListNode import ListNode
class LinkedList(object):
#--------------------------------------------------------------
def __init__(self, seq=()):
""" Pre: Creates a Linked List
Post: Creates a list containing the items in the seq=()"""
if seq == ():
# If there is no items to be put into the list, then it creates an empty one.
self.head = None
else:
# Creates a node for the first item.
self.head = ListNode(seq[0], None)
# If there are remaining items, then they're added while keeping track of the last node.
last = self.head
for item in seq[1:]:
last.link = ListNode(item, None)
last = last.link
self.size = len(seq)
#-------------------------------------------------------------
def __len__(self):
'''Pre: Nothing.
Post: Returns the number of items in the list.'''
return self.size
#-------------------------------------------------------------
def __max__(self):
''' Goes through each node and compares what the max is for the linked list.
Post: Finds the max of the linked list and returns that value.'''
if self.head is None:
return None
max_value = self.head.item
node = self.head.link
while node is not None:
if node.item > max_value:
max_value = node.item
node = node.link
return max_value
#--------------------------------------------------------------
def __min__(self):
''' Goes through each node and compares what the min is for the linked list.
Post: Finds the min of the linked list and returns that value.'''
if self.head is None:
return None
min_value = self.head.item
node = self.head.link
while node is not None:
if node.item < min_value:
min_value = node.item
node = node.link
return min_value
#--------------------------------------------------------------
def getCount(self, yourData):
''' This function counts the amount of times a certain item is in the Linked List.'''
count = 0
node = self.head
for i in range(self.size):
data = node.item
if data is yourData:
count += 1
node = node.link
return count
#--------------------------------------------------------------
def getIndex(self, yourData):
''' getIndex finds the index of the selected item and returns that value. '''
node = self.head
if node is None:
return None
for i in range(self.size):
data = node.item
if data == yourData:
return i
node = node.link
raise IndexError
#--------------------------------------------------------------
def removeItem(self, position):
''' removeItem removes a selected, because python has a built in "garbage remover",
you don't have to physically delete the node, you only have to skip that node link and python will destroy it
by it self.'''
currentNode = self.head
previousNode = None
count = 0
while count != position:
#This is a quick check to make sure the next node isn't empty.
if currentNode.link == None:
print("Position Invalid")
return None
previousNode = currentNode
currentNode = currentNode.link
count += 1
#Node.Link should link to the next node in the sequence.
previousNode.link = currentNode.link
return currentNode
#--------------------------------------------------------------
If anyone could help me out to find out why my removeItem function isn't working that would be helpful!
On a side note, I'm also trying to make a doubly linked list of this list, I know I need to add a prev_node function into my ListNode function, but what else do I need to add? Thanks again!
If your method is returning a <LinkNode object at 0xmemoryaddr> string then it is working fine. You are printing the removed node, and Python is using the default repr() representation for that instance.
If you wanted to make it more readable, you could give the ListNode a object.__repr__ method:
def __repr__(self):
next = 'None' if not self.link else '...' # just to indicate
return 'ListNode({!r}, {})'.format(self.item, next)
This then will print ListNode(99, None) instead of the <ListNode object at 0xmemoryaddr> string Python defaulted to:
>>> ll = LinkedList((1, 900, 3, 99))
>>> ll.head
ListNode(1, ...)
>>> ll.head.link
ListNode(900, ...)
>>> ll.head.link.link
ListNode(3, ...)
>>> ll.head.link.link.link
ListNode(99, None)
One thing you do have to take into account: you need to adjust the length of the list too; on successful removal, subtract 1 from self.size.

problems with BST in python

I have my BST class build like this :
class BST:
"""A Binary Search Tree."""
def __init__(self: 'BST', container: list =None) -> None:
"""
Initialize this BST by inserting the items from container (default [])
one by one, in the order given.
"""
# Initialize empty tree.
self.root = None
# Insert every item from container.
if container:
for item in container:
self.insert(item)
def __str__(self: 'BST'):
"""
Return a "sideways" representation of the items in this BST, with
right subtrees above nodes above left subtrees and each item preceded
by a number of TAB characters equal to its depth.
"""
# Tricky to do iteratively so we cheat,
# You could take up the challenge...
return BST._str("", self.root)
def insert(self: 'BST', item: object) -> None:
"""
Insert item into this BST.
"""
# Find the point of insertion.
parent, current = None, self.root
while current:
if item < current.item:
parent, current = current, current.left
else: # item > current.item
parent, current = current, current.right
# Create a new node and link it in appropriately.
new_node = _BSTNode(item)
if parent:
if item < parent.item:
parent.left = new_node
else: # item > parent.item
parent.right = new_node
else:
self.root = new_node
My problem is how to implement a contains function without using recursion. I have tried a couple loop methods but it always ended up with indent error.
The contains method will look very similar to your insert method, but even simpler because all you have to do is check if the item exists. So, traverse the BST as usual and return False if you reach the end, or True if you find the element:
def contains(self, item):
current = self.root
while current:
if item == current.item:
return True
if item < current.item:
current = current.left
else:
current = current.right
return False

Categories

Resources