Sample Linked Lists Chapter (Data Structure and Algorithmic Thinking With Python)
Sample Linked Lists Chapter (Data Structure and Algorithmic Thinking With Python)
Chapter
Linked Lists
15
40
NULL
Head
Delete: removes and returns the specified position element from the list
Auxiliary Linked Lists Operations
Delete List: removes all elements of the list (disposes the list)
Count: returns the number of elements in the list
Find node from the end of the list
48
Linked Lists
2
1
1
2
2
3
3
4
Advantages of Arrays
Disadvantages of Arrays
Fixed size: The size of the array is static (specify the array size before using it).
One block allocation: To allocate the array at the beginning itself, sometimes it may not be possible to
get the memory for the complete array (if the array size is big).
Complex position-based insertion: To insert an element at a given position we may need to shift the
existing elements. This will create a position for us to insert the new element at the desired position. If
the position at which we want to add an element is at the beginning then the shifting operation is more
expensive.
Dynamic Arrays
Dynamic array (also called as , , , or ) is a random access,
variable-size list data structure that allows elements to be added or removed.
One simple way of implementing dynamic arrays is, initially start with some fixed size array. As soon as that
array becomes full, create the new array of size double than the original array. Similarly, reduce the array size to
half if the elements in the array are less than half.
Note: We will see the implementation for in the , and chapters.
49
Linked Lists
Linked list
Array
Dynamic array
Indexing
O()
O(1)
O(1)
Insertion/deletion at beginning
O(1)
O()
Insertion at ending
O()
Deletion at ending
O()
Insertion in middle
O()
Deletion in middle
O()
Wasted space
O()
O(1)
O(), if array is not full (for
shifting the elements)
O(), if array is not full (for
shifting the elements)
0
15
40
NULL
Head
Following is a type declaration for a linked list of integers:
#Node of a Singly Linked List
class Node:
#constructor
def __init__(self):
self.data = None
self.next = None
#method for setting the data field of the node
def setData(self,data):
self.data = data
#method for getting the data field of the node
def getData(self):
return self.data
#method for setting the next field of the node
def setNext(self,next):
self.next = next
#method for getting the next field of the node
def getNext(self):
return self.next
#returns true if the node points to another node
def hasNext(self):
return self.next != None
50
Linked Lists
Display the contents of the nodes (or count) as they are traversed.
Stop when the next pointer points to NULL.
5
17
NULL
Head
The ListLength() function takes a linked list as input and counts the number of nodes in the list. The function
given below can be used for printing the list data with extra print function.
def listLength(self):
current = self.head
count = 0
while current != None:
count = count + 1
current = current.getNext()
return count
Time Complexity: O(), for scanning the list of size .
Space Complexity: O(1), for creating temporary variable.
Note: To insert an element in the linked list at some position , assume that after inserting the element the
position of this new node is .
Update the next pointer of new node, to point to the current head.
New node
data
15
40
NULL
head
Update head pointer to point to the new node.
New node
data
15
40
NULL
Head
#method for inserting a new node at the beginning of the Linked List (at the head)
def insertAtBeginning(self,data):
newNode = Node()
newNode.setData(data)
if self.length == 0:
51
Linked Lists
15
New node
0 data
NULL
Head
15
40
NULL
Head
#method for inserting a new node at the end of a Linked List
def insertAtEnd(self,data):
newNode = Node()
newNode.setData(data)
current = self.head
while current.getNext() != None:
current = current.getNext()
current.setNext(newNode)
self.length += 1
If we want to add an element at position 3 then we stop at position 2. That means we traverse 2 nodes
and insert the new node. For simplicity let us assume that second node is called node. New
node points to the next node of the position where we want to add this node.
Position node
4
Head
15
40
NULL
data
New node
52
Linked Lists
15
Head
NULL
40
data
New node
Let us write the code for all these three cases. We must update the first element pointer in the calling function,
not just in the called function. For this reason we need to send double pointer. The following code inserts a node
in the singly linked list.
#Method for inserting a new node at any position in a Linked List
def insertAtPos(self,pos,data):
if pos > self.length or pos < 0:
return None
else:
if pos == 0:
self.insertAtBeg(data)
else:
if pos == self.length:
self.insertAtEnd(data)
else:
newNode = Node()
newNode.setData(data)
count = 0
current = self.head
while count < pos-1:
count += 1
current = current.getNext()
newNode.setNext(current.getNext())
current.setNext(newNode)
self.length += 1
Note: We can implement the three variations of the operation separately.
Time Complexity: O(). Since, in the worst we may need to insert the node at end of the list.
Space Complexity: O(1), for creating one temporary variable.
Create a temporary node which will point to same node as that of head.
4
Head
15
40
NULL
Temp
Now, move the head nodes pointer to the next node and dispose the temporary node.
53
Linked Lists
15
Temp
40
NULL
Head
Traverse the list and while traversing maintain the previous node address also. By the time we reach the
end of list, we will have two pointers one pointing to the node and other pointing to the node
tail node.
4
15
15
NULL
Tail
40
Head
NULL
40
Head
NULL
Tail
NULL
15
Head
40
NULL
Tail
54
Linked Lists
As similar to previous case, maintain previous node while traversing the list. Once we found the node to
be deleted, change the previous nodes next pointer to next pointer of the node to be deleted.
15
Head
Previous node
40
NULL
Node to be deleted
15
Previous node
Head
40
NULL
Node to be deleted
55
Linked Lists
currentnode = self.head
previousnode = self.head
if pos > self.length or pos < 0:
print "The position does not exist. Please enter a valid position"
else:
while currentnode.next != None or count < pos:
count = count + 1
if count == pos:
previousnode.next = currentnode.next
self.length -= 1
return
else:
previousnode = currentnode
currentnode = currentnode.next
Time Complexity: O(). In the worst we may need to delete the node at the end of the list.
Space Complexity: O(1), for one temporary variable.
As similar to singly linked list, let us implement the operations of doubly linked lists. If you understand the
singly linked list operations then doubly linked list operations are very obvious. Following is a type declaration
for a doubly linked list of integers:
class Node:
# If data is not given by user,its taken as None
def __init__(self, data=None, next=None, prev=None):
self.data = data
self.next = next
self.prev = prev
#method for setting the data field of the node
def setData(self,data):
self.data = data
#method for getting the data field of the node
def getData(self):
return self.data
#method for setting the next field of the node
def setNext(self,next):
self.next = next
#method for getting the next field of the node
def getNext(self):
return self.next
56
Linked Lists
Update the right pointer of new node to point to the current head node (dotted link in below figure) and
also make left pointer of new node as NULL.
New node
data
NULL
Head
15
40
NULL
NULL
Update head nodes left pointer to point to the new node and make new node as head.
Head
data
15
40
NULL
NULL
def insertAtBeginning(self, data):
newNode = Node(data, None, None)
if (self.head == None): # To imply that if head == None
self.head = self.tail = newNode
else:
newNode.setPrev(None)
newNode.setNext(self.head)
self.head.setPrev(newNode)
self.head = newNode
57
Linked Lists
New node right pointer points to NULL and left pointer points to the end of the list.
Head
15
data
NULL
NULL
New node
NULL
15
New node
data
NULL
NULL
right pointer points to the next node of the where we want to insert the new
node. Also, left pointer points to the node.
NULL
Position node
4
15
Head
40
NULL
data
New node
Position node right pointer points to the new node and the of position nodes left pointer points
to new node.
NULL
4
Head
Position node
15
40
NULL
data
New node
58
Linked Lists
Now, let us write the code for all these three cases. We must update the first element pointer in the calling
function, not just in the called function. For this reason we need to send double pointer. The following code
inserts a node in the doubly linked list.
def getNode(self, index):
currentNode = self.head
if currentNode == None:
return None
i=0
while i <= index:
currentNode = currentNode.getNext()
if currentNode == None:
break
i += 1
return currentNode
def insertAtGivenPosition(self, index, data):
newNode = Node(data)
if self.head == None or index == 0:
self.insertAtBeginning(data)
elif index > 0:
temp = self.getNode(index)
if temp == None or temp.getNext() == None:
self.insertAtEnd(data)
else:
newNode.setNext(self.getNext())
newNode.setPrev()
temp.getNext().setPrev(newNode)
temp.setNext(newNode)
Time Complexity: O(). In the worst we may need to insert the node at the end of the list.
Space Complexity: O(1), for temporary variable.
Create a temporary node which will point to same node as that of head.
NULL
Head
15
40
NULL
Temp
59
Linked Lists
Now, move the head nodes pointer to the next node and change the heads left pointer to NULL. Then,
dispose the temporary node.
NULL
4
15
40
NULL
NULL
Temp
Head
Traverse the list and while traversing maintain the previous node address also. By the time we reach the
end of list, we will have two pointers one pointing to the tail and other pointing to the node before tail
node.
NULL
4
15
NULL
Tail
NULL
4
15
Head
40
Head
40
NULL
Tail
Head
15
40
NULL
Tail
Similar to previous case, maintain previous node also while traversing the list. Once we found the node
to be deleted, change the previous nodes next pointer to the next node of the node to be deleted.
60
Linked Lists
Head
15
Previous node
40
NULL
Node to be deleted
Head
15
Previous node
40
NULL
Node to be deleted
61
Linked Lists
lists, there is no node with NULL pointer in a circularly linked list. In some situations, circular linked lists are
useful. There is no difference in the node declaration of circular linked lists compared to singly linked lists.
For example, when several processes are using the same computer resource (CPU) for the same amount of time,
we have to assure that no process accesses the resource before all other processes did (round robin algorithm).
The following is a type declaration for a circular linked list:
#Node of a Circular Linked List
class Node:
#constructor
def __init__(self):
self.data = None
self.next = None
#method for setting the data field of the node
def setData(self,data):
self.data = data
#method for getting the data field of the node
def getData(self):
return self.data
#method for setting the next field of the node
def setNext(self,next):
self.next = next
#method for getting the next field of the node
def getNext(self):
return self.next
#returns true if the node points to another node
def hasNext(self):
return self.next != None
In circular linked list we access the elements using the node (similar to node in singly linked list and
doubly linked lists).
15
40
Head
The circular list is accessible through the node marked . To count the nodes, the list has to be traversed
from node marked , with the help of a dummy node and stop the counting when reaches the
starting node .
If the list is empty, will be NULL, and in that case set = 0. Otherwise, set the current pointer to the
first node, and keep on counting till the current pointer reaches the starting node.
#This method would be a member of other class (say, CircularList)
def circularListLength(self):
currentNode = self.head
if currentNode == None:
return 0
count = 1
currentNode = currentNode.getNext()
while currentNode != self.head:
currentNode = currentNode.getNext()
count = count + 1
retur count
Time Complexity: O(), for scanning the complete list of size . Space Complexity: O(1), for temporary variable.
62
Linked Lists
15
40
Head
We assume here that the list is being accessed by its node. Since all the nodes are arranged in a circular
fashion, the node of the list will be the node previous to the node. Let us assume we want to print the
contents of the nodes starting with the node. Print its contents, move to the next node and continue
printing till we reach the node again.
def printCircularList(self):
currentNode = self.head
if currentNode == None: return 0
print (currentNode.getData())
currentNode = currentNode.getNext()
while currentNode != self.head:
currentNode = currentNode.getNext()
print (currentNode.getData())
Time Complexity: O(), for scanning the complete list of size . Space Complexity: O(1), for temporary variable.
Create a new node and initially keep its next pointer points to itself.
15
40
data
Head
New node
Update the next pointer of new node with head node and also traverse the list until the tail. That means
in circular list we should stop at a node whose next node is head.
Previous node of head
4
15
40
data
Head
New node
Update the next pointer of previous node to point to new node and we get the list as shown below.
15
17
40
data
Head
63
Linked Lists
Time Complexity: O(), for scanning the complete list of size . Space Complexity: O(1), for temporary variable.
Create a new node and initially keep its next pointer points to itself.
data
15
40
New node
Head
Update the next pointer of new node with head node and also traverse the list until the tail. That means
in circular list we should stop at the node which is its previous node in the list.
Head
15
data
40
New node
Update the previous node of head in the list to point to new node.
4
15
40
data
Head
New node
data
15
40
Head
def insertAtBeginInCLL (self, data):
current = self.head
64
Linked Lists
Traverse the list and find the tail node and its previous node.
60
15
Node to be
deleted
Update the tail nodes previous node next pointer to point to head.
60
15
7
Previous node to
deleting node
Head
40
Previous node to
deleting node
Head
40
Node to be
deleted
60
Head
15
7
Previous node to
deleting node
40
Node to be
deleted
65
Linked Lists
Find the tail node of the linked list by traversing the list. Tail node is the previous node to the head node
which we want to delete.
60
15
40
Previous node to
deleting node
Node to be
deleted
Head
Create a temporary node which will point to head. Also, update the tail nodes next pointer to point to
next node of head (as shown below).
Temp
60
Head
15
40
Previous node to
deleting node
Node to be
deleted
Now, move the head pointer to next node. Create a temporary node which will point to head. Also,
update the tail nodes next pointer to point to next node of head (as shown below).
Temp
60
4
Node to be
deleted
15
Head
40
Previous node to
deleting node
66
Linked Lists
Head
NULL
Pointer differences
The pointer field contains the difference between the pointer to the next node and the pointer to the
previous node. The pointer difference is calculated by using exclusive-or () operation.
67
Linked Lists
The of the start node (head node) is the of NULL and node (next node to head). Similarly, the
of end node is the of node (previous to end node) and NULL. As an example, consider the
following linked list.
In the example above,
blockHead
blockHead
30
70
45
91
19
17
Assume that there will be no more than elements in the unrolled linked list at any time. To simplify this
problem, all blocks, except the last one, should contain exactly elements. Thus, there will be no more than
blocks at any time.
blockHead
blockHead
30
70
45
91
19
17
68
Linked Lists
1.
Traverse on the to the one that contains the node, i.e., the th block. It takes O()
2.
blockHead
22
30
List Head
45
Shifting element
19
22
30
17
Shifting element
blockHead
blockHead
10
70
blockHead
blockHead
70
45
19
17
When inserting a node, we have to re-arrange the nodes in the unrolled linked list to maintain the properties
previously mentioned, that each block contains nodes. Suppose that we insert a node after the node,
and should be placed in the block. Nodes in the block and in the blocks after the block have to be
shifted toward the tail of the list so that each of them still have nodes. In addition, a new block needs to be
added to the tail if the last block of the list is out of space, i.e., it has more than nodes.
2.
B
3
19
45
17
In block , move the next pointer of the head node to point to the second to-the-last node, so that
the tail node of can be removed.
temp
A
70
3.
B
3
19
45
17
Let the next pointer of the node which will be shifted (the tail node of ) point to the tail node of .
A
70
B
3
19
17
45
temp
69
Linked Lists
Let the next pointer of the head node of point to the node temp points to.
A
70
B
3
19
17
45
temp
5.
Finally, set the head pointer of to point to the node temp points to. Now the node temp points to
become the new head node of .
A
70
B
45
19
17
temp
6.
pointer can be thrown away. We have completed the shift operation to move the original tail
node of to become the new head node of .
A
70
B
3
45
19
17
Performance
With unrolled linked lists, there are a couple of advantages, one in speed and one in space. First, if the number
of elements in each block is appropriately sized (e.g., at most the size of one cache line), we get noticeably better
cache performance from the improved memory locality. Second, since we have O(/) links, where is the
number of elements in the unrolled linked list and is the number of elements we can store in any block, we
can also save an appreciable amount of space, which is particularly noticeable if each element is small.
Implementation
#Node of a Singly Linked List
70
Linked Lists
class Node:
#constructor
def __init__(self):
self.value = None
self.next = None
#Node of a Singly Linked List
class LinkedBlock:
#constructor
def __init__(self):
self.head = None
self.next = None
nodeCount = 0
blockSize = 2
blockHead = None
#create an empty block
def newLinkedBlock():
block=LinkedBlock()
block.next=None
block.head=None
block.nodeCount=0
return block
#create a node
def newNode(value):
temp=Node()
temp.next=None
temp.value=value
return temp
def searchElements(blockHead, k):
#find the block
j=(k+blockSize-1)//blockSize #k-th node is in the j-th block
p=blockHead
j -= 1
while(j):
p=p.next
j -= 1
fLinkedBlock=p
#find the node
q=p.head
k=k%blockSize
if(k==0):
k=blockSize
k = p.nodeCount+1-k
k -= 1
while (k):
q=q.next
k -= 1
fNode=q
return fLinkedBlock, fNode
#start shift operation from block *p
def shift(A):
B=A
global blockHead
while(A.nodeCount > blockSize): #if this block still have to shift
if(A.next==None): #reach the end. A little different
A.next=newLinkedBlock()
B=A.next
temp=A.head.next
A.head.next=A.head.next.next
B.head=temp
temp.next=temp
71
Linked Lists
A.nodeCount -= 1
B.nodeCount += 1
else:
B=A.next
temp=A.head.next
A.head.next=A.head.next.next
temp.next=B.head.next
B.head.next=temp
B.head=temp
A.nodeCount -= 1
B.nodeCount += 1
A=B
def addElement(k, x):
global blockHead
r = newLinkedBlock()
p = Node()
if(blockHead == None): #initial, first node and block
blockHead=newLinkedBlock()
blockHead.head=newNode(x)
blockHead.head.next=blockHead.head
blockHead.nodeCount += 1
else:
if(k==0): #special case for k=0.
p=blockHead.head
q=p.next
p.next=newNode(x)
p.next.next=q
blockHead.head=p.next
blockHead.nodeCount += 1
shift(blockHead)
else:
r, p = searchElements(blockHead, k)
q=p
while(q.next != p):
q=q.next
q.next=newNode(x)
q.next.next=p
r.nodeCount += 1
shift(r)
return blockHead
def searchElement(blockHead, k):
q, p = searchElements(blockHead, k)
return p.value
blockHead = addElement(0,11)
blockHead = addElement(0,21)
blockHead = addElement(1,19)
blockHead = addElement(1,23)
blockHead = addElement(2,16)
blockHead = addElement(2,35)
searchElement(blockHead, 1)
72
Linked Lists
Skip lists are a probabilistic alternative to balanced trees. Skip list is a data structure that can be used as an
alternative to balanced binary trees (refer chapter). As compared to a binary tree, skip lists allow quick
search, insertions and deletions of elements. This is achieved by using probabilistic balancing rather than
strictly enforce balancing. It is basically a linked list with additional pointers such that intermediate nodes can
be skipped. It uses a random number generator to make some decisions.
In an ordinary sorted linked list, search, insert, and delete are in O() because the list must be scanned nodeby-node from the head to find the relevant node. If somehow we could scan down the list in bigger steps (skip
down, as it were), we would reduce the cost of scanning. This is the fundamental idea behind Skip Lists.
12
19
23
29
43
70
12
19
23
29
43
70
12
19
23
29
43
70
This section gives algorithms to search for, insert and delete elements in a dictionary or symbol table. The
Search operation returns the contents of the value associated with the desired key or failure if the key is not
present. The Insert operation associates a specified key with a new value (inserting the key if it had not already
been present). The Delete operation deletes the specified key. It is easy to support additional operations such as
find the minimum key or find the next key.
Each element is represented by a node, the level of which is chosen randomly when the node is inserted without
regard for the number of elements in the data structure. A level i node has i forward pointers, indexed 1 through
i. We do not need to store the level of a node in the node. Levels are capped at some appropriate constant
. The level of a list is the maximum level currently in the list (or 1 if the list is empty). The header of a
list has forward pointers at levels one through MaxLevel. The forward pointers of the header at levels higher
than the current maximum level of the list point to NULL.
Initialization
An element NIL is allocated and given a key greater than any legal key. All levels of all skip lists are terminated
with NIL. A new list is initialized so that the level of the list is equal to 1 and all forward pointers of the lists
header point to NIL.
73
Linked Lists
Performance
In a simple linked list that consists of elements, to perform a search comparisons are required in the worst
case. If a second pointer pointing two nodes ahead is added to every node, the number of comparisons goes
down to /2 + 1 in the worst case. Adding one more pointer to every fourth node and making them point to the
fourth node ahead reduces the number of comparisons to /2 + 2. If this strategy is continued so that every
node with pointers points to 2 1 nodes ahead, O() performance is obtained and the number of pointers
has only doubled ( + /2 + /4 + /8 + /16 + .... = 2).
The find, insert, and remove operations on ordinary binary search trees are efficient, O(), when the input
data is random; but less efficient, O(), when the input data are ordered. Skip List performance for these same
operations and for any data set is about as good as that of randomly-built binary search trees - namely O().
The nodes in an ordinary list have one next reference. The nodes in a Skip List have many
references (also called references).
The number of references for a given node is determined probabilistically.
We speak of a Skip List node having levels, one level per forward reference. The number of levels in a node is
called the of the node. In an ordinary sorted list, insert, remove, and find operations require sequential
traversal of the list. This results in O() performance per operation. Skip Lists allow intermediate nodes in the
list to be skipped during a traversal - resulting in an expected performance of O() per operation.
Implementation
import random
import math
class Node(object):
def __init__(self, data, level=0):
self.data = data
self.next = [None] * level
def __str__(self):
return "Node(%s,%s)" % (self.data, len(self.next))
__repr__ = __str__
class SkipList(object):
def __init__(self, max_level=8):
self.max_level = max_level
n = Node(None, max_level)
self.head = n
self.verbose = False
def randomLevel(self, max_level):
num = random.randint(1, 2**max_level - 1)
lognum = math.log(num, 2)
level = int(math.floor(lognum))
return max_level - level
def updateList(self, data):
update = [None] * (self.max_level)
n = self.head
self._n_traverse = 0
level = self.max_level - 1
while level >= 0:
if self.verbose and \
n.next[level] != None and n.next[level].data >= data:
print 'DROP down from level', level + 1
74
Linked Lists
Problem-2
Solution: Brute-Force Method: Start with the first node and count the number of nodes present after that
node. If the number of nodes are < 1 then return saying fewer number of nodes in the list. If the number of
nodes are > 1 then go to next node. Continue this until the numbers of nodes after current node are 1.
Time Complexity: O(2 ), for scanning the remaining list (from current node) for each node.
Space Complexity: O(1).
Problem-3
Solution: Yes, using hash table. As an example consider the following list.
5
17
NULL
Head
75
Linked Lists
In this approach, create a hash table whose entries are < , >. That means, key is the
position of the node in the list and value is the address of that node.
Position in List
1
2
3
4
Address
Address
Address
Address
Address
of
of
of
of
of
Node
5 node
1 node
17 node
4 node
By the time we traverse the complete list (for creating hash table), we can find the list length. Let us say, the list
length is . To find from end of linked list, we can convert this to - + 1 from the beginning. Since we
already know the length of the list, it is just a matter of returning - + 1 key value from the hash table.
Time Complexity: Time for creating the hash table, () = O().
Space Complexity: Since we need to create a hash table of size , O().
Problem-4
Can we use Problem-3 approach for solving Problem-2 without creating the hash table?
Solution: Yes. If we observe the Problem-3 solution, what actually we are doing is finding the size of the linked
list. That means, we are using hash table to find the size of the linked list. We can find the length of the linked
list just by starting at the head node and traversing the list.
So, we can find the length of the list without creating the hash table. After finding the length, compute + 1
and with one more scan we can get the + 1 node from the beginning. This solution needs two scans:
one for finding the length of list and other for finding + 1 node from the beginning.
Time Complexity: Time for finding the length + Time for finding the - + 1 node from the beginning.
Therefore, ( = O() + O() O().
Space Complexity: O(1). Since, no need of creating the hash table.
Problem-5
Solution: Yes. Efficient Approach: Use two pointers and . Initially, both points to head node of
the list. starts moving only after made moves.
From there both moves forward until reaches end of the list. As a result points to node from
end of the linked list.
Note: at any point of time both moves one node at time.
def nthNodeFromEnd( self, n ):
if 0 > n:
return None
# count k units from the self.head.
temp = self.head
count = 0
while count < n and None != temp:
temp = temp.next
count += 1
# if the LinkedList does not contain k elements, return None
if count < n or None == temp:
return None
# keeping tab on the nth element from temp, slide temp until
# temp equals self.tail. Then return the nth element.
nth = self.head
while None != temp.next:
temp = temp.next
nth = nth.next
return nth
Time Complexity: O(). Space Complexity: O(1).
Problem-6
Check whether the given linked list is either NULL-terminated or ends in a cycle (cyclic).
Solution: Brute-Force Approach. As an example consider the following linked list which has a loop in it. The
difference between this list and the regular list is that, in this list there are two nodes whose next pointers are
same. In regular singly linked lists (without loop) each nodes next pointer is unique.
That means, the repetition of next pointers indicates the existence of loop.
76
Linked Lists
One simple and brute force way of solving this is, start with the first node and see whether there is any node
whose next pointer is current nodes address. If there is a node with same address then that indicates that some
other node is pointing to the current node and we can say loops exists.
Continue this process for all the nodes of the linked list.
Does this method works? As per the algorithm we are checking for the next pointer addresses, but how do we
find the end of the linked list (otherwise we will end up in infinite loop)?
Note: If we start with a node in loop, this method may work depending on the size of the loop.
Problem-7
Check if the address of the node is available in the hash table or not.
If it is already available in the hash table then that indicates that we are visiting the node that was
already visited. This is possible only if the given linked list has a loop in it.
If the address of the node is not available in the hash table then insert that nodes address into the hash
table.
Continue this process until we reach end of the linked list we find loop.
Time Complexity: O() for scanning the linked list. Note that we are doing only scan of the input.
Space Complexity: O() for hash table.
Problem-8
Solution: No. Consider the following algorithm which is based on sorting. And then, we see why this algorithm
fails.
Algorithm:
Traverse the linked list nodes one by one and take all the next pointer values into some array.
If there is a loop in the linked list, definitely two nodes next pointers will pointing to the same node.
After sorting if there is a loop in the list, the nodes whose next pointers are same will come adjacent in
the sorted list.
If any such pair exists in the sorted list then we say the linked list has loop in it.
Time Complexity: O() for sorting the next pointers array.
Space Complexity: O() for the next pointers array.
Problem with above algorithm: The above algorithm works only if we can find the length of the list. But if the
list is having loop then we may end up in infinite loop. Due to this reason the algorithm fails.
Problem-9
Solution: Yes. Efficient Approach (Memory less Approach): This problem was solved by . The solution is
named as Floyd cycle finding algorithm. It uses 2 pointers moving at different speeds to walk the linked list.
Once they enter the loop they are expected to meet, which denotes that there is a loop.
This works because the only way a faster moving pointer would point to the same location as a slower moving
pointer is, if somehow the entire list or a part of it is circular. Think of a tortoise and a hare running on a track.
The faster running hare will catch up with the tortoise if they are running in a loop.
77
Linked Lists
As an example, consider the following example and trace out the Floyd algorithm. From the diagrams below we
can see that after the final step they are meeting at some point in the loop which may not be the starting of the
loop.
Note: () moves one pointer at a time and () moves two pointers at a time.
slowPtr
fastPtr
slowPtr
fastPtr
fastPtr
slowPtr
slowPtr
fastPtr
slowPtr
fastPtr
fastPt
r
slowPt
r
slowPtr
fastPt
r
78
Linked Lists
def detectCycle(self):
fastPtr = self.head
slowPtr = self.head
while (fastPtr and slowPtr):
fastPtr = fastPtr.getNext()
if (fastPtr == slowPtr):
return True
if fastPtr == None:
return False
fastPtr = fastPtr.getNext()
if (fastPtr == slowPtr):
return True
slowPtr = slowPtr.getNext()
Time Complexity: O(). Space Complexity: O(1).
Problem-10
We are given a pointer to the first element of a linked list . There are two possibilities for , it
either ends (snake) or its last element points back to one of the earlier elements in the list (snail). Give an
algorithm that tests whether a given list is a snake or a snail.
Solution: It is same as Problem-6.
Problem-11
Check whether the given linked list is either NULL-terminated or not. If there is a cycle find the
start node of the loop.
Solution: The solution is an extension to the previous solution (Problem-9). After finding the loop in the linked
list, we initialize the to head of the linked list. From that point onwards both and moves
only one node at a time. The point at which they meet is the start of the loop. Generally we use this method for
removing the loops. Let and y be travelers such that y is walking twice as fast as (i.e. = 2). Further, let s
be the place where and first started walking at the same time. Then when x and y meet again, the distance
from to the start of the loop is the exact same distance from the present meeting place of and to the start of
the loop.
def detectCycleStart( self ) :
if None == self.head or None == self.head.next:
return None
# slow and fast both started at head after one step,
# slow is at self.head.next and fast is at self.head.next.next
slow = self.head.next
fast = slow.next
# each keep walking until they meet again.
while slow != fast:
slow = slow.next
try:
fast = fast.next.next
except AttributeError:
return None # no cycle if NoneType reached
# from self.head to beginning of loop is same as from fast to beginning of loop
slow = self.head
while slow != fast:
slow = slow.next
fast = fast.next
return slow # beginning of loop
Time Complexity: O(). Space Complexity: O(1).
Problem-12
From the previous discussion and problems we understand that the meeting of tortoise and
hare meeting concludes the existence of loop, but how does moving tortoise to beginning of linked list while
keeping the hare at meeting place, followed by moving both one step at a time make them meet at starting
point of cycle?
Solution: This problem is the heart of number theory. In Floyd cycle finding algorithm, notice that the tortoise
and the hare will meet when they are , where is the loop length. Furthermore, the tortoise is at the
79
Linked Lists
midpoint between the hare and the beginning of the sequence, because of the way they move. Therefore the
tortoise is away from the beginning of the sequence as well.
If we move both one step at a time, from the position of tortoise and from the start of the sequence, we know
that they will meet as soon as both are in the loop, since they are , a multiple of the loop length, apart.
One of them is already in the loop, so we just move the other one in single step until it enters the loop, keeping
the other away from it at all times.
Problem-13
In Floyd cycle finding algorithm, does it work if we use the steps 2 and 3 instead of 1 and 2?
Solution: Yes, but the complexity might be high. Trace out some example.
Problem-14
loop.
Check whether the given linked list is NULL-terminated. If there is a cycle find the length of the
Solution: This solution is also an extension to the basic cycle detection problem. After finding the loop in the
linked list, keep the as it is. keeps on moving until it again comes back to . While moving
, use a counter variable which increments at the rate of 1.
def findLoopLength( self ):
if None == self.head or None == self.head.next:
return 0
# slow and fast both started at head after one step,
# slow is at self.head.next and fast is at self.head.next.next
slow = self.head.next
fast = slow.next
# each keep walking until they meet again.
while slow != fast:
slow = slow.next
try:
fast = fast.next.next
except AttributeError:
return 0 # no cycle if NoneType reached
loopLength = 0
slow = slow.next
while slow != fast:
slow = slow.next
loopLength = loopLength + 1
return loopLength
Time Complexity: O(). Space Complexity: O(1).
Problem-15
Solution: Traverse the list and find a position for the element and insert it.
def orderedInsert(self,item):
current = self.head
previous = None
stop = False
while current != None and not stop:
if current.getData() > item:
stop = True
else:
previous = current
current = current.getNext()
temp = Node(item)
if previous == None:
temp.setNext(self.head)
self.head = temp
else:
temp.setNext(current)
previous.setNext(temp)
Time Complexity: O(). Space Complexity: O(1).
Problem-16
80
Linked Lists
Solution: This algorithm reverses this singly linked list in place, in O(). The function uses three pointers to
walk the list and reverse link direction between each pair of nodes.
# Iterative version
def reverseList(self):
last = None
current = self.head
while(current is not None):
nextNode = current.getNext()
current.setNext(last)
last = current
current = nextNode
self.head = last
Time Complexity: O(). Space Complexity: O(1).
Recursive version: We can find it easier to start from the bottom up, by asking and answering tiny questions
(this is the approach in The Little Lisper):
Solution: Brute-Force Approach: One easy solution is to compare every node pointer in the first list with every
other node pointer in the second list by which the matching node pointers will lead us to the intersecting node.
But, the time complexity in this case will O() which will be high.
Time Complexity: O(). Space Complexity: O(1).
Problem-18
Solution: No. Consider the following algorithm which is based on sorting and see why this algorithm fails.
Algorithm:
Take first list node pointers and keep in some array and sort them.
Take second list node pointers and keep in some array and sort them.
After sorting, use two indexes: one for first sorted array and other for second sorted array.
Start comparing values at the indexes and increment the index whichever has lower value (increment
only if the values are not equal).
81
Linked Lists
At any point, if we were able to find two indexes whose values are same then that indicates that those
two nodes are pointing to the same node and we return that node.
Time Complexity: Time for sorting lists + Time for scanning (for comparing)
= O() +O() +O( + ).
We need to consider the one that gives the maximum value.
Space Complexity: O(1).
Any problem with the above algorithm? Yes. In the algorithm, we are storing all the node pointers of both the
lists and sorting. But we are forgetting the fact that, there can be many repeated elements. This is because after
the merging point all node pointers are same for both the lists. The algorithm works fine only in one case and it
is when both lists have ending node at their merge point.
Problem-19
Solution: Yes.
Algorithm:
Select a list which has less number of nodes (If we do not know the lengths beforehand then select one
list randomly).
Now, traverse the other list and for each node pointer of this list check whether the same node pointer
exists in the hash table.
If there is a merge point for the given lists then we will definitely encounter the node pointer in the hash
table.
def findIntersectingNode( self, list1, list2 ):
intersect = {}
t = list1
while None != t:
intersect[t] = True
t = t.getNext()
# first duplicate is intersection
t = list2
while None != t:
if None != intersect.get( t ):
return t
t = t.getNext()
return None
Time Complexity: Time for creating the hash table + Time for scanning the second list = O() + O() (or O() +
O(), depends on which list we select for creating the hash table). But in both cases the time complexity is
same. Space Complexity: O() or O().
Problem-20
Solution: Yes.
Algorithm:
Create two stacks: one for the first list and one for the second list.
Traverse the first list and push all the node address on to the first stack.
Traverse the second list and push all the node address on to the second stack.
Now both stacks contain the node address of the corresponding lists.
If they are same, then pop the top elements from both the stacks and keep in some temporary variable
(since both node addresses are node, it is enough if we use one temporary variable).
Continue this process until top node addresses of the stacks are not same.
This point is the one where the lists merge into single list.
Solution: Yes. Using finding the first repeating number approach in an array (for algorithm refer
chapter).
Algorithm:
Create an array and keep all the next pointers of both the lists in the array.
82
Linked Lists
In the array find the first repeating element in the array [Refer chapter for algorithm].
The first repeating number indicates the merging point of the both lists.
Solution: Yes. By combining sorting and search techniques we can reduce the complexity.
Algorithm:
Create an array and keep all the next pointers of the first list in the array.
Then, for each of the second list element, search in the sorted array (let us assume that we are using
binary search which gives O()).
Since we are scanning the second list one by one, the first repeating element that appears in the array is
nothing but the merging point.
Time Complexity: Time for sorting + Time for searching = O((, )).
Space Complexity: O((, )).
Problem-23
Solution: Yes.
Efficient Approach:
Find lengths (L1 and L2) of both list -- O() + O() = O((, )).
Step in both lists in parallel until links to next node match -- O((, )).
Solution: Brute-Force Approach: For each of the node count how many nodes are there in the list and see
whether it is the middle.
Time Complexity: O(2 ). Space Complexity: O(1).
Problem-25
Solution: Yes.
Algorithm:
After finding the length, again scan the list and locate /2 node from the beginning.
Time Complexity: Time for finding the length of the list + Time for locating middle node = O() + O() O().
Space Complexity: O(1).
83
Linked Lists
Solution: Efficient Approach: Use two pointers. Move one pointer at twice the speed of the second. When the
first pointer reaches end of the list, the second pointer will be pointing to the middle node.
Note: If the list has even number of nodes, the middle node will be of /2.
def findMiddleNode( self) :
fastPtr = self.head
slowPtr = self.head
while (fastPtr != None):
fastPtr = fastPtr.getNext()
if (fastPtr == None):
return slowPtr
fastPtr = fastPtr.getNext()
slowPtr = slowPtr.getNext()
return slowPtr
Time Complexity: O(). Space Complexity: O(1).
Problem-28
Solution: Traverse recursively till end of the linked list. While coming back, start printing the elements. It is
natural to express many list operations using recursive methods. For example, the following is a recursive
algorithm for printing a list backwards:
1. Separate the list into two pieces: the first node (called the head); and the rest (called the tail).
2. Print the tail backward.
3. Print the head.
Of course, Step 2, the recursive call, assumes that we have a way of printing a list backward.
def printListFromEnd( self, list) :
if list == None:
return
head = list
tail = list.getNext()
self.printListFromEnd(tail)
print head.getData(),
if __name__ == "__main__":
linkedlst = LinkedList()
linkedlst.insertAtEnd(1)
linkedlst.insertAtEnd(2)
linkedlst.insertAtEnd(3)
linkedlst.insertAtEnd(4)
linkedlst.printList()
linkedlst.printListFromEnd(linkedlst.head)
Time Complexity: O(). Space Complexity: O() for Stack.
Problem-29
Solution: Use a 2 pointer. Take a pointer that moves at 2 [two nodes at a time]. At the end, if the length is
even then pointer will be NULL otherwise it will point to last node.
def isLinkedListLengthEven(self):
current = self.head
while current != None and current.getNext()!= None:
current = current.getNext().getNext()
if current == None:
return 1
return 0
84
Linked Lists
Problem-30
If the head of a linked list is pointing to element, then how will you get the elements before
element?
Solution: Use Memory Efficient Linked Lists [XOR Linked Lists].
Problem-31
Given two sorted Linked Lists, how to merge them into the third list in sorted order?
Store the mid and last pointers of the linked list using Floyd cycle finding algorithm.
15
40
Head
85
Linked Lists
15
Head
40
middle
def splitList(head):
fast = head
slow = head
while fast != None and fast.getNext() != None:
slow = slow.getNext()
fast = fast.getNext()
fast = fast.getNext()
middle = slow.getNext()
slow.setNext(None)
return head, middle
Time Complexity: O(). Space Complexity: O(1).
Problem-36
If we want to concatenate two linked lists which of the following gives O(1) complexity?
1) Singly linked lists
2) Doubly linked lists
3) Circular doubly linked lists
Solution: Circular Doubly Linked Lists. This is because for singly and doubly linked lists, we need to traverse
the first list till the end and append the second list. But in case of circular doubly linked lists we dont have to
traverse the lists.
Problem-37
Solution:
Algorithm:
1. Get the middle of the linked list.
2. Reverse the second half of the linked list.
3. Compare the first half and second half.
4. Construct the original linked list by reversing the second half again and attaching it back to the first
half.
Time Complexity: O(). Space Complexity: O(1).
Problem-38
For a given value ( > 0) reverse blocks of nodes in a list.
Example: Input: 1 2 3 4 5 6 7 8 9 10. Output for different values:
For = 2: 2 1 4 3 6 5 8 7 10 9
For = 3: 3 2 1 6 5 4 9 8 7 10
For = 4: 4 3 2 1 8 7 6 5 9 10
Solution:
Algorithm: This is an extension of swapping nodes in a linked list.
1)
2)
3)
4)
5)
6)
86
Linked Lists
end = end.getNext()
if end == None:
return temp.getNext()
nextBlock = end.getNext()
self.reverseList(begin,end)
previous.setNext(end)
begin.setNext(nextBlock)
previous = begin
def reverseList(self, start, end):
alreadyReversed = start
actual = start
nextNode = start.getNext()
while actual != end:
actual = nextNode
nextNode = nextNode.getNext()
actual.setNext(alreadyReversed)
alreadyReversed = actual
Problem-39
Solution: Yes. Create a linked list at the same time keep it in a hash table. For elements we have to keep all
the elements into hash table which gives preprocessing time of O(). To read any element we require only
constant time O(1) and to read elements we require 1 unit of time = units. Hence by using amortized
analysis we can say that element access can be performed within O(1) time.
Time Complexity O(1) [Amortized]. Space Complexity - O() for Hash Table.
Problem-40
Josephus Circle: Flavius Josephus was a famous Jewish historian of the first century, at the
time of the destruction of the Second Temple. According to legend, during the Jewish-Roman war he was
trapped in a cave with a group of forty soldiers surrounded by Romans. Preferring death to capture, the Jews
decided to form a circle and, proceeding around it, to kill every third person remaining until no one was left.
Josephus found the safe spot in the circle and thus stayed alive. Write a function josephus(n,m) that returns
a list of people, numbered from 0 to 1, in the order in which they are executed, every person in turn,
with the sole survivor as the last person in the list. That mean, find which person will be the last one
remaining (with rank 1).
Solution: Assume the input is a circular linked list with nodes and each node has a number (range 1 to )
associated with it. The head node has number 1 as data.
def getJosephusPosition(n, m):
class Node:
def __init__(self, data = None, next = None):
self.setData(data)
self.setNext(next)
#method for setting the data field of the node
def setData(self,data):
self.data = data
#method for getting the data field of the node
def getData(self):
return self.data
#method for setting the next field of the node
def setNext(self,next):
self.next = next
#method for getting the next field of the node
def getNext(self):
return self.next
#returns true if the node points to another node
def hasNext(self):
return self.next != None
answer = []
# initialize circular linked list
head = Node(0)
prev = head
for n in range(1, n):
currentNode = Node(n)
87
Linked Lists
prev.setNext(currentNode)
prev = currentNode
prev.setNext(head) # set the last node to point to the front (circular list)
# extract items from linked list in proper order
currentNode = head
counter = 0
while currentNode.getNext() != currentNode:
counter += 1
if counter == m:
counter = 0
prev.setNext(currentNode.next)
answer.append(currentNode.getData())
else:
prev = currentNode
currentNode = currentNode.getNext()
answer.append(currentNode.getData())
return answer
print str(getJosephusPosition(6, 3))
Problem-41
Given a linked list consists of data, next pointer and also a random pointer which points to a
random node of the list. Give an algorithm for cloning the list.
Solution: We can use a hash table to associate newly created nodes with the instances of node in the given list.
Algorithm:
Scan the original list and for each node , create a new node with data of , then store the pair (, )
in hash table using as a key. Note that during this scan set and to and we
will fix them in the next scan.
Now for each node in the original list we have a copy stored in our hash table. We scan again the
original list and set the pointers buildings the new list.
class Node:
def __init__(self, data):
self.setData(data)
self.setNext(None)
self.setRand(None)
#method for setting the data field of the node
def setData(self,data):
self.data = data
#method for getting the data field of the node
def getData(self):
return self.data
#method for setting the next field of the node
def setNext(self,next):
self.next = next
#method for setting the next field of the node
def setRand(self,rand):
self.rand = rand
#method for getting the next field of the node
def getRand(self):
return self.rand
#method for getting the next field of the node
def getNext(self):
return self.next
#returns true if the node points to another node
def hasNext(self):
return self.next != None
def cloneLinkedList(old):
if not old:
return
old_copy = old
root = Node(old.getData())
prev = root
88
Linked Lists
temp = None
old = old.getNext()
mapping = {}
while old:
temp = Node(old.getData())
mapping[old] = temp
prev.setNext(temp)
prev = temp
old = old.getNext()
old = old_copy
temp = root
while old:
temp.setRand(mapping[old.rand])
temp = temp.getNext()
old = old.getNext()
return root
Time Complexity: O(). Space Complexity: O().
Problem-42
Solution: Yes. Follow the comments in below code and trace out.
# Definition for singly-linked list with a random pointer.
class RandomListNode:
def __init__(self, data):
self.data = data
self.next = None
self.random = None
class Solution:
# @param head, a RandomListNode
# @return a RandomListNode
def copyRandomList(self, head):
if None == head:
return None
save_list = [ ]
p1 = head
while None != p1:
save_list.append(p1)
p1 = p1.next
new_head = RandomListNode(-1)
new_head.next = head
first = new_head
second = head
copyHead = RandomListNode(-1)
copyFirst = copyHead
copySecond = None
while None != first:
copySecond = RandomListNode(second.data) if None != second else None
copyFirst.next = copySecond
copyFirst = copyFirst.next
first = first.next
if None != second:
second = second.next
p1 = head
p1_tail = head.next
p2 = copyHead.next
while None != p1:
p1_tail = p1.next
p1.next = p2
p2.random = p1
p1 = p1_tail
89
Linked Lists
Problem-43
Given a linked list with even and odd numbers, create an algorithm for making changes to list
in such a way that all even numbers appear at the beginning.
Solution: To solve this problem, we can use the splitting logic. While traversing the list, split the linked list into
two: one contains all even nodes and other containing all odd nodes. Now, to get the final list, we can simply
append the odd node linked list after the even node linked list.
To split the linked list, traverse the original linked list and move all odd nodes to a separate linked list of all odd
nodes. At the end of loop, the original list will have all the even nodes and the odd node list will have all the odd
nodes. To keep the ordering of all nodes same, we must insert all the odd nodes at the end of the odd node list.
Time Complexity: O(). Space Complexity: O(1).
Problem-44
In a linked list with nodes, the time taken to insert an element after an element pointed by
some pointer is
(A) O(1)
(B) O()
(C) O()
(D) O(1)
Solution: A.
Problem-45
Find modular node: Given a singly linked list, write a function to find the last element from the
beginning whose % == 0, where is the number of elements in the list and is an integer constant. For
example, if = 19 and = 3 then we should return 18 node.
Solution: For this problem the value of is not known in advance.
def modularNodeFromBegin(self, k):
currentNode = self.head
modularNode = None
i=1
if k <= 0:
return None;
while currentNode != None:
if i%k == 0:
modularNode = currentNode
i=i+1
currentNode = currentNode.getNext()
print ( modularNode.getData())
Time Complexity: O(). Space Complexity: O(1).
Problem-46
Find modular node from end: Given a singly linked list, write a function to find the first from
the end whose % == 0, where is the number of elements in the list and is an integer constant. If = 19
and = 3 then we should return 16 node.
Solution: For this problem the value of is not known in advance and it is same as finding the element from
end of the linked list.
def modularNodeFromEnd(self, k):
currentNode = self.head
modularNode = self.head
i=0
if k <= 0:
return None;
while i < k and currentNode != None:
i=i+1
90
Linked Lists
element, where
Problem-48
Find node: Given a singly linked list, write a function to find the
the number of elements in the list. Assume the value of is not known in advance.
element, where is
91
Linked Lists
if list1.getData()<list2.getData():
pointer.setNext(list1)
list1 = list1.getNext()
else:
pointer.setNext(list2)
list2 = list2.getNext()
pointer = pointer.getNext()
if list1 == None:
pointer.setNext(list2)
else:
pointer.setNext(list1)
return temp.getNext()
Time Complexity: The loop takes O((, )) time as it will run for (, ) times. The other steps run in
O(1). Therefore the total time complexity is O((, )).
Space Complexity: O(1).
Problem-50
Solution: Median is the middle number in a sorted list of numbers (if we have odd number of elements). If we
have even number of elements, median is the average of two middle numbers in a sorted list of numbers.
We can solve this problem with linked lists (with both sorted and unsorted linked lists).
, let us try with linked list. In an unsorted linked list, we can insert the element either at the head
or at the tail. The disadvantage with this approach is that, finding the median takes O(). Also, the insertion
operation takes O(1).
Now, let us with linked list. We can find the median in O(1) time if we keep track of the middle elements.
Insertion to a particular location is also O(1) in any linked list. But, finding the right location to insert is not
O() as in sorted array, it is instead O() because we cant perform binary search in a linked list even if it is
sorted.
So, using a sorted linked list doesnt worth the effort, insertion is O() and finding median is O(1), same as the
sorted array. In sorted array insertion is linear due to shifting, here its linear because we cant do binary search
in a linked list.
Note: For efficient algorithm refer chapter.
Problem-51
Given a linked list, how do you modify it such that all even numbers appear before all the odd
numbers in the modified linked list?
Solution:
def exchangeEvenOddList(head):
# initializing the odd and even list headers
oddList = evenList =None
# creating tail variables for both the list
oddListEnd = evenListEnd = None
itr=head
if( head == None ):
return
else:
while( itr != None ):
if( itr.data % 2 == 0 ):
if( evenList == NULL ):
# first even node
evenList = evenListEnd = itr
else:
# inserting the node at the end of linked list
evenListEnd.next = itr
evenListEnd = itr
else:
if( oddList == NULL ):
# first odd node
oddList = oddListEnd = itr
else:
92
Linked Lists
93
Linked Lists
Write code for finding the sum of all data values from linked list with recursion.
Solution: One of the basic operations we perform on linked lists (as we do with lists) is to iterate over them,
processing alst their values. The following function computes the sum of the values in a linked list.
def linkedListSum(lst):
sum = 0
while lst != None:
sum += lst.
lst = lst.getNext()
return sum
Lots of code that traverses (iterates over) linked lists looks similar. In class we will go over (hand simulate) how
this code processes the linked list above, with the call (x) and see exactly how it is that we visit
each node in the linked list and stop processing it at the end.
We can also define linked lists recursively and use such a definition to help us write functions that recursively
process linked lists.
1)
2)
So None is a linked list (of 0 values); a list node whose next is is a linked list (of 1 value); a list node whose
next is a list node whose next is is a linked list (of 2 values); etc.
So, we can recursively process a linked list by processing its first node and then recursively processing the (one
smaller) linked list they refer to; recursion ends at None (which is the base case: the smallest linked list). We can
recursively compute the sum of linked list by
def linkedListSum(self, lst):
if lst == None:
return 0
else:
return lst.getData() + linkedListSum(lst.getNext())
An even simpler traversal of linked lists computes their length. Here are the iterative and recursive methods.
def listLength(lst):
count = 0
while lst != None:
count += 1
lst = lst.getNext()
return count
def listLengthRecursive(lst):
if lst == None:
return 0
else:
return 1 + listLengthRecursive(lst.getNext())
These are simpler than the function: rather than adding the value of each list node, these add 1 to
a count for each list node, ultimately computing the number of list nodes in the entire linked list: its length.
Problem-54
Given a sorted linked list, write a program to remove duplicates from it.
94