Concatenate Python Linked List - python

I am attempting to concatenate a Python linked list without copying the data contained within the nodes of the list. I have a function that will concatenate the list using copies of the nodes passed in, but I can't seem to get the function that doesn't use copies to work.
These functions are for testing and timing purposes; I know that Python's built-in list is awesome!
Here is the class I have been working with and the concatenate function.
class Cell:
def __init__( self, data, next = None ):
self.data = data
self.next = next
def print_list(self):
node = self
while node != None:
print node.data
node = node.next
The concatenation function is not meant to be a member function of the Cell class.
def list_concat(A, B):
while A.next != None:
A = A.next
A.next = B
return A
This function overwrites the first element of a list if the parameter A has more than one node. I understand why that is happening, but am not sure how to go about fixing it.
Here is the testing code I've been using for this function.
e = Cell(5)
test = Cell(3, Cell(4))
test2 = list_concat(test2, e)
test2.print_list()
Any insight or help would be greatly appreciated.
*edited to fix code formatting

Try this instead:
def list_concat(A, B):
current = A
while current.next != None:
current = current.next
current.next = B
return A
Assigning new values to a function's parameters is a bad programming practice, and the code in your question shows why: You used A for iterating over the original list, and by doing so, you lost the reference to its first element.

I'm not sure on about if extend performs a copy or not, but in case it doesn't, just use
A.extend(B)

Related

Python object isn't being created as normal even though I have created it as normal within the same function (doubly linked list)

I've created a doubly linked list and I'm having trouble with a function that swaps the first node with the last node, the second node with the second from last, etc. I'm creating various functions within the doubly linked list class (LDL). The problem comes with trying to create a node object. However it's strange as I have created the node objects without problem even within the same function. Here's the code:
class Node:
def __init__(self, data, nextLeft=None, nextRight=None):
self.data = data
self.nextLeft = nextLeft
self.nextRight = nextRight
class LDL:
def __init__(self, head=None):
self.head = head
def insertAtEnd(self, dataToInsert):
...
def reverseSwap(self):
nodeFirst = self.head # THE PROBLEM OBJECT
nodeCurrent = self.head
nodeLast = Node(None)
counter = 0
while nodeCurrent.nextRight is not None:
nodeCurrent = nodeCurrent.nextRight
conter += 1
for i in range(0, int(cont/2)):
temp = nodeFirst.data
nodeFirst.data = nodeLast.data # THE LINE OF THE ERROR
nodeLast.data = temp
nodeFirst = nodeFirst.nextRight
nodeLast = nodeLast.nextLeft
When I try to run this I get the error:
nodeFirst.data = nodeLast.data
AttributeError: 'NoneType' object has no attribute 'data'
However I knew this was coming as I can see while coding that it's not recognised as a Node object, because it doesn't offer to autofill nodeFirst.data or nodeFirst.nextLeft etc.
I have tried setting nodeFirst = nodeCurrent, I have tried placing it at various other parts of the code, I have tried different names, but I can't get it to work.
EDIT: I should point out that nodeCurrent = self.head works fine and as intended. This is also the first time I've come across this when working with linked lists as I have used a similar setup to work with singly linked lists with no problems.
If anybody could point me in the right direction that would be great.
because your init method of LDL class allows head to be None.
Therefore nodeFirst and nodeLast may become None.
to prevent this fix following
def __init__(self, head=None):
self.head=head
to this
def __init__(self, headdata):
self.head=Node(headdata)
or alternatively consider the edge case of list size = 0 in reverseSwap method

Insert at head in python linked list

