dsa.singlylinkedlist

Module containing singly linked list class.

  1""" Module containing singly linked list class. """
  2
  3class Node:
  4    """ 
  5    A singly linked list node implementation.
  6    """
  7    def __init__(self, value):
  8        """ 
  9        A singly linked list node.
 10        Args:
 11            value: The value of the node.
 12        """
 13        #: value of the node
 14        self.value = value
 15        #: reference to the next node
 16        self.next = None
 17
 18class LinkedList:
 19    """ 
 20    A singly linked list implementation.
 21    """
 22    def __init__(self, head: Node=None, tail: Node=None, count: int=0):
 23        """ 
 24        Initialize a singly linked list.
 25        
 26        if only the head node is specified, tail is set to the head node and count is automatically set to 0
 27        if both head and tail nodes are specified, count should be specified as well
 28        
 29        Args:
 30            head: The reference to the head node.
 31            tail: The reference to the tail node.
 32            count: The number of nodes in the linked list.
 33
 34        """        
 35        self.head = head
 36        if head and tail is None:
 37            self.tail = head
 38            self.count = 1
 39        else:
 40            self.tail = tail
 41            self.count = count
 42
 43    @classmethod
 44    def from_list(cls, mylist=None):
 45        """
 46        Create a linked list from a list.
 47
 48        Args:
 49            mylist: A list or container to convert from.
 50        
 51        Returns:
 52            A  linked list containing the items from mylist.
 53        """
 54        ll = cls()
 55        for value in mylist:
 56            ll.append(value)
 57
 58        return ll
 59    
 60    def to_list(self) -> list:
 61        """
 62        Create a list with contents of the linked list.
 63
 64        Returns:
 65            List with contents of linked list.
 66        """
 67        mylist = []
 68        current = self.head
 69        while current:
 70            mylist.append(current.value)
 71            current = current.next
 72        return mylist
 73
 74    def print(self):
 75        """
 76        Print the contents of the linked list.
 77        """
 78        current = self.head
 79        while current:
 80            print(current.value, end=" ")
 81            current = current.next
 82        print()
 83
 84            
 85    def __repr__(self):
 86        """
 87        Return a string representation of the linked list.
 88
 89        Returns:
 90            A string representation of the linked list.
 91        """
 92        s = ""
 93        current = self.head
 94        while current:
 95            s += str(current.value) + " "
 96            current = current.next
 97
 98        return f"[ {s}] Count: {self.count}"
 99    
