Moving a node to the end of a chain of nodes - python

I have a function where I have to move an existing code for example
def print_chain_and_ids(chain):
current = chain
while current != None:
print(id(current), current.get_data())
current = current.get_next()
a = Node('first')
b = Node('middle')
c = Node('last')
a.set_next(b)
b.set_next(c)
print_chain_and_ids(a)
move_node_to_end(a, 'middle')
print_chain_and_ids(a)
so now the chain goes:
a ----> b ----> c
with the node c at the end of the chain.
If I wanted to move the node b to the end of the chain so it goes:
a ----> c ----> b
so that it doesn't change the value of the last node but just moves it around. I have a node class ready:
class Node:
def __init__(self, init_data):
self.data = init_data
self.next = None
def get_data(self):
return self.data
def get_next(self):
return self.next
def set_data(self, new_data):
self.data = new_data
def set_next(self, new_next):
self.next = new_next
def __str__(self):
return str(self.data)
I wanted to know how I would go about doing this.
I want to make to make a function which takes two inputs, the first node of the chain, and also the value which moves to the last position of the chain. So:
def node_to_end(first_node, value_to_move):
.....
This is where I have to modify the position of the nodes. So that value to move goes to the last position.
a = Node('blue')
b = Node('red')
c = Node('green')
a.set_next(b)
b.set_next(c)
which would result in blue red green
node_to_end(a, 'red')
would create a chain of
blue green red
Thank you for any help.

Your chain-of-nodes is very similar to what is called a singly-linked-list. With those, nodes are typically removed by keeping track of the previous node while traversing along the list, that way when the target node is found, you'll know which one (if any) came before it. Having that piece of information allows the list to be easily modified.
Here's how to apply that to your code. I also added a little utility to print the contents of chains to make it clear what is in them.
class Node:
def __init__(self, init_data):
self.data = init_data
self.next = None
def get_data(self):
return self.data
def get_next(self):
return self.next
def set_data(self, new_data):
self.data = new_data
def set_next(self, new_next):
self.next = new_next
def __str__(self):
return str(self.data)
def move_to_end(start, target):
"""Move target node from the chain beginning with start to end."""
previous = None
current = start
while current:
if current.get_next() is target:
previous = current
break
current = current.get_next()
if previous: # target found in chain?
previous.set_next(target.get_next()) # remove it
# and move it to the end
current = target
while current:
if not current.get_next(): # last node in chain?
target.set_next(None)
current.set_next(target)
break
current = current.get_next()
def print_node_chain(start):
"""Utility to print out a node chain starting from given node."""
values = []
current = start
while current:
values.append(str(current))
current = current.get_next()
print(' ----> '.join(values) + ' ----> None')
a = Node('blue')
b = Node('red')
c = Node('green')
a.set_next(b)
b.set_next(c)
print_node_chain(a)
move_to_end(a, b)
print_node_chain(a)
Output:
blue ----> red ----> green ----> None
blue ----> green ----> red ----> None

Well this will require some computation. Let's assume the generic case:
ei-1 -> ei -> ei+1 -> ... -> en
Now we want to move ei to the last position:
ei-1 -> ei+1 -> ... -> en -> ei
So the question is: what should change? Based on the generic case, there are three pointers that must change:
ei-1 now points to ei+1;
ei now points to nothing (None); and
en now points to ei.
Now since the linked list is not doubly linked: a node has no reference to the previous node, the only thing we can do to get the previous element, is iterate from the root until we find the element:
def get_prev_element(root,node):
while root.get_next() is not node:
root = root.get_next()
Once we have the previous element, we can let it link to the next element:
previous.set_next(node.get_next())
But now we still have to find out what the last element is. And guess what, we do this again, by iterating, we can however start from our own node:
def get_last(node):
while node.get_next() is not None:
node = node.get_next()
return node
Now we set the next of the last node, to our own node:
last.set_next(node)
and finally we set our own next to None:
node.set_next(None)
Now grouping this all together we can define a method on the node:
class Node:
# ...
def get_previous(self,root):
previous = root
while previous.get_next() is not self:
previous = previous.get_next()
return previous
def get_last(self):
last = self
while last.get_next() is not None:
last = last.get_next()
return last
def move_last(self,root):
previous = self.get_previous(root)
previous.set_next(self.get_next())
last = self.get_last()
last.set_next(self)
self.set_next(None)
Note that since the linked list is not double linked, you will have to give it the root element.
Intermezzo: given you have references to a, b and c. Of course there is no reason to calculate the previous and last: you know that a is the previous and that c is the last. So in that case, the code is simply:
a.set_next(c)
c.set_next(b)
b.set_next(None)
This code does not work if the root element is the node itself. I leave it as an exercise to modify the code to let it work properly. It is not very hard.