I'm implementing inserting at a linked list's head using Python. I'm referencing this guide. for case 2, I found I must add return self.head to get driver code to properly insert at head otherwise it will not terminate. Why is that? I would consider the first lines to be enough since I'm calling this method to modify the linked list in place. why do i need to return?
And here is the code for insert before a node:
class LinkedList:
# note nodes = Node set the default (no argument) initialization
def __init__(self, nodes = None):
self.head = None
if nodes is not None:
# .pop(index) method remove the element from an array-like container and return it
node = Node(nodes.pop(0))
self.head = node
# loop through the rest elements in nodes (2nd now became the 1st in nodes)
for elem in nodes:
node.next = Node(elem)
node = node.next
def insert_before(self, targetn_data, newn):
# case1: empty list
if self.head is None:
raise Exception('empty llist')
# case2: insert before head (newn becomes new head)
if targetn_data == self.head.data:
print(f'inserting {newn} at the head')
newn.next = self.head
self.head = newn
################# Why? ##################
return self.head
#########################################
# case3: in between. use runner technique
...
driver code:
def main():
nodes = [1, 2, 3, 4, 5, 6]
# instantiate a linked list using __init__ method we defined
llist = LinkedList(nodes)
# insert_before driver code
llist.insert_before(1, Node(100))
llist.insert_before(6, Node(90))
print(f'prints out the llist after insert_before: \n {llist}\n')
The Implementation of the function depends upon you. It can be changed.
And Regarding Why he used a return is to just come out the function or else whatever other steps are there #case3 they will run which is not expected.
Generally, When you write a code better than writing an if-else clause it would be better to use exit first or execute the remaining code. (here exit is return statement).
This way of coding will be easy to understand for other developers who see code so that they don't have to track the if-else in nested if-else case.
Let me elaborate it with an Example.
public boolean function() {
if (conditionA) {
# Do something 1
} else {
# Do Something 2
}
return true/false;
}
// Different way You could write the code like this.
// This will way cleaner and understandable
// Than the previous version when there nested if-else.
public boolean function() {
if (conditionA) {
# Do something 1
return true;
} // Exit First
# Do Something 2
return false;
}
Look Naive for single if-else but will a great help in huge nested if-else codes.
But a Good Coding principle to follow when you can.

How to move last element of a linked list to first in python (below code)?

#DSA-Prac-1
class Node:
def __init__(self,data):
self.__data=data
self.__next=None
def get_data(self):
return self.__data
def set_data(self,data):
self.__data=data
def get_next(self):
return self.__next
def set_next(self,next_node):
self.__next=next_node
class LinkedList:
def __init__(self):
self.__head=None
self.__tail=None
def get_head(self):
return self.__head
def get_tail(self):
return self.__tail
def add(self,data):
new_node=Node(data)
if(self.__head is None):
self.__head=self.__tail=new_node
else:
self.__tail.set_next(new_node)
self.__tail=new_node
def insert(self,data,data_before):
new_node=Node(data)
if(data_before==None):
new_node.set_next(self.__head)
self.__head=new_node
if(new_node.get_next()==None):
self.__tail=new_node
else:
node_before=self.find_node(data_before)
if(node_before is not None):
new_node.set_next(node_before.get_next())
node_before.set_next(new_node)
if(new_node.get_next() is None):
self.__tail=new_node
else:
print(data_before,"is not present in the Linked list")
def display(self):
temp=self.__head
while(temp is not None):
print(temp.get_data())
temp=temp.get_next()
def find_node(self,data):
temp=self.__head
while(temp is not None):
if(temp.get_data()==data):
return temp
temp=temp.get_next()
return None
def delete(self,data):
node=self.find_node(data)
if(node is not None):
if(node==self.__head):
if(self.__head==self.__tail):
self.__tail=None
self.__head=node.get_next()
else:
temp=self.__head
while(temp is not None):
if(temp.get_next()==node):
temp.set_next(node.get_next())
if(node==self.__tail):
self.__tail=temp
node.set_next(None)
break
temp=temp.get_next()
else:
print(data,"is not present in Linked list")
def change_order(input_list):
'I need the code to be written here'
return input_list
input_list=LinkedList()
input_list.add(9)
input_list.add(3)
input_list.add(56)
input_list.add(6)
input_list.add(2)
input_list.add(7)
input_list.add(4)
result=change_order(input_list)
result.display()
Only the function change_order must be written. No changes should be made in other parts of the program. The input linked list is 9->3->56->6->2->7->4 and the output should be 4->9->3->56->6->2->7.I need answer for this particular code.
This is what i have tried. Since the head of linkedlist class is a private attribute, i face difficulty in assigning the new head.
def change_order(input_list):
temp=input_list.get_head()
while temp and temp.get_next():
sec_last = temp
temp=temp.get_next()
sec_last.set_next(None)
temp.set_next(input_list.get_head())
Your LinkedList class should already provide all the functionality you need to be able to accomplish this without any need to mess around with the pointers yourself:
data = input_list.get_tail().get_data() # get last element
input_list.delete(data) # remove last element
input_list.insert(data, None) # insert that element first
Note that the list interface assumes that all items in the list are unique; some of these methods don't work properly if you have duplicates and will only ever operate on the first match. If you do the insert before the delete, for example, the delete will remove the item at the head that you just inserted, not the item at the tail that you wanted to remove.
This is essentially a bug/constraint of this list implementation; normally a list interface would provide you with some sort of iterator to allow you to handle cases with multiple matches.
If you had to work around that under the parameters of the assignment, being able to modify the head isn't the hard part (because you can do that reliably via insert), but rather popping off the tail (since the only interface that lets you do that is delete, which will flatly not let you access a node by reference, and is therefore always going to do the wrong thing if you're trying to use it to delete the tail when there's a duplicate). The simplest solution IMO is to just convert the entire list into a better format, do whatever you need, and then convert it back. (This is a terrible lesson if the goal is to learn how linked lists work, but it's a good lesson if the goal is learn how sometimes you need to do silly things to work around someone else's incompetence.)
def change_order(input_list):
'I need the code to be written here'
# Define helper functions to convert LinkedList to and from List.
def convert_linked_list_to_list(linked_list):
"""Converts a LinkedList to a native List."""
arr = []
node = input_list.get_head()
while node is not None:
arr.append(node.get_data())
node = node.get_next()
return arr
def rebuild_linked_list_from_list(linked_list, arr):
"""Replaces input LinkedList contents with native List contents."""
while linked_list.get_head() is not None:
linked_list.delete(linked_list.get_head().get_data())
for data in arr:
linked_list.add(data)
# Now do the order change using a List.
arr = convert_linked_list_to_list(input_list)
rebuild_linked_list_from_list(input_list, arr[-1:] + arr[:-1])
return input_list
In real life, you'd define these helpers outside of this function, because they're bound to be useful in other situations where you need to manipulate one of these LinkedList containers in ways that its terrible interface doesn't support, but the parameters of the assignment require everything to be contained to change_order, so there you have it.