100    def __getitem__(self, index: int) -> Node:
101        """ 
102        Return value at a specified index. Raise IndexError if index is out of bounds.
103        
104        Args:
105            index: Index of value.
106
107        Raises:
108            IndexError: If index is out of bounds.
109
110        Returns:
111            The value at the specified index.
112        """        
113        i = 0
114        current = self.head
115        while current:
116            if i == index:
117                return current.value
118            current = current.next
119            i += 1
120        raise IndexError("Index Out of Bounds")
121
122    def __len__(self) -> int:
123        """
124        Return the number of elements in the linked list.
125        """
126        return self.count
127    
128    def is_empty(self) -> bool:
129        """
130        Check if the linked list is empty.
131        """
132        return self.count == 0
133        
134    def search(self, value) -> int:
135        """
136        Search for a value in the linked list.
137
138        Args:
139            value: The value to search for.
140
141        Returns:
142            Return index of found value.
143        
144        Raises:
145            Exception: If value is not found.
146        """
147        i = 0
148        current = self.head
149        while current:
150            if current.value == value:
151                return i
152            i += 1
153            current = current.next
154        raise Exception("Value not found")
155    
156    def insert(self, index: int, value):
157        """
158        Insert a value at a specified index. Raise exception if index is out of bounds.
159
160        Args:
161            index (int): The index to insert a value.
162            value: The value to append.
163
164        Returns:
165            None
166
167        Raises:
168            IndexError: If index is out of bounds.
169        """
170        i = 0
171        
172        # insert front
173        if index == 0:
174            self.prepend(value)
175            return
176        elif index == self.count: # insert at end
177            self.append(value)
178            return
179        elif index > self.count:
180            raise IndexError("Index Out of Bounds")
181        
182        # find node to insert after
183        current = self.head
184        while index < i or current:
185            i += 1
186            if i == index:
187                break
188            current = current.next
189        
190        if index > i:
191            raise IndexError("Index Out of Bounds")
192
193        new_node = Node(value)
194        tmp = current.next
195        current.next = new_node
196        new_node.next = tmp
197        self.count += 1
198
199    def prepend(self, value):
200        """
201        Place a value at the beginning of the linked list.
202
203        Args:
204            value: A value to append.
205
206        Returns:
207            None
208        """
209        new_node = Node(value)
210        new_node.next = self.head
211        self.head = new_node
212        self.count += 1
213        
214    def append(self, value):
215        """
216        Place a value at the end of the linked list.
217
218        Args:
219            value: A value to append.
220
221        Returns:
222            None
223        
224        Raises:
225            IndexError: If linked list is empty or index is not found.
226        """
227        if self.head is None:
228            self.head = Node(value)
229            if self.count == 0:
230                self.tail = self.head
231            self.count += 1
232            return
233
234        # go to the end of the list
235        new_node = Node(value)
236        self.tail.next = new_node
237        self.tail = new_node
238        
239        self.count += 1
240
241    def delete(self, index: int):
242        """
243        Delete a node at a specified index. Raise IndexError if linked list is empty or if index is not found.
244
245        Args:
246            index: Index of element to be deleted.
247        
248        Returns:
249            None
250            
251        Raises:
252            IndexError: If linked list is empty or index is not found.
253        """
254        if index == 0:
255            self.delete_head()
256            return
257        elif index + 1 == self.count:
258            self.delete_tail()
259            return
260
261        i = 0
262        current = self.head
263        prev = None
264        while current:
265            if index == i:
266                if prev is not None:
267                    prev.next = current.next
268                else:
269                    self.head = current.next
270                self.count -= 1
271                return
272            i += 1
273            prev = current
274            current = current.next
275        raise IndexError("Index not found")
276
277    def delete_head(self):
278        """
279        Delete the head node in the linked list. Raise IndexError if linked list is empty.
280
281        Returns:
282            None
283
284        Raises:
285            IndexError: If linked list is empty.
286        """
287        if self.head is None:
288            raise IndexError("LinkedList is Empty")
289        self.head = self.head.next
290        self.count -= 1
291
292    def delete_tail(self):
293        """
294        Delete the last node in the linked list. Raise IndexError if linked list is empty.
295
296        Returns:
297            None
298            
299        Raises:
300            IndexError: If linked list is empty.
301        """
302        if self.head is None:
303            raise IndexError("LinkedList is Empty")
304        
305        if self.head.next is None:
306            self.head = None
307            self.count -= 1
308            return
309        
310        current = self.head
311        while current.next.next:
312            current = current.next
313        
314        current.next = None
315        self.tail = current
316        self.count -= 1
317    
318if __name__ == "__main__":
319    ll = LinkedList.from_list(range(10))
320    ll = LinkedList()
321
322    for _ in range(15):
323        ll.append(_)
324    assert (ll.head.value == 0)
325    assert (ll.tail.value == 14)
326    assert (ll.count == 15)
327
328    print(ll.to_list())
329    ll.insert(1, -1)
330    print(ll.to_list())
331    assert (ll[1] == -1)
332#    self.assertEqual(ll.count, 16)
333    ll.insert(0, -2)
334#    ll.prepend(-2)
335    print(ll.to_list())
336    assert (ll[0] == -2)
class Node:
 4class Node:
 5    """ 
 6    A singly linked list node implementation.
 7    """
 8    def __init__(self, value):
 9        """ 
10        A singly linked list node.
11        Args:
12            value: The value of the node.
13        """
14        #: value of the node
15        self.value = value
16        #: reference to the next node
17        self.next = None

A singly linked list node implementation.

Node(value)
 8    def __init__(self, value):
 9        """ 
10        A singly linked list node.
11        Args:
12            value: The value of the node.
13        """
14        #: value of the node
15        self.value = value
16        #: reference to the next node
17        self.next = None

A singly linked list node. Args: value: The value of the node.