Related

LinkedList by Python

class Node:
def __init__(self, item):
self.data = item
self.next = None
class LinkedList:
def __init__(self):
self.nodeCount = 0
self.head = None #Headnode(First node of LinkedList)
self.tail = None #Tailnode(Last node of LinkedList)
def getAt(self, pos): #pos = index number
if pos<=0 or pos>self.nodeCount:
return None
i = 1
curr = self.head
while i < pos:
curr = curr.next
i += 1
return curr
This is the code of LinkedList made by Python from DS class.
I have 2 questions from this code
When I learned C and C++, to make "Node class", I have to make Data field and Link(Pointer) field. And I store next Node's address(pointer) at Node's Link field. So I can move to next node. But at Python code, I don't know how node class's member's 'self.next' points next node. Which one is saved at the next field?
I do not inherit Node class at Linked List class. But how can I use Node class's member function 'self.next' at LinkedList class when I make getAt function?
Here is a simple implementation of Node and LinkedList classes in Python. The Node class has only 2 attributes: value and next. The LinkedList class only has one attribute: start. When an empty LinkedList is created, it has no start. All the interesting action occurs in the add_item_to_end() method. When the first item is added to a linked list, a node is created and assigned to start. When the second item is added, another node is created and assigned to the previously unoccupied next of the start node. When the third, fourth, ... nodes are added, the add method begins at the start of LinkedList and goes through all consecutively linked nodes until it reaches a node that has no next, then it set the next of that node to the node being added.
class Node:
def __init__(self, value = None, next = None):
self.value = value
self.next = next
class LinkedList:
def __init__(self, start = None):
self.start = start
def add_item_to_end(self, item):
my_node = Node(value=item)
if self.start == None:
self.start = my_node
else:
p = self.start
while p.next:
p = p.next
p.next = my_node
#The following method is just to visualize the linked list.
#It is not necessary for the functioning of the list:
def toList(self):
result = []
if self.start:
p = self.start
while p is not None:
result.append(p.value)
p = p.next
return result
#example runs
my_ll = LinkedList()
print(my_ll.toList())
#output: []
my_ll.add_item_to_end("bread")
print(my_ll.toList())
#output: ['bread']
my_ll.add_item_to_end("milk")
print(my_ll.toList())
#output: ['bread', 'milk']

Python - Removing a node from a linked-list at beginning, in between and at end

