Skip to content

Commit eaa735f

Browse files
authored
Merge pull request #39 from miguelHx/miguel_2.3_delete_middle_node
Miguel 2.3 - Delete Middle Node [Python]
2 parents f49d803 + e449e0d commit eaa735f

File tree

1 file changed

+159
-0
lines changed

1 file changed

+159
-0
lines changed
Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
"""
2+
Python version 3.7.0
3+
2.3 - Delete Middle Node
4+
Implement an algorithm to delete a node
5+
in the middle (i.e., any node but the
6+
first and last node, not necessarily
7+
the exact middle) of a singly linked list,
8+
given only access to that node
9+
EXAMPLE
10+
Input: the node c from the linked list
11+
a -> b -> c -> d -> e -> f
12+
Result: nothing is returned, but the new
13+
linked list looks like
14+
a -> b -> d -> e -> f
15+
"""
16+
import unittest
17+
18+
19+
class Node:
20+
def __init__(self, d: int):
21+
self.data = d
22+
self.next = None
23+
24+
def __repr__(self):
25+
return self.__str__()
26+
27+
def __str__(self):
28+
return '<Node Value: {}>'.format(self.data)
29+
30+
def __eq__(self, other: object):
31+
if not isinstance(other, Node):
32+
return NotImplemented
33+
return self.data == other.data
34+
35+
36+
class LinkedList:
37+
def __init__(self, *numbers: int):
38+
self.head = None
39+
self.tail = None
40+
self.size = 0
41+
for num in numbers:
42+
self.append_to_tail(num)
43+
44+
def append_to_tail(self, d: int) -> None:
45+
if self.head is None:
46+
self.head = Node(d)
47+
self.tail = self.head
48+
else:
49+
end = Node(d)
50+
self.tail.next = end
51+
self.tail = end
52+
self.size += 1
53+
54+
def append_to_head(self, d: int) -> None:
55+
new_head = Node(d)
56+
new_head.next = self.head
57+
self.head = new_head
58+
self.size += 1
59+
60+
def get_node_at(self, index: int) -> Node:
61+
if index < 0 or index >= self.size:
62+
raise IndexError('list index out of range')
63+
n = self.head
64+
for i in range(self.size):
65+
if i == index:
66+
return n
67+
n = n.next
68+
69+
def __repr__(self):
70+
return self.__str__()
71+
72+
def __str__(self):
73+
if self.head is None:
74+
return '<empty>'
75+
ll = []
76+
n = self.head
77+
while n.next is not None:
78+
ll.append('{} -> '.format(n.data))
79+
n = n.next
80+
ll.append(str(n.data))
81+
return ''.join(ll)
82+
83+
def __eq__(self, other: object):
84+
if not isinstance(other, LinkedList):
85+
return NotImplemented
86+
a = self.head
87+
b = other.head
88+
while a is not None and b is not None:
89+
if a.data != b.data:
90+
return False
91+
# otherwise, advance both pointers
92+
a = a.next
93+
b = b.next
94+
return a is None and b is None
95+
96+
97+
def delete_middle_node(ll: LinkedList, node: Node) -> None:
98+
"""
99+
delete_middle_node will delete a node from
100+
a singly linked list. The node can be any
101+
node within the linked list that is NOT the
102+
head or the tail.
103+
We will be comparing the address of
104+
the input node with the address of each
105+
node in the linked list.
106+
Runtime: O(N)
107+
Space Complexity: O(1)
108+
:param ll: an input linked list
109+
:param node: pointer to a node in ll
110+
:return: a linked list with/wo having deleted node
111+
"""
112+
if node is ll.head or node is ll.tail:
113+
raise ValueError('node cannot be head or tail of linked list')
114+
n = ll.head
115+
while n.next is not None:
116+
if n.next is node:
117+
n.next = n.next.next
118+
return
119+
n = n.next
120+
121+
122+
class TestDeleteMiddleNode(unittest.TestCase):
123+
124+
def setUp(self):
125+
self.test_cases = [
126+
(
127+
LinkedList(1, 2, 3, 4, 5, 6),
128+
2,
129+
LinkedList(1, 2, 4, 5, 6),
130+
),
131+
(
132+
LinkedList(3, 6, 2, 1, 7, 8),
133+
1,
134+
LinkedList(3, 2, 1, 7, 8),
135+
),
136+
(
137+
LinkedList(-100, 200, 65, 22, 1),
138+
3,
139+
LinkedList(-100, 200, 65, 1),
140+
)
141+
]
142+
143+
def test_delete_middle_node(self):
144+
for ll, node_index, expected in self.test_cases:
145+
delete_middle_node(ll, ll.get_node_at(node_index))
146+
self.assertEqual(ll, expected, msg=(ll, node_index, expected))
147+
148+
def test_delete_middle_node_value_error(self):
149+
ll = LinkedList(1, 2, 3, 4)
150+
head = ll.head
151+
tail = ll.tail
152+
with self.assertRaises(ValueError, msg=(ll, ll.head)):
153+
delete_middle_node(ll, head)
154+
with self.assertRaises(ValueError, msg=(ll, ll.tail)):
155+
delete_middle_node(ll, tail)
156+
157+
158+
if __name__ == '__main__':
159+
unittest.main()

0 commit comments

Comments
 (0)