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