I learned about linked-lists today. I learned how to insert and remove nodes from them. In the following code, it teaches me how to insert nodes with three distinct functions: at beginning (the head node), in between and at the end. However, they teach me how to remove the node in and single function. I don't find the code in the remove function to be very clear. Can anyone help make an easier to understand code under the remove function? Is there a way to make it into three functions just like the inserting ones? I'm open to any suggestion or explanation. Thanks in advance.
Here's my code:
class Node:
def __init__(self, data=None):
self.data = data
self.nextnode = None
class LinkedList:
def __init__(self):
self.headnode = None
def printlist(self):
node = self.headnode
while node is not None:
print (node.data)
node = node.nextnode
def atbegining(self,new_node):
new_node.nextnode = self.headnode
self.headnode = new_node
# Function to add newnode
def AtEnd(self, newnode):
if self.headnode is None:
self.headnode = newnode
return
node = self.headnode
while(node.nextnode):
node = node.nextnode
node.nextnode=newnode
# Function to add node
def Inbetween(self,preNode,newNode):
if preNode is None:
print("The mentioned node is absent")
return
newNode.nextnode = preNode.nextnode
preNode.nextnode = newNode
# Function to remove node
def RemoveNode(self, RemoveVal):
node = self.headnode
if (node is not None):
if (node.data == RemoveVal):
self.headnode = node.nextnode
node = None
return
while (node is not None):
if node.data == RemoveVal:
break
prevnode = node
node = node.nextnode
if (node == None):
return
prevnode.nextnode = node.nextnode
node = None
list1 = LinkedList()
list1.headnode = Node("Mon")
n2 = Node("Tue")
n3 = Node("Wed")
# Link first Node to second node
list1.headnode.nextnode = n2
# Link second Node to third node
n2.nextnode = n3
n4 = Node("Sun")
n5 = Node("Tur")
n6 = Node("Newdate")
list1.atbegining(n4)
list1.AtEnd(n5)
list1.Inbetween(list1.headnode,n6)
list1.RemoveNode("Newdate")
list1.printlist()
RemoveNode is complicated by the fact that there are two structurally distinct kinds of LinkedLists: one whose head is None, and one whose head is not None. You can fix this by making sure every LinkedList contains at least one node. This is typically referred to as a dummy node, and you can use this node to store metadata (such as the length of the list).
The Node class itself does not change.
class Node:
def __init__(self, data=None):
self.data = data
self.nextnode = None
The LinkedList, however, simplifies by creating a dummy node. This provides
the guarantee that every node that stores real data is point to by another node.
class LinkedList:
def __init__(self):
self.headnode = Node(0)
def insert(self, preNode, newNode):
newNode.nextnode = preNode.nextnode
preNode.nextnode = newNode
self.headnode.data += 1
def append(self, newNode):
curr = self.headnode
while curr.nextNode is not None:
curr = curr.nextNode
self.insert(curr, newNode)
def prepend(self, newNode):
self.insert(self.headnode, newNode)
def _find_before(self, val):
pre = self.headnode
while pre.nextnode is not None:
curr = pre.nextnode
if curr.data == val:
return pre
pre = curr
def remove(self, RemoveVal):
pre = self._find_before(RemoveVal)
if pre is None:
return
pre.nextnode = pre.nextnode.nextnode
self.headnode.data -= 1
This simplifies all three insertions. The general case can always apply, since there is always a node that comes before the node you insert. append and prepend are simple wrappers that find the appropriate node to pass to insert.
Likewise, remove simply finds the node before the given value, and if the search succeeds, handles updating the prior node's nextnode attribute.
insert and remove also update the size of the list stored in the dummy node.
A find method becomes a simple wrapper around _find_before; if you find a node before the value you are looking for, just return the node that follows it.
I think that an alternative design will make the code much clearer. Consider for example the following:
class Node:
def __init__(self, data=None):
self.data = data
self.nextnode = None
def printlist(self):
print(self.data)
if self.nextnode is not None:
self.nextnode.printlist()
def push(self, node):
node.nextnode = self
return node
def insertafter(self, node):
node.nextnode = self.nextnode
self.nextnode = node
return self
def append(self, node):
lastnode = self
while lastnode.nextnode is not None:
lastnode = lastnode.nextnode
lastnode.nextnode = node
return self
def remove(self, value):
prev = None
walk = self
while walk is not None:
if walk.data == value:
if prev is None:
return walk.nextnode
else:
prev.nextnode = walk.nextnode
return self
else:
prev = walk
walk = walk.nextnode
return self
list1 = Node("Mon")
n2 = Node("Tue")
n3 = Node("Wed")
# Link first Node to second node
list1 = list1.insertafter(n2)
# Link second Node to third node
n2 = n2.insertafter(n3)
n4 = Node("Sun")
n5 = Node("Tur")
n6 = Node("Newdate")
list1 = list1.push(n4)
list1 = list1.append(n5)
list1 = list1.insertafter(n6)
list1 = list1.remove("Newdate")
list1.printlist()
The main idea is that a Node is the linked list. As long as you have the head of the list kept in a variable, you can have access to the entire list, without the need for a separate data structure.

