Added circular array implementation
parent
1b339dbdde
commit
51741b7a96
|
@ -0,0 +1,222 @@
|
||||||
|
{
|
||||||
|
"cells": [
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"This notebook was prepared by [Sarath S Pillai](https://github.com/sarathsp06). Source and license info is on [GitHub](https://github.com/donnemartin/system-design-primer-primer)."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"# Design a circular array"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"## Constraints and assumptions\n",
|
||||||
|
"\n",
|
||||||
|
"* For simplicity, are the keys integers only?\n",
|
||||||
|
" * Yes\n",
|
||||||
|
"* Can we assume this fits memory?\n",
|
||||||
|
" * Yes\n",
|
||||||
|
"* Is array size fixed\n",
|
||||||
|
" * Yes\n",
|
||||||
|
"* What happens to deleted indexes\n",
|
||||||
|
" * None onget request"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"## Circular array Interface\n",
|
||||||
|
"* \\[idx\\]\n",
|
||||||
|
" * get item on idx ,assuming circular array\n",
|
||||||
|
" * any idx value is taken as modulo of itself with size\n",
|
||||||
|
" * negative idx is not permitted\n",
|
||||||
|
"* len\n",
|
||||||
|
" * length is always length of current valid entries\n",
|
||||||
|
"* repr\n",
|
||||||
|
" * the circular aray is printed with values in order\n",
|
||||||
|
" * logical order is maintained not how it is stored\n",
|
||||||
|
"* push\n",
|
||||||
|
" * pushed item to end of queue\n",
|
||||||
|
" * throws exception if capcity is filled , len == capcaity\n",
|
||||||
|
"* pop\n",
|
||||||
|
" * pop an item from start of array\n",
|
||||||
|
" * throws exception if \n",
|
||||||
|
"* capacity\n",
|
||||||
|
" * returns initial size of array "
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"## Solution"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 1,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "stdout",
|
||||||
|
"output_type": "stream",
|
||||||
|
"text": [
|
||||||
|
"Overwriting circular_array.py\n"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"source": [
|
||||||
|
"%%writefile circular_array.py\n",
|
||||||
|
"class CircularArray(object):\n",
|
||||||
|
" def __init__(self, size):\n",
|
||||||
|
" if size <= 0:\n",
|
||||||
|
" raise ValueError(\"Size has to be non zero positive number\")\n",
|
||||||
|
" self.size = size\n",
|
||||||
|
" self.array = self.size *[None]\n",
|
||||||
|
" self.start = self.end = None\n",
|
||||||
|
" \n",
|
||||||
|
" def capacity(self):\n",
|
||||||
|
" return self.size\n",
|
||||||
|
" \n",
|
||||||
|
" def __len__(self):\n",
|
||||||
|
" if self.start is None:\n",
|
||||||
|
" return 0\n",
|
||||||
|
" return (self.end - self.start + self.size ) % self.size + 1\n",
|
||||||
|
" \n",
|
||||||
|
" def __getitem__(self, key):\n",
|
||||||
|
" if key < 0:\n",
|
||||||
|
" raise ValueError(\"Key has to be a positive number\")\n",
|
||||||
|
" if self.start is None:\n",
|
||||||
|
" return None\n",
|
||||||
|
" index = (key + self.start) % self.size\n",
|
||||||
|
" return self.array[index]\n",
|
||||||
|
" \n",
|
||||||
|
" def push(self, value):\n",
|
||||||
|
" if self.start is None:\n",
|
||||||
|
" self.start = self.end = 0\n",
|
||||||
|
" else:\n",
|
||||||
|
" index = (self.end + 1) % self.size\n",
|
||||||
|
" if index == self.start:\n",
|
||||||
|
" raise IndexError(\"Push to full array \")\n",
|
||||||
|
" self.end = index\n",
|
||||||
|
" self.array[self.end] = value\n",
|
||||||
|
" \n",
|
||||||
|
" def __repr__(self):\n",
|
||||||
|
" if self.start is None:\n",
|
||||||
|
" return '[]'\n",
|
||||||
|
" if self.start < self.end:\n",
|
||||||
|
" return repr(self.array[self.start:self.end+1])\n",
|
||||||
|
" return repr(self.array[self.start:]+self.array[:self.end+1])\n",
|
||||||
|
" \n",
|
||||||
|
" def pop(self):\n",
|
||||||
|
" if self.start is None:\n",
|
||||||
|
" raise RuntimeException(\"Pop on nil array\")\n",
|
||||||
|
" value = self.array[self.start]\n",
|
||||||
|
" if self.start == self.end:\n",
|
||||||
|
" self.start = self.end = None\n",
|
||||||
|
" return value\n",
|
||||||
|
" self.start = (self.start + 1) % self.size\n",
|
||||||
|
" return value"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"### Test\n",
|
||||||
|
"\n",
|
||||||
|
"Here are basic test cases to illustrate the features"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 8,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"from circular_array import CircularArray\n",
|
||||||
|
"# create a circular array of 10 elements\n",
|
||||||
|
"ca = CircularArray(10);\n",
|
||||||
|
"assert ca.capacity() == 10\n",
|
||||||
|
"\n",
|
||||||
|
"#push 4 items\n",
|
||||||
|
"ca.push(1)\n",
|
||||||
|
"ca.push(2)\n",
|
||||||
|
"ca.push(3)\n",
|
||||||
|
"ca.push(4)\n",
|
||||||
|
"assert ca.capacity() == 10\n",
|
||||||
|
"\n",
|
||||||
|
"#pop and check 3 elements\n",
|
||||||
|
"assert ca.pop() == 1\n",
|
||||||
|
"assert ca.pop() == 2\n",
|
||||||
|
"assert ca.pop() == 3\n",
|
||||||
|
"assert len(ca) == 1\n",
|
||||||
|
"\n",
|
||||||
|
"#push 4 more elements\n",
|
||||||
|
"ca.push(5)\n",
|
||||||
|
"ca.push(6)\n",
|
||||||
|
"ca.push(7)\n",
|
||||||
|
"ca.push(8)\n",
|
||||||
|
"assert len(ca) == 5\n",
|
||||||
|
"\n",
|
||||||
|
"#check getitem function for proper indexing and pop 2 elements\n",
|
||||||
|
"assert ca[0] == 4\n",
|
||||||
|
"assert ca.pop() == 4\n",
|
||||||
|
"assert ca[0] == 5\n",
|
||||||
|
"assert ca[10] == 5\n",
|
||||||
|
"assert ca.pop() == 5\n",
|
||||||
|
"assert len(ca) == 3\n",
|
||||||
|
"#push 7 more items \n",
|
||||||
|
"ca.push(9)\n",
|
||||||
|
"ca.push(10)\n",
|
||||||
|
"ca.push(11)\n",
|
||||||
|
"ca.push(12)\n",
|
||||||
|
"ca.push(13)\n",
|
||||||
|
"ca.push(14)\n",
|
||||||
|
"ca.push(15)\n",
|
||||||
|
"assert len(ca) == 10\n",
|
||||||
|
"assert ca.capacity() == 10\n",
|
||||||
|
"assert repr(ca) == '[6, 7, 8, 9, 10, 11, 12, 13, 14, 15]'\n",
|
||||||
|
"assert ca[1] == 7\n",
|
||||||
|
"assert ca[11] == 7"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"metadata": {
|
||||||
|
"kernelspec": {
|
||||||
|
"display_name": "Python 3",
|
||||||
|
"language": "python",
|
||||||
|
"name": "python3"
|
||||||
|
},
|
||||||
|
"language_info": {
|
||||||
|
"codemirror_mode": {
|
||||||
|
"name": "ipython",
|
||||||
|
"version": 3
|
||||||
|
},
|
||||||
|
"file_extension": ".py",
|
||||||
|
"mimetype": "text/x-python",
|
||||||
|
"name": "python",
|
||||||
|
"nbconvert_exporter": "python",
|
||||||
|
"pygments_lexer": "ipython3",
|
||||||
|
"version": "3.6.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nbformat": 4,
|
||||||
|
"nbformat_minor": 1
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
class CircularArray(object):
|
||||||
|
def __init__(self, size):
|
||||||
|
if size <= 0:
|
||||||
|
raise ValueError("Size has to be non zero positive number")
|
||||||
|
self.size = size
|
||||||
|
self.array = self.size *[None]
|
||||||
|
self.start = self.end = None
|
||||||
|
|
||||||
|
def capacity(self):
|
||||||
|
return self.size
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
if self.start is None:
|
||||||
|
return 0
|
||||||
|
return (self.end - self.start + self.size ) % self.size + 1
|
||||||
|
|
||||||
|
def __getitem__(self, key):
|
||||||
|
if key < 0:
|
||||||
|
raise ValueError("Key has to be a positive number")
|
||||||
|
if self.start is None:
|
||||||
|
return None
|
||||||
|
index = (key + self.start) % self.size
|
||||||
|
return self.array[index]
|
||||||
|
|
||||||
|
def push(self, value):
|
||||||
|
if self.start is None:
|
||||||
|
self.start = self.end = 0
|
||||||
|
else:
|
||||||
|
index = (self.end + 1) % self.size
|
||||||
|
if index == self.start:
|
||||||
|
raise IndexError("Push to full array ")
|
||||||
|
self.end = index
|
||||||
|
self.array[self.end] = value
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
if self.start is None:
|
||||||
|
return '[]'
|
||||||
|
if self.start < self.end:
|
||||||
|
return repr(self.array[self.start:self.end+1])
|
||||||
|
return repr(self.array[self.start:]+self.array[:self.end+1])
|
||||||
|
|
||||||
|
def pop(self):
|
||||||
|
if self.start is None:
|
||||||
|
raise RuntimeException("Pop on nil array")
|
||||||
|
value = self.array[self.start]
|
||||||
|
if self.start == self.end:
|
||||||
|
self.start = self.end = None
|
||||||
|
return value
|
||||||
|
self.start = (self.start + 1) % self.size
|
||||||
|
return value
|
Loading…
Reference in New Issue