value
next
class LinkedList:
 19class LinkedList:
 20    """ 
 21    A singly linked list implementation.
 22    """
 23    def __init__(self, head: Node=None, tail: Node=None, count: int=0):
 24        """ 
 25        Initialize a singly linked list.
 26        
 27        if only the head node is specified, tail is set to the head node and count is automatically set to 0
 28        if both head and tail nodes are specified, count should be specified as well
 29        
 30        Args:
 31            head: The reference to the head node.
 32            tail: The reference to the tail node.
 33            count: The number of nodes in the linked list.
 34
 35        """        
 36        self.head = head
 37        if head and tail is None:
 38            self.tail = head
 39            self.count = 1
 40        else:
 41            self.tail = tail
 42            self.count = count
 43
 44    @classmethod
 45    def from_list(cls, mylist=None):
 46        """
 47        Create a linked list from a list.
 48
 49        Args:
 50            mylist: A list or container to convert from.
 51        
 52        Returns:
 53            A  linked list containing the items from mylist.
 54        """
 55        ll = cls()
 56        for value in mylist:
 57            ll.append(value)
 58
 59        return ll
 60    
 61    def to_list(self) -> list:
 62        """
 63        Create a list with contents of the linked list.
 64
 65        Returns:
 66            List with contents of linked list.
 67        """
 68        mylist = []
 69        current = self.head
 70        while current:
 71            mylist.append(current.value)
 72            current = current.next
 73        return mylist
 74
 75    def print(self):
 76        """
 77        Print the contents of the linked list.
 78        """
 79        current = self.head
 80        while current:
 81            print(current.value, end=" ")
 82            current = current.next
 83        print()
 84
 85            
 86    def __repr__(self):
 87        """
 88        Return a string representation of the linked list.
 89
 90        Returns:
 91            A string representation of the linked list.
 92        """
 93        s = ""
 94        current = self.head
 95        while current:
 96            s += str(current.value) + " "
 97            current = current.next
 98
 99        return f"[ {s}] Count: {self.count}"
100    
101    def __getitem__(self, index: int) -> Node:
102        """ 
103        Return value at a specified index. Raise IndexError if index is out of bounds.
104        
105        Args:
106            index: Index of value.
107
108        Raises:
109            IndexError: If index is out of bounds.
110
111        Returns:
112            The value at the specified index.
113        """        
114        i = 0
115        current = self.head
116        while current:
117            if i == index:
118                return current.value
119            current = current.next
120            i += 1
121        raise IndexError("Index Out of Bounds")
122
123    def __len__(self) -> int:
124        """
125        Return the number of elements in the linked list.
126        """
127        return self.count
128    
129    def is_empty(self) -> bool:
130        """
131        Check if the linked list is empty.
132        """
133        return self.count == 0
134        
135    def search(self, value) -> int:
136        """
137        Search for a value in the linked list.
138
139        Args:
140            value: The value to search for.
141
142        Returns:
143            Return index of found value.
144        
145        Raises:
146            Exception: If value is not found.
147        """
148        i = 0
149        current = self.head
150        while current:
151            if current.value == value:
152                return i
153            i += 1
154            current = current.next
155        raise Exception("Value not found")
156    
157    def insert(self, index: int, value):
158        """
159        Insert a value at a specified index. Raise exception if index is out of bounds.
160
161        Args:
162            index (int): The index to insert a value.
163            value: The value to append.
164
165        Returns:
166            None
167
168        Raises:
169            IndexError: If index is out of bounds.
170        """
171        i = 0
172        
173        # insert front
174        if index == 0:
175            self.prepend(value)
176            return
177        elif index == self.count: # insert at end
178            self.append(value)
179            return
180        elif index > self.count:
181            raise IndexError("Index Out of Bounds")
182        
183        # find node to insert after
184        current = self.head
185        while index < i or current:
186            i += 1
187            if i == index:
188                break
189            current = current.next
190        
191        if index > i:
192            raise IndexError("Index Out of Bounds")
193
194        new_node = Node(value)
195        tmp = current.next
196        current.next = new_node
197        new_node.next = tmp
198        self.count += 1
199
200    def prepend(self, value):
201        """
202        Place a value at the beginning of the linked list.
203
204        Args:
205            value: A value to append.
206
207        Returns:
208            None
209        """
210        new_node = Node(value)
211        new_node.next = self.head
212        self.head = new_node
213        self.count += 1
214        
215    def append(self, value):
216        """
217        Place a value at the end of the linked list.
218
219        Args:
220            value: A value to append.
221
222        Returns:
223            None
224        
225        Raises:
226            IndexError: If linked list is empty or index is not found.
227        """
228        if self.head is None:
229            self.head = Node(value)
230            if self.count == 0:
231                self.tail = self.head
232            self.count += 1
233            return
234
235        # go to the end of the list
236        new_node = Node(value)
237        self.tail.next = new_node
238        self.tail = new_node
239        
240        self.count += 1
241
242    def delete(self, index: int):
243        """
244        Delete a node at a specified index. Raise IndexError if linked list is empty or if index is not found.
245
246        Args:
247            index: Index of element to be deleted.
248        
249        Returns:
250            None
251            
252        Raises:
253            IndexError: If linked list is empty or index is not found.
254        """
255        if index == 0:
256            self.delete_head()
257            return
258        elif index + 1 == self.count:
259            self.delete_tail()
260            return
261
262        i = 0
263        current = self.head
264        prev = None
265        while current:
266            if index == i:
267                if prev is not None:
268                    prev.next = current.next
269                else:
270                    self.head = current.next
271                self.count -= 1
272                return
273            i += 1
274            prev = current
275            current = current.next
276        raise IndexError("Index not found")
277
278    def delete_head(self):
279        """
280        Delete the head node in the linked list. Raise IndexError if linked list is empty.
281
282        Returns:
283            None
284
285        Raises:
286            IndexError: If linked list is empty.
287        """
288        if self.head is None:
289            raise IndexError("LinkedList is Empty")
290        self.head = self.head.next
291        self.count -= 1
292
293    def delete_tail(self):
294        """
295        Delete the last node in the linked list. Raise IndexError if linked list is empty.
296
297        Returns:
298            None
299            
300        Raises:
301            IndexError: If linked list is empty.
302        """
303        if self.head is None:
304            raise IndexError("LinkedList is Empty")
305        
306        if self.head.next is None:
307            self.head = None
308            self.count -= 1
309            return
310        
311        current = self.head
312        while current.next.next:
313            current = current.next
314        
315        current.next = None
316        self.tail = current
317        self.count -= 1