How do I insert data into the middle of a singlelinkedlist in python?

Node Class and SingleLinkedList Class code:
class Node():
'''represents a node as a building block of a single linked list'''
def __init__(self, element, next_node=None):
'''(Node, obj, Node) -> NoneType
construct a node as building block of a single linked list'''
self._element = element
self._next = next_node
def set_next(self, next_node):
'''(Node, Node) -> NoneType
set node to point to next_node'''
self._next = next_node
def set_element(self, element):
'''(Node, obj) ->NoneType
set the _element to a new value'''
self._element = element
def get_next(self):
'''(Node) -> Node
returns the reference to next node'''
return self._next
def get_element(self):
'''(Node) -> obj
returns the element of this node'''
return self._element
def __str__(self):
'''(Node) -> str
returns the element of this node and the reference to next node'''
return "(" + str(self._element) + ", " + str(hex(id(self._next))) + ")"
class SingleLinkedList():
''' represents a single linked list'''
def __init__(self):
'''(SingleLinkedList) ->NoneType
initializes the references of an empty SLL'''
self._size = 0
self._head = None
self._tail = None
self._value = None
self._next = None
def set_head(self, new_head):
'''(SingleLinkedList) -> None
updates the head'''
self._head = new_head
def set_tail(self, new_tail):
'''(SingleLinkedList) -> None
updates the tail'''
self._tail = new_tail
def get_head(self):
'''(SingleLinkedList) -> Node
Return the pointer to the head'''
return self._head
def get_tail(self):
'''(SingleLinkedList) -> Node
Return the pointer to the tail'''
return self._tail
def is_empty(self):
'''(SingleLinkedList) -> bool
returns true if no item is in this SLL'''
return self._size == 0
def size(self):
'''(SingleLinkedList) -> int
returns the number of items in this SLL'''
return self._size
def add_first(self, element):
'''(SingleLinkedList, obj) -> NoneType
adds a node to the first of the SLL'''
# create a node that point to the head
node = Node(element, self._head)
# let head point to the node
self._head = node
# if this node is the first node in this SLL, tail should point to this node too
if (self._size == 0):
self._tail = node
# increment the size
self._size += 1
def add_last(self, element):
'''(SingleLinkedList, obj) -> NoneType
adds a node to the end of this SLL'''
# create a node with the given element that points to None
node = Node(element, None)
# let the _next part of the tail to point to newly created node
self._tail.set_next(node)
#let tail to point to the added node
self._tail = node
# if this node is the first node in this SLL, let head to point to this node too
if (self._size == 0):
self._head = node
# increment the size
self._size += 1
def remove_first(self):
'''(SingleLinkedList, obj) -> obj
remvoe the node from the head of this SLL and returns the element stored in this node'''
# sset element to None in case SLL was empty
element = None
# if SLL is not empty
if (self._head is not None):
# get the first node
node = self._head
# let head point to the second node
self._head = self._head.get_next()
# decrement the size
self._size -= 1
#set the _next of previous head to point to None (for garbage collection purpose)
node.set_next(None)
# get the element stored in the node
element = node.get_element()
#return the element of the removed node
return element
def __str__(self):
'''(SingleLinkedList) -> str
returns the items in the SLL in a string form
'''
# define a node, which points to the head
cur = self._head
# define an empty string to be used as a container for the items in the SLL
result = ""
# loop over the SLL until you get to the end of the SLL
while (cur is not None):
# get the element that of the current node and attach it to the final result
result = result + str(cur.get_element()) + ", "
# proceed to next node
cur = cur.get_next()
#enclose the result in a parantheses
result = "(" + result[:-2] + ")"
#return the result
return result
As you can see, there are already functions to add at the head and add at the tail, but I dont know how to add in the middle of the list. I need to make a function that takes new data, and adds a node with the data in the middle of the singlelinkedlist. Would someone be able to show me code or how to modify one of these functions or add a new one? Appreciate the help!
You have to start from the first elements, then iterate through the list until you reach the position you want to insert. Let's say you need to add a node node_to_insert to position pos:
current_node = self.get_head()
for i in range(pos): # iterate pos time:
current_node = current_node.get_next() # Jump to next node
# Now curr node is `pos`-th node. We insert `node_to_insert` here.
# Suppose u already have it named `node_to_insert`.
# We need to store the next node (of current node),
# so we can link the inserted node to it
next_current_node = current_node.get_next()
current_node.set_next(node_to_insert)
node_to_insert.set_next(next_current_node)
That's all. Hope this help. I didn't test the code, but I hope u get my idea.
This should work:
class SingleLinkedList():
...
def add_after(self, n, element):
"""add element after the n-th node, counting from 1 (if n=0, add before the first node)"""
# check if we should add at the start...
if (n<=0):
self.add_first(element)
# ... or the end
elif (n>=self.size()):
self.add_last(element)
# otherwise, add after node n
else:
# start at the first node
node = self.get_head()
# loop over nodes until we reach node n
for i in range(n - 1):
node = node.get_next()
# make a new node from our element
new_node = Node(element,node.get_next())
# insert it after node n
node.set_next(new_node)
Testing:
# test
q = SingleLinkedList()
q.add_first('A')
q.add_last('B')
q.add_last('C')
q.add_last('D')
q.add_last('E')
q.add_after(2, 'X')
print(q) # (A, B, X, C, D, E)

