Insert specific Node in desired Position Linked List on Python - python

i have sort of problem imagining or solving this, i have this node and list
class node:
def __init__(self, info):
self.info = info
self.next = None
class list:
def __init__(self):
self.__first = None
self.__last = None
and i have to create a function, called indexL(self, info, position), that put the exact node in the desired position, here is what i have for now
(i have created already a method called self.length() to give the size of the list)
def indexL(self, info, position):
longit = self.length()
n = node(info)
p = self.__first
if position == 0:
self.__first = n
else:
if position > 0 and position < longit:
if position == longit-1:
self.__last = n
else:
and now i'm stuck there, by the way i can't add any method to the node or use other method of the list, if someone want to help or any recommendation, i would be really grateful
EDIT: in my last comment is more clear if you are confused :P

You don't really need a length() method... all you need to do is iterate over the list until you reach position and update the info:
def indexL(self, info, position):
if not self.__first:
raise Error("Empty List")
item = self.__first
i = 0
while item:
if i == position:
break
item = item.next
i += 1
else:
raise Error("Position is outside of the size of the list")
item.info = info # Replace info

Related

Why creating an instance of a class within a class method changes the 'self' argument?

I'm writing a linked list in Python and I've come across an issue which is really troublesome and terrible for debugging and I feel like I'm missing something about Python. I'm supposed to create a singly linked list with some basic functionalities. One of them is the take() function, which is meant to create a new list of n first elements of the original list.
However, creating a new instance of the LinkedList class seems to change the .self parameter and the variable node is modified, as the attribute .next is turned to None. In result, when creating a list and then trying to make a new one out of the n elements of it, the program runs indefinitely, but no matter which part I look at, I cannot find the loop or the reason behind it.
class LinkedList:
def __init__(self, head=None):
self.head = head
def is_empty(self):
if self.head == None:
return True
else:
return False
def add_last(self, node):
if self.is_empty():
self.head = node
return
nextEl = self.head
while True:
if nextEl.next is None:
nextEl.next = node
return
nextEl = nextEl.next
def take(self, n):
node = self.head
newHead = self.head
newHead.next = None
newList = LinkedList(newHead)
count = 0
while count < n:
newList.add_last(node.next)
node = node.next
count += 1
return newList
class Node:
def __init__(self, data, next=None):
self.data = data
self.next = next
Thank you for all your help.
In the take() function the line
newHead.next = None
modifies a node of the linked list, breaking this list. You can fix this as follows:
def take(self, n):
node = self.head
newHead = Node(self.head.data)
newList = LinkedList(newHead)
count = 0
while count < n:
newList.add_last(node.next)
node = node.next
count += 1
return newList
This, however, still will not work correctly since there is a problem with the add_last() function too. This function, I think, is supposed to add a node as the last element of a linked list, but since you do not modify the next attribute of the node, you actually append a whole linked list starting with that node. This can be fixed in the following way:
def add_last(self, node):
if self.is_empty():
self.head = node
return
nextEl = self.head
while True:
if nextEl.next is None:
nextEl.next = Node(node.data)
return
nextEl = nextEl.next
There are more issues. For example, take(sefl, n) will actually create a list of n+1 elements and will throw an exception if it is applied to a linked list that does not have that many elements.

Printing a binary tree in the specific format