A singly linked list implementation.

LinkedList( head: Node = None, tail: Node = None, count: int = 0)
23    def __init__(self, head: Node=None, tail: Node=None, count: int=0):
24        """ 
25        Initialize a singly linked list.
26        
27        if only the head node is specified, tail is set to the head node and count is automatically set to 0
28        if both head and tail nodes are specified, count should be specified as well
29        
30        Args:
31            head: The reference to the head node.
32            tail: The reference to the tail node.
33            count: The number of nodes in the linked list.
34
35        """        
36        self.head = head
37        if head and tail is None:
38            self.tail = head
39            self.count = 1
40        else:
41            self.tail = tail
42            self.count = count

Initialize a singly linked list.

if only the head node is specified, tail is set to the head node and count is automatically set to 0 if both head and tail nodes are specified, count should be specified as well

Args: head: The reference to the head node. tail: The reference to the tail node. count: The number of nodes in the linked list.

head
@classmethod
def from_list(cls, mylist=None):
44    @classmethod
45    def from_list(cls, mylist=None):
46        """
47        Create a linked list from a list.
48
49        Args:
50            mylist: A list or container to convert from.
51        
52        Returns:
53            A  linked list containing the items from mylist.
54        """
55        ll = cls()
56        for value in mylist:
57            ll.append(value)
58
59        return ll

Create a linked list from a list.

Args: mylist: A list or container to convert from.

Returns: A linked list containing the items from mylist.

def to_list(self) -> list:
61    def to_list(self) -> list:
62        """
63        Create a list with contents of the linked list.
64
65        Returns:
66            List with contents of linked list.
67        """
68        mylist = []
69        current = self.head
70        while current:
71            mylist.append(current.value)
72            current = current.next
73        return mylist

Create a list with contents of the linked list.

Returns: List with contents of linked list.

def print(self):
75    def print(self):
76        """
77        Print the contents of the linked list.
78        """
79        current = self.head
80        while current:
81            print(current.value, end=" ")
82            current = current.next
83        print()

Print the contents of the linked list.

def is_empty(self) -> bool:
129    def is_empty(self) -> bool:
130        """
131        Check if the linked list is empty.
132        """
133        return self.count == 0

Check if the linked list is empty.

def search(self, value) -> int:
135    def search(self, value) -> int:
136        """
137        Search for a value in the linked list.
138
139        Args:
140            value: The value to search for.
141
142        Returns:
143            Return index of found value.
144        
145        Raises:
146            Exception: If value is not found.
147        """
148        i = 0
149        current = self.head
150        while current:
151            if current.value == value:
152                return i
153            i += 1
154            current = current.next
155        raise Exception("Value not found")

Search for a value in the linked list.

Args: value: The value to search for.

Returns: Return index of found value.

Raises: Exception: If value is not found.