Python - Recursively calling __str__() only returns one item

This is my code (pretty simple)
class Node:
def __init__(self, data, next):
self.data = data
self.next = next
def __str__(self):
node = self
if node.next:
node = node.next
return node.__str__()
return str(self.data)
Now, when I create two Nodes, like so:
a = Node(1,1)
b = Node(2,a)
print(b)
it returns
1
My question is, when I do print(b), shouldn't it print
2
1
? Because first, it will check if node.next exists (in this case, it does. node.next is a). It will then do
node = node.next
return node.__str__() # a.__str__() which is equal to 1
return str(self.data) # this correctly returns 2
How come it doesn't return
2
1
and returns only
1
instead?
Your code does not concatenate values. It seems to just recurse until it hits the end, then return (only) this value. A...
return node.__str__() + str(self.data)
...might be more along the lines of what you wanted.

Implementing Doubly Linked List in Python

I was trying to implement a doubly linked list with the following functions:
_insertItemAfterNode(self,index)
_nodeBeforeIndex(self, index)
insertItemAtTheFront(self,item)
insertItemAtTheEnd(self,item)
insertItemAtIndex(self, index, item)
The last three functions should use the first two private methods.
This is what I have so far but I can't seem to work it. Any help is appreciated!!!
# DoublyLinkedLists
class Node(object):
def __init__(self, prev = None, data=None, next = None):
self._prev = prev
self._data = data
self._next = next
def __str__(self):
return str(self._data)
def __repr__(self):
return "Node(%s,%s,%s)" % (repr(self._prev), repr(self._data), repr (self._next))
def __eq__(self, other):
if other == None:
return False
else:
return self._prev == other._prev and self._data == other._data and self._next == other._next`enter code here`
class DoublyLinkedList(object):
def __init__(self):
self._first = Node(None, None, None)
self._length = 0
self._last = Node(None, None, None)
def __len__(self):
return self._length
def _insertItemAfterNode(self,item,aNode):
newNode = Node(aNode._prev, item, aNode._next)
aNode._next= newNode._prev
aNode._prev=newNode._next
self._length += 1
def _nodeBeforeIndex(self, index):
if 0 <= index <= self._length:
aNode = self._first
for i in range(index):
aNode = aNode._next
return aNode
else:
raise IndexError
def _nodeAfterIndex(self, index):
if 0<= index <= self.length:
aNode = self._last
for i in range(index):
aNode = aNode._prev
return aNode
else:
raise IndexError
def __getitem__(self, index):
return self._nodeBeforeIndex(index)._next._data
def insertAtEnd(self, item):
self._nodeAfterIndex(item)
def __iter__(self):
return DoublyLinkedListIterator(self)
def __setitem__(self, index, item):
self._nodeBeforeIndex(index)._next._data = item
def insertItemAtTheFront(self, item):
self._insertItemAfterNode(item, self._nodeBeforeIndex(0))
def insertItemAtTheEnd(self, item):
self._insertItemAfterNode(item, self._nodeBeforeIndex(self._length))
def insertItemAtIndex(self, index, item):
'''Valid range 0 <= index <= length.'''
self._insertItemAfterNode(item, self._nodeBeforeIndex(index))
def __iter__(self):
return DoublyLinkedListIterator(self)
def __repr__(self):
#used by print in abscence of __str__ .
plist = []
for item in self:
plist.append(item)
return "DoublyLinkedList(%s)" % str(plist)
class DoublyLinkedListIterator(object):
def __init__(self, aList):
self._list = aList
self._currentIndex = -1
self._currentNode = self._list._first
def __iter__(self):
return self
def __next__(self):
if self._currentIndex == self._list._length - 1:
raise StopIteration
else:
self._currentIndex += 1
self._currentNode = self._currentNode._next
return self._currentNode._data
def main():
x = DoublyLinkedList()
x.insertItemAtTheEnd(45)
print(x)
main()
I see two immediate issues with your code. There may be more issues that I haven't noticed, but these will probably prevent you from seeing any others until they are fixed.
The first issue is very simple. You have two sentinel nodes, _first and _last in your DoublyLinkedList class. However, they're not linked to each other, so when more nodes are added later, they won't be connected to both sentinels like they should be.
You can fix this by changing the __init__ method:
def __init__(self):
self._first = Node(None, None, None)
self._length = 0
self._last = Node(self._first, None, None) # pass first node as an arg here
self._first._next = self._last # make a link back too
The second issue is how you're adding nodes. There are a couple of places where you're assigning values from the _prev or _next attributes of a node, rather than referring to the node itself.
Lets think of a list containing A and C nodes, and you want to insert B in between them. You need to make B's node link to both A and C, and then modify C and A to link back to it. In your code, A is aNode, B is newNode and C is (at the start) aNode._next.
def _insertItemAfterNode(self, item, aNode):
newNode = Node(aNode, item, aNode._next) # link B to A and C
aNode._next._prev = newNode # link C back to B
aNode._next = newNode # and A to B too!
self._length += 1
There are a few things strange with your code. Let's dig into the first problem that I found:
def _insertItemAfterNode(self,item,aNode):
newNode = Node(aNode._prev, item, aNode._next)
aNode._next= newNode._prev
aNode._prev=newNode._next
self._length += 1
Assume that you have:
prevNode <-> aNode <-> nextNode
You now create a newNode which points to prevNode as its previous and nextNode as its follow-up. Then you reverse the pointers of aNode. prevNode still thinks its following node is aNode, but aNode now thinks that its following node is prevNode again.
/---------\
/----> aNode < v
prevNode <--------/ \-- nextNode
^ ^
\---- newNode --/
Which is not nearly what you want:
prevNode <-> aNode <-> newNode <-> nextNode
Here's a better version:
def _insertItemAfterNode(self,item,aNode):
# If the new Node follows aNode, than its preceeding node is aNode,
# not aNode._prev!
newNode = Node(aNode, item, aNode._next)
# Now we need to make aNode point at its new following Node, newNode
aNode._next = newNode
# And finally, we need to make the following Node notice that
# its preceeding Node has changed.
newNode._next._prev = newNode
self._length += 1
This doesn't care about any edge cases, for example what to do if aNode is the last node in the linked list.
What I recommend is that you take out a piece of paper and draw how the different links need to be changed for each of the operations that you need to make, because it is hard to keep all this in your head.
Make sure that you look at all the edge cases, ie. putting into an empty list, putting in item into the first and last positions.
And finally, while shuffling links around, always double check where each link is pointing at each instruction, and not to drop any nodes accidentally.

Categories