def str_tree(atree,indent_char ='.',indent_delta=2):
def str_tree_1(indent,atree):
if atree == None:
return ''
else:
answer = ''
answer += str_tree_1(indent+indent_delta,atree.right)
answer += indent*indent_char+str(atree.value)+'\n'
answer += str_tree_1(indent+indent_delta,atree.left)
return answer
return str_tree_1(0,atree)
def build_balanced_bst(l):
d = []
if len(l) == 0:
return None
else:
mid = (len(l)-1)//2
if mid >= 1:
d.append(build_balanced_bst(l[:mid]))
d.append(build_balanced_bst(l[mid:]))
else:
return d
The build_balanced_bst(l) takes in a list of unique values that are sorted in increasing order. It returns a reference to the root of a well-balanced binary search tree. For example, calling build_ballanced_bst( list(irange(1,10)) returns a binary search tree of height 3 that would print as:
......10
....9
..8
......7
....6
5
......4
....3
..2
....1
The str_tree function prints what the build_balanced_bst function returns
I am working on the build_balanced_bst(l) function to make it apply to the str_tree function. I used the middle value in the list as the root’s value.
But when I call the function as the way below:
l = list(irange(1,10))
t = build_balanced_bst(l)
print('Tree is\n',str_tree(t),sep='')
it doesn't print anything. Can someone help me to fix my build_balanced_bst(l) function?
Keeping the str_tree method as it is, here's the remaining code.
class Node:
"""Represents a single node in the tree"""
def __init__(self, value, left=None, right=None):
self.value = value
self.left = left
self.right = right
def build_balanced_bst(lt):
"""
Find the middle element in the sorted list
and make it root.
Do same for left half and right half recursively.
"""
if len(lt) == 1:
return Node(lt[0])
if len(lt) == 0:
return None
mid = (len(lt)-1)//2
left = build_balanced_bst(lt[:mid])
right = build_balanced_bst(lt[mid+1:])
root = Node(lt[mid], left, right)
return root
ordered_list = list(range(1,11))
bst=build_balanced_bst(ordered_list)
bst_repr = str_tree(bst)
print(bst_repr)
The output comes out as follows:
......10
....9
..8
......7
....6
5
......4
....3
..2
....1

Making a linked list without built in functions

I have a project to make a linked list in python.
My program needs to add to the list, remove from it and get elements. Sounds easy right? Wrong! We aren't allowed to use normal lists or built-in functions (other than the basic print, str...)
I have one problem with my code, I have to initialise a blank list then add the elements, 1 by 1. Everything else works fine.
My questions:
Is this how a normal python list works?
Is it possible to add items to a linked list with a loop? (without another list)
Here's the code:
class Node: # the node class
def __init__(self, cargo = None, next = None): # __init__ stands for initialize
self.cargo = cargo # e.g. steve
self.next = next # represents the next node or None if its the last
def __str__(self): # __str__ is called when the node is printed or converted to a string
return str(self.cargo) # return a string
class List: # the main list class
def __init__(self): # default is to initialize an empty list
self.first_node = None
self.last_node = None
self.length = 0
def get(self, position, length): # function for efficiency
if position == "end":
position = length - 1 # last
if position > length - 1: # can't go beyond last
raise ValueError("List index out of range")
prv_node = self.first_node
node = self.first_node # start at the first
num = 0
while num < position: # go up to position
prv_node = node # remember the previous node
node = node.next # next node!
num = num + 1
return prv_node, node, position
def add_node(self, cargo, position = "end"): # adds a node
prv_node, node, position = self.get(position, self.length + 1) # +1 because the length is being increased
print("adding node at "+str(position)+": "+str(cargo))
if position == 0: # first
self.first_node = Node(cargo, next = self.first_node) # the first node is the new node
if self.length == 0: # first node to be added
self.last_node = self.first_node # there is only one node
elif position == self.length: # last
self.last_node.next = Node(cargo, next = None) # last_node.next was None, it is now a new node
self.last_node = self.last_node.next # last node is now the new last node
else: # normal
prv_node.next = Node(cargo, next = node) # stick it in between
self.length = self.length + 1 # length is now + 1
def get_node(self, position): # gets a node
...
def remove_node(self, position): # removes a node
...
def __str__(self): # when the list is printed
node = self.first_node # start from the first
string = ""
while node != self.last_node: # go to the end
string = string + str(node) + ", " # print each node
node = node.next
string = string + str(self.last_node) # last node hasn't been added yet
return string
# initialize
mylist = List()
mylist.add_node("steve")
mylist.add_node("james")
mylist.add_node("tom")
mylist.add_node("david")
mylist.add_node("hoe-yin")
mylist.add_node("daniel")
print(mylist)
[EDIT] second question re-phrased
Here's how Python lists are implemented in CPython: http://www.laurentluce.com/posts/python-list-implementation/
If you have your values in some other iterable, then yes:
for item in list_of_items:
mylist.add_node(item)

Python Tree Recursion

I'm having some difficulties getting python to recursively print out the results from a search tree. I'm native to C++ and I'm completely familiar with using pointers to traverse such structures, but Python does more work than I'm used to. . .
In any case, I'm hoping someone will be able to help me. I'm working on implementing a heuristic to solve the Traveling Salesman Problem; however, I can't begin work on the actual heuristic until I can iterate through my tree. In any case, here's the code for the tree.
class Tree:
branches = dict()
def __init__(self, cities, n=0):
if len(cities) == 1:
nc = list(cities) # create a working list
# grab the nth element of the list, default to head
# Stash that as the node value
self.node = nc[n]
print "Complete!"
elif len(cities) == 0:
print "Doubly Complete!"
else:
nc = list(cities) # create a working list
# grab the nth element of the list, default to head
# Stash that as the node value
self.node = nc[n]
print self.node
del nc[n] # Pop off the nth value from the list
print "deleted city! See?"
print nc
c = 0 # create a counter
for a in nc: # loop through the remaining cities
self.branches[a] = Tree(nc, c) # generate a new tree
c += 1 # increase the counter
def __repr__(self, tier=1):
ret = ("\t" * tier)
ret += self.node
ret += "\n"
for a in self.branches:
ret += self.branches[a].__repr__(tier+1)
return ret
__str__ = __repr__
Here is where the tree is instantiated and printed:
l = ['A','B','C','D']
mine = Tree(l)
print mine
The result of printing the Tree is a RuntimeError: maximum recursion depth exceeded. I'm at my wits end when it comes to what to do next. I would certainly appreciate any help!
Oh! Believe me when I say, if I could use another method than recursion, I would. This particular heuristic requires it, though.
Thanks for any and all help!
This code seems to work. All I did was move the self.branches to inside the __init__. I did so following best practices while debugging. The problem was they were class members not instance members. Having a mutable datatype like dict be a class member just asks for problems.
class Tree:
def __init__(self, cities, n=0):
self.branches = dict()
if len(cities) == 1:
nc = list(cities) # create a working list
# grab the nth element of the list, default to head
# Stash that as the node value
self.node = nc[n]
print "Complete!"
elif len(cities) == 0:
print "Doubly Complete!"
else:
nc = list(cities) # create a working list
# grab the nth element of the list, default to head
# Stash that as the node value
self.node = nc[n]
print self.node
del nc[n] # Pop off the nth value from the list
print "deleted city! See?"
print nc
c = 0 # create a counter
for a in nc: # loop through the remaining cities
self.branches[a] = Tree(nc, c) # generate a new tree
c += 1 # increase the counter
def __repr__(self, tier=1):
ret = ("\t" * tier)
ret += self.node
ret += "\n"
for a in self.branches:
ret += self.branches[a].__repr__(tier+1)
return ret
__str__ = __repr__
t = Tree(["SLC", "Ogden"], 1)
print t

counting in a Linked List

I just want to make sure that my getCount function will work, because I have no idea how to test this to make sure it works could someone tell me how I would either test this function or what I did wrong? It is supposed to count the number of times a certain object has occurred in my linked list.
Here is the ListNode import
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
.
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 getCount(self, position):
''' This function counts the amount of times a certain item is in the Linked List.'''
count = 0
if self.head == position:
count = 1
if self.head.link is None:
return count
return count + getCount(self.head.link, position)
def __copy__(self):
''' Post: Returns a new Linked List object that is a shallow copy of self.'''
a = LinkedList()
node = self.head
while node is not None:
a.append(node.item)
node = node.link
return a
#-----------------------------------------------------------------
def __iter__(self):
return LinkedListIterator(self.head)
#---------------------------------------------------------------------
class LinkedListIterator(object):
#-----------------------------------------------------------------
def __init__(self, head):
self.currnode = head
#-----------------------------------------------------------------
def next(self):
if self.currnode is None:
raise StopIteration
else:
item = self.currnode.item
self.currnode = self.currnode.link
return item
#-----------------------------------------------------------------
Hopefully I posted enough of my code for you guys to see the problem. I just want to find a way to test to see if my my count works and if it doesn't I need to know how to make it work.
Your LinkedList.getCount() method has several issues:
It tries to count self.head if it is equal to position, but self.head is a node, an instance of ListNode. It'll never be equal to a value you want to count.
It tries to use the method recursively, but there is no global getCount() function.
There is no need to use recursion here; just keep grabbing the next node from the 'current' until you run out, and compare against node.item each time:
def getCount(self, value):
count = 0
current = self.head
while current is not None:
if current.item == value:
count += 1
current = current.link
return count

Categories

Resources