Advantage
- Linked Lists are dynamic data structures, arrays are not
- It can allocate the needed memory in runtime
- Very efficient if we want to manipulate the first elements
- Can store items with different sizes; an array assumes every element to be exactly the same
- It is easier for a linked list to grow organically. An array’s size usually need to be known ahead of time or re-created when it needs to grow
Disadvantages
- Waste memory because of the references
- Nodes in a linked list must be read in order from the beginning as linked lists have sequential access (array items can be reached via indexes in O(1) time)
- Solution: doubly linked lists -> easier to read, but memory is wasted in allocating space for a back pointer
Pros & Cons of an array
- Pros
- We can use random access by indexes, O(1)
- Very fast implementation and use
- Very fast data structure
- A good choice when we want to add items over and over again and we want to get items with given indexes
- Cons
- Usually, we have to know the size of the array at compile time
- If it is full we have to create a bigger array and have to copy values one by one.
- It is not able to store items with different types (Not the case in Python)
Linked Lists vs Arrays
Linked Lists | Arrays | |
---|---|---|
search | O(n) | O(1) via index |
insert at the start | O(1) | O(N) |
insert at the end | O(N) | O(1) |
Waste Space | O(N) | 0 |
Implementation
Linked List implementation with Python1
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
96class Node(object):
def __init__(self, data):
self.data = data
self.nextNode = None
class LinkedList(object):
def __init__(self):
self.head = None
self.size = 0
# O(1)
def insertStart(self, data):
self.size = self.size + 1
newNode = Node(data)
if not self.head:
self.head = newNode
else:
newNode.nextNode = self.head
self.head = newNode
def remove(self, data):
if self.head is None:
return
self.size = self.size - 1
currentNode = self.head
previousNode = None
while currentNode.data != data:
previousNode = currentNode
currentNode = currentNode.nextNode
if previousNode is None:
self.head = currentNode.nextNode
else:
previousNode = currentNode.nextNode
# O(1)
def size1(self):
return self.size
# O(N) not good !!!!!
def seize2(self):
actualNode = self.head
size = 0
while actualNode is not None:
size += 1
actualNode = actualNode.nextNode
return size
# O(N)
def insertEnd(self, data):
self.size = self.size + 1
newNode = Node(data)
actualNode = self.head
while actualNode.nextNode is not None:
actualNode = actualNode.nextNode
actualNode.nextNode = newNode
def traverseList(self):
actualNode = self.head
while actualNode is not None:
print('%d ' % actualNode.data)
actualNode = actualNode.nextNode
# test
linkedList = LinkedList()
linkedList.insertStart(12)
linkedList.insertStart(122)
linkedList.insertStart(3)
linkedList.insertEnd(5)
linkedList.traverseList()
linkedList.remove(3)
linkedList.remove(5)
linkedList.remove(122)
print(linkedList.size1())
Other Note
abstract data types | data structures |
---|---|
Stack | array, linked list |
Queue | array, linked list |
Priority queue | heap |
Dictionary / hashmap | array |