Why does recursive function for travelling to front of doubly linked list not work?

I am a novice who has just finished edX's introductory course MIT 6.00.1x; the following is related to a problem on that course's final exam (now concluded, so I can seek help). Let
def class DLLNode(object):
def __init__(self, name):
self.cargo = cargo
self.before = None
self.after = None
def setBefore(self, before): self.before = before
def setAfter(self, after): self.after = after
def getBefore(self): return self.before
def getAfter(self): return self.after
def getCargo(self): return self.cargo
be used to create a doubly linked list. Suppose node is an instance of class DLLNode that appears in a doubly linked list. Then node.getBefore() returns that node's immediate predecessor in the list, except that it returns None if node is at the front of the list and so has no predecessor.
I have written a recursive function
def firstInList(nodeInList):
""" Prints out the cargo carried by the first node in that doubly linked list
of which nodeInList is a part. Returns that first node. """
if nodeInList.getBefore() == None:
firstnode = nodeInList
print firstnode.getCargo()
return firstnode
# nodeInList.getBefore() is not None, so nodeInList has an immediate predecessor
# on which firstInList can be be called.
firstInList(nodeInList.getBefore())
that I wish to return the first node in a doubly linked list, given as argument a known node nodeInList in the list.
My problem: firstInList arrives at the correct first node, as evidenced by its printing the first node's cargo regardless of the specific nodeInList used. But whenever nodeInList is not the first node in the linked list, the return value of firstInList(node) turns out to be None rather than the desired first node. This conclusion is based on the following: If, for example, the list's first node node1 has cargo 1 and is followed by node2 with cargo 2, then firstInList(node2) == None evaluates as True but firstInList(node2) == node1 evaluates as False. A call firstInList(node2).getCargo() will return an error message
Attribute Error: 'NoneType' object has no attribute 'getCargo'
Another datum is that firstInList(node1) == node1 evaluates as True; that, at least, is as I would expect.
This suggests the firstnode found is not being returned back up the chain of recursive calls in the way I have imagined. Can anyone explain why?
(Please do not suggest that I use iteration instead of recursion. I know how to do that. I am trying to understand Python 2.7's behavior for the code as written.)
Well, it would appear that you're not returning the result of the recursion, so the function will in all cases but the degenerate simply return the default uninitialized value.
The last line should be:
return firstInList(nodeInList.getBefore())
Many thanks to Nathan Tuggy. At first I misunderstood what you were saying, but in fact you were correct.
My firstInList function worked perfectly once I changed the last line
firstInList(nodeInList.getBefore())
to read
return firstInList(nodeInList.getBefore()) .
Given the ridiculous number of hours I've spent worrying about this, I think this is a type of mistake I'm not likely to make in the future. Or if I do, I'll be able to discover the problem myself.

Python basic data structure Implementation

I am a C++ coder. Recently started with Python. I was having a look at a simple Linked List implementation in Python. I am bit confused here. Not only here but also in Tree implementation and so on with the same problem.
class Element contains data and pointer to next node. Perfect no problem. However in class LinkedList I can see self.tail.next=e, now next is a variable of Element class even if it is public than also an object of Element class has to access it. Here how can we write something like self.tail.next = e as tail is just a variable of LinkedList class and is not an object of Element class. I am confused.
class Element:
def __init__(self,x):
self.data=x
self.next=None
class LinkedList:
def __init__(self):
self.head=None
self.tail=None
def append(self,x):
# create a new Element
e = Element(x)
# special case: list is empty
if self.head==None:
self.head=e
self.tail=e
else:
# keep head the same
self.tail.next=e
self.tail=e
Python works with references. Everything is always passed by reference, the values are always shared via references (unless explicitly copied).
Assigning an object means assigning the reference to that object. This way self.tail.next = e means: self.tail is expecting to refer to the object of the Element class. The object has the .next attribute. The self.tail.next = e means that the last element of the non-empty list is going to point to the just appended new element. Then the self.tail = e means that the reference to the last element is moved to the just appended last element.
Any variable in Python is just a reference variable with the given name. It is automatically dereferenced. Because of that it may look strangely to those familiar with classical compiled languages, like C++.
I am not sure if you can display the articles at Expert Exchange without creating the account. If yes, have a look at http://www.experts-exchange.com/Programming/Languages/Scripting/Python/A_6589-Python-basics-illustrated-part-2.html and namely the http://www.experts-exchange.com/Programming/Languages/Scripting/Python/A_7109-Python-basics-illustrated-part-3.html for the images that explain the problem.
The only place where you initialize self.tail is in append and in there you set it to be equal to e. Just a little bit above you have e = Element(x) and so e is an object of type Element. Please note that in the moment you call self.tail.next=e you know head is not none and thus tail is also not None but an instance of Element.
Hope this helps.
You wrote:
now next is a variable of Element class even if it is public than also an object of Element class has to access it.
There is a misunderstanding there. Public members (i.e. all members except those that start with two underscores) are accessible from anywhere, not only from within methods of the same class.
next and tail are Elements, that's why. This would be true for a linked list in any language, including C or C++. A linked list is a list of elements linked together with pointers/references.
When the list is traversed, those links are used to get from node (element) to node. It would not make sense if they referred to other linked lists, would it? The first element in the list is the head, the last element is the tail, the next element pointed to in a node is the element after it in the list, the previous node is the element before it.
In python everything is a reference.
Please: separate the list implementation from your (application) data.
As in C++ it is good style to encapsulate the access methods - nevertheless because there are no access restrictions to instance fields they can be accessed from everywhere.
An idea of a generic double linked list (this is only a skeleton which should be enhanced - but I hope it transports the idea).
class DoubleLinkedList(object):
class ListNode(object):
def __init__(self):
self.__next = None
self.__prev = None
def next(self):
return self.__next
def prev(self):
return self.__prev
def set_next(self, next_node):
self.__next = next_node
def set_prev(self, prev_node):
self.__prev = prev_node
def is_last(self):
return self.next()==None
def __init__(self):
'''Sets up an empty linked list.'''
self.__head = DoubleLinkedList.ListNode()
self.__tail = DoubleLinkedList.ListNode()
self.__head.set_next(self.__tail)
self.__tail.set_prev(self.__head)
def first(self):
return self.__head.next()
def last(self):
return self.__tail.prev()
def append(self, list_node):
list_node.set_next(self.__tail)
list_node.set_prev(self.__tail.prev())
self.__tail.set_prev(list_node)
list_node.prev().set_next(list_node)
########################################
class MyData(DoubleLinkedList.ListNode):
def __init__(self, d):
DoubleLinkedList.ListNode.__init__(self)
self.__data = d
def get_data(self):
return self.__data
ll = DoubleLinkedList()
md1 = MyData(1)
md2 = MyData(2)
md3 = MyData(3)
ll.append(md1)
ll.append(md2)
ll.append(md3)
node = ll.first()
while not node.is_last():
print("Data [%s]" % node.get_data())
node = node.next()

Categories