-
Notifications
You must be signed in to change notification settings - Fork 78
/
dynamic_array.py
104 lines (81 loc) · 2.98 KB
/
dynamic_array.py
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
# coding: utf-8
"""
https://learning.oreilly.com/library/view/Data+Structures+and+Algorithms+in+Python/9781118290279/10_chap05.html#ch005-sec009
"""
import ctypes
# A dynamic array is that a list maintains an underlying array that has greater capacity than the current length of the list
# This extra capacity makes it easy to append a new element to the list
class DynamicArray:
def __init__(self, capacity=2):
self._size = 0
self._capacity = capacity
self._array = self._new_array(self._capacity)
# O(1)
def __len__(self):
return self._size
def _positive_index(self, index):
if index >= 0:
if index >= self._size:
raise IndexError
positive_index = index
else:
if abs(index) > self._size:
raise IndexError
positive_index = self._size + index # Convert to the positive index
return positive_index
# O(1)
def __getitem__(self, index):
positive_index = self._positive_index(index)
return self._array[positive_index]
# O(1)
def __setitem__(self, index, value):
positive_index = self._positive_index(index)
self._array[positive_index] = value
# O(n)
def __iter__(self):
for i in range(self._size):
yield self._array[i]
def _new_array(self, capacity):
return (capacity * ctypes.py_object)()
# O(n)
def _resize(self, new_capacity):
new_array = self._new_array(new_capacity)
for i in range(self._size):
new_array[i] = self._array[i]
self._array = new_array
self._capacity = new_capacity
# O(1)
# O(n) if it triggers resizing
def append(self, value):
if self._size == self._capacity:
self._resize(self._capacity * 2)
# Access the underlying array directly instead of using self.__setitem__()
self._array[self._size] = value
self._size += 1
# O(n)
# O(1) if it pops the last item
def pop(self, index=-1):
positive_index = self._positive_index(index)
pop_value = self._array[positive_index]
for i in range(positive_index, self._size - 1):
self._array[i] = self._array[i + 1]
self._array[self._size - 1] = None
self._size -= 1
return pop_value
# O(n)
def insert_before(self, index, value):
if self._size == self._capacity:
self._resize(self._capacity * 2)
positive_index = self._positive_index(index)
for i in range(self._size, positive_index, -1):
self._array[i] = self._array[i - 1]
self._array[positive_index] = value
self._size += 1
# O(n)
def extend(self, another_array):
new_size = self._size + len(another_array)
if new_size > self._capacity:
self._resize(new_size * 2)
for i in range(len(another_array)):
self._array[self._size + i] = another_array[i]
self._size = new_size