Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added Dynamic Arrays #28

Merged
merged 4 commits into from
Oct 22, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ sudo: false
language: python

python:
- "2.7"
- "3.5"
install:
- pip install -r requirements.txt
Expand Down
1 change: 1 addition & 0 deletions pydatastructs/linear_data_structures/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@

from .arrays import (
OneDimensionalArray,
DynamicOneDimensionalArray
)
__all__.extend(arrays.__all__)
129 changes: 128 additions & 1 deletion pydatastructs/linear_data_structures/arrays.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
from pydatastructs.utils.misc_util import _check_type, NoneType

__all__ = [
'OneDimensionalArray'
'OneDimensionalArray',
'DynamicOneDimensionalArray'
]

class Array(object):
Expand Down Expand Up @@ -112,3 +113,129 @@ def fill(self, elem):
elem = self._dtype(elem)
for i in range(self._size):
self._data[i] = elem

ODA = OneDimensionalArray

class DynamicArray(Array):
"""
Abstract class for dynamic arrays.
"""
pass

class DynamicOneDimensionalArray(DynamicArray, OneDimensionalArray):
"""
Represents dynamic one dimensional arrays.

Parameters
==========

dtype: type
A valid object type.
size: int
The number of elements in the array.
elements: list/tuple
The elements in the array, all should
be of same type.
init: a python type
The inital value with which the element has
to be initialized. By default none, used only
when the data is not given.
load_factor: float, by default 0.25
The number below which if the ratio, Num(T)/Size(T)
falls then the array is contracted such that at
most only half the positions are filled.

Raises
======

ValueError
When the number of elements in the list do not
match with the size.
More than three parameters are passed as arguments.
Types of arguments is not as mentioned in the docstring.
The load factor is not of floating point type.

Note
====

At least one parameter should be passed as an argument along
with the dtype.
Num(T) means the number of positions which are not None in the
array.
Size(T) means the maximum number of elements that the array can hold.

Examples
========

>>> from pydatastructs import DynamicOneDimensionalArray as DODA
>>> arr = DODA(int, 0)
>>> arr.append(1)
>>> arr.append(2)
>>> arr[0]
1
>>> arr.delete(0)
>>> arr[0]
>>> arr[1]
2
>>> arr.append(3)
>>> arr.append(4)
>>> [arr[i] for i in range(arr.size)]
[None, 2, 3, 4, None, None, None]

References
==========

.. [1] http://www.cs.nthu.edu.tw/~wkhon/algo09/lectures/lecture16.pdf
"""

__slots__ = ['_load_factor', '_num', '_last_pos_filled', '_size']

def __new__(cls, dtype=NoneType, *args, **kwargs):
obj = super().__new__(cls, dtype, *args, **kwargs)
obj._load_factor = float(kwargs.get('load_factor', 0.25))
obj._num = 0 if obj._size == 0 or obj[0] == None else obj._size
obj._last_pos_filled = obj._num - 1
return obj

def _modify(self):
"""
Contracts the array if Num(T)/Size(T) falls
below load factor.
"""
if self._num/self._size < self._load_factor:
arr_new = ODA(self._dtype, 2*self._num + 1)
j = 0
for i in range(self._last_pos_filled + 1):
if self[i] != None:
arr_new[j] = self[i]
j += 1
self._last_pos_filled = j - 1
self._data = arr_new._data
self._size = arr_new._size

def append(self, el):
if self._last_pos_filled + 1 == self._size:
arr_new = ODA(self._dtype, 2*self._size + 1)
for i in range(self._last_pos_filled + 1):
arr_new[i] = self[i]
arr_new[self._last_pos_filled + 1] = el
self._last_pos_filled += 1
self._size = arr_new._size
self._num += 1
self._data = arr_new._data
else:
self[self._last_pos_filled + 1] = el
self._last_pos_filled += 1
self._num += 1
self._modify()

def delete(self, idx):
if idx <= self._last_pos_filled and idx >= 0 and \
self[idx] != None:
self[idx] = None
self._num -= 1
self._modify()

@property
def size(self):
return self._size
21 changes: 20 additions & 1 deletion pydatastructs/linear_data_structures/tests/test_arrays.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from pydatastructs.linear_data_structures import OneDimensionalArray
from pydatastructs.linear_data_structures import (
OneDimensionalArray, DynamicOneDimensionalArray)
from pydatastructs.utils.raises_util import raises


Expand All @@ -17,3 +18,21 @@ def test_OneDimensionalArray():
raises(TypeError, lambda: ODA(int, 5.0))
raises(TypeError, lambda: ODA(int, set([1, 2, 3])))
raises(ValueError, lambda: ODA(int, 3, [1]))

def test_DynamicOneDimensionalArray():
DODA = DynamicOneDimensionalArray
A = DODA(int, 0)
A.append(1)
A.append(2)
A.append(3)
A.append(4)
A.delete(0)
A.delete(0)
A.delete(15)
A.delete(-1)
A.delete(1)
A.delete(2)
assert A._data == [4, None, None]
assert A.size == 3
A.fill(4)
assert A._data == [4, 4, 4]