-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathlinked_list.py
More file actions
136 lines (104 loc) · 3.31 KB
/
linked_list.py
File metadata and controls
136 lines (104 loc) · 3.31 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
"""
Linked List Data Structure
A linked list is a linear data structure where elements are stored in nodes,
and each node points to the next node. Unlike arrays, linked lists don't have
contiguous memory allocation.
Time Complexity:
- Access: O(n)
- Insertion at head: O(1)
- Insertion at tail: O(1) with tail pointer, O(n) without
- Deletion: O(1) if node is known, O(n) to find node
- Search: O(n)
Space Complexity: O(n)
"""
class Node:
"""Node class for linked list."""
def __init__(self, data):
self.data = data
self.next = None
class LinkedList:
"""Singly linked list implementation."""
def __init__(self):
self.head = None
self.size = 0
def is_empty(self):
"""Check if list is empty."""
return self.head is None
def append(self, data):
"""Add element at the end of the list."""
new_node = Node(data)
if self.head is None:
self.head = new_node
else:
current = self.head
while current.next:
current = current.next
current.next = new_node
self.size += 1
def prepend(self, data):
"""Add element at the beginning of the list."""
new_node = Node(data)
new_node.next = self.head
self.head = new_node
self.size += 1
def insert_after(self, prev_node, data):
"""Insert element after a given node."""
if prev_node is None:
raise ValueError("Previous node cannot be None")
new_node = Node(data)
new_node.next = prev_node.next
prev_node.next = new_node
self.size += 1
def delete(self, data):
"""Delete first occurrence of data."""
if self.head is None:
return False
if self.head.data == data:
self.head = self.head.next
self.size -= 1
return True
current = self.head
while current.next:
if current.next.data == data:
current.next = current.next.next
self.size -= 1
return True
current = current.next
return False
def search(self, data):
"""Search for data in the list."""
current = self.head
index = 0
while current:
if current.data == data:
return index
current = current.next
index += 1
return -1
def __len__(self):
"""Return size of the list."""
return self.size
def __str__(self):
"""String representation of the list."""
elements = []
current = self.head
while current:
elements.append(str(current.data))
current = current.next
return " -> ".join(elements) if elements else "Empty"
# Example usage
if __name__ == "__main__":
ll = LinkedList()
print("Appending elements:")
ll.append(1)
ll.append(2)
ll.append(3)
print(f" {ll}")
print("\nPrepending element:")
ll.prepend(0)
print(f" {ll}")
print(f"\nSearching for 2: Index {ll.search(2)}")
print(f"Size: {len(ll)}")
print("\nDeleting element 2:")
ll.delete(2)
print(f" {ll}")