def insert(self, index: int, value):
157    def insert(self, index: int, value):
158        """
159        Insert a value at a specified index. Raise exception if index is out of bounds.
160
161        Args:
162            index (int): The index to insert a value.
163            value: The value to append.
164
165        Returns:
166            None
167
168        Raises:
169            IndexError: If index is out of bounds.
170        """
171        i = 0
172        
173        # insert front
174        if index == 0:
175            self.prepend(value)
176            return
177        elif index == self.count: # insert at end
178            self.append(value)
179            return
180        elif index > self.count:
181            raise IndexError("Index Out of Bounds")
182        
183        # find node to insert after
184        current = self.head
185        while index < i or current:
186            i += 1
187            if i == index:
188                break
189            current = current.next
190        
191        if index > i:
192            raise IndexError("Index Out of Bounds")
193
194        new_node = Node(value)
195        tmp = current.next
196        current.next = new_node
197        new_node.next = tmp
198        self.count += 1

Insert a value at a specified index. Raise exception if index is out of bounds.

Args: index (int): The index to insert a value. value: The value to append.

Returns: None

Raises: IndexError: If index is out of bounds.

def prepend(self, value):
200    def prepend(self, value):
201        """
202        Place a value at the beginning of the linked list.
203
204        Args:
205            value: A value to append.
206
207        Returns:
208            None
209        """
210        new_node = Node(value)
211        new_node.next = self.head
212        self.head = new_node
213        self.count += 1

Place a value at the beginning of the linked list.

Args: value: A value to append.

Returns: None

def append(self, value):
215    def append(self, value):
216        """
217        Place a value at the end of the linked list.
218
219        Args:
220            value: A value to append.
221
222        Returns:
223            None
224        
225        Raises:
226            IndexError: If linked list is empty or index is not found.
227        """
228        if self.head is None:
229            self.head = Node(value)
230            if self.count == 0:
231                self.tail = self.head
232            self.count += 1
233            return
234
235        # go to the end of the list
236        new_node = Node(value)
237        self.tail.next = new_node
238        self.tail = new_node
239        
240        self.count += 1

Place a value at the end of the linked list.

Args: value: A value to append.

Returns: None

Raises: IndexError: If linked list is empty or index is not found.

def delete(self, index: int):
242    def delete(self, index: int):
243        """
244        Delete a node at a specified index. Raise IndexError if linked list is empty or if index is not found.
245
246        Args:
247            index: Index of element to be deleted.
248        
249        Returns:
250            None
251            
252        Raises:
253            IndexError: If linked list is empty or index is not found.
254        """
255        if index == 0:
256            self.delete_head()
257            return
258        elif index + 1 == self.count:
259            self.delete_tail()
260            return
261
262        i = 0
263        current = self.head
264        prev = None
265        while current:
266            if index == i:
267                if prev is not None:
268                    prev.next = current.next
269                else:
270                    self.head = current.next
271                self.count -= 1
272                return
273            i += 1
274            prev = current
275            current = current.next
276        raise IndexError("Index not found")

Delete a node at a specified index. Raise IndexError if linked list is empty or if index is not found.

Args: index: Index of element to be deleted.

Returns: None

Raises: IndexError: If linked list is empty or index is not found.

def delete_head(self):
278    def delete_head(self):
279        """
280        Delete the head node in the linked list. Raise IndexError if linked list is empty.
281
282        Returns:
283            None
284
285        Raises:
286            IndexError: If linked list is empty.
287        """
288        if self.head is None:
289            raise IndexError("LinkedList is Empty")
290        self.head = self.head.next
291        self.count -= 1

Delete the head node in the linked list. Raise IndexError if linked list is empty.

Returns: None

Raises: IndexError: If linked list is empty.

def delete_tail(self):
293    def delete_tail(self):
294        """
295        Delete the last node in the linked list. Raise IndexError if linked list is empty.
296
297        Returns:
298            None
299            
300        Raises:
301            IndexError: If linked list is empty.
302        """
303        if self.head is None:
304            raise IndexError("LinkedList is Empty")
305        
306        if self.head.next is None:
307            self.head = None
308            self.count -= 1
309            return
310        
311        current = self.head
312        while current.next.next:
313            current = current.next
314        
315        current.next = None
316        self.tail = current
317        self.count -= 1

Delete the last node in the linked list. Raise IndexError if linked list is empty.

Returns: None

Raises: IndexError: If linked list is empty.