added circular array implementation in Python
parent
17530912ac
commit
cda699ef9f
|
@ -0,0 +1,105 @@
|
||||||
|
{
|
||||||
|
"cells": [
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"## Constraints and Assumptions\n",
|
||||||
|
"> Can we assume the list fits in memory?\n",
|
||||||
|
"\n",
|
||||||
|
"Yes\n",
|
||||||
|
"\n",
|
||||||
|
"> Do we have to worry about load factors?\n",
|
||||||
|
"\n",
|
||||||
|
"No\n",
|
||||||
|
"\n",
|
||||||
|
"> Can we assume inputs are valid or do we have to validate them?\n",
|
||||||
|
"\n",
|
||||||
|
"Assume they are valid"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 1,
|
||||||
|
"metadata": {
|
||||||
|
"collapsed": true
|
||||||
|
},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"class CircularArray:\n",
|
||||||
|
" \"\"\"\n",
|
||||||
|
" Python class implementing a circular array.\n",
|
||||||
|
" \"\"\"\n",
|
||||||
|
" def __init__(self, size):\n",
|
||||||
|
" \"\"\"\n",
|
||||||
|
" Constructor. Refer to `full()` for explanation for `size+1`.\n",
|
||||||
|
" \"\"\"\n",
|
||||||
|
" self._size = size + 1\n",
|
||||||
|
" self._items = [None for _ in range(self._size)]\n",
|
||||||
|
" self._read = 0 # read pointer\n",
|
||||||
|
" self._write = 0 # write pointer\n",
|
||||||
|
" \n",
|
||||||
|
" @property\n",
|
||||||
|
" def empty(self):\n",
|
||||||
|
" \"\"\"\n",
|
||||||
|
" Returns whether the queue is empty.\n",
|
||||||
|
" \"\"\"\n",
|
||||||
|
" return self._read == self._write\n",
|
||||||
|
" \n",
|
||||||
|
" @property\n",
|
||||||
|
" def full(self):\n",
|
||||||
|
" \"\"\"\n",
|
||||||
|
" Return wheter the queue is full.\n",
|
||||||
|
" In a naive implementation, full and empty are both indicated by read == write, which introduces an\n",
|
||||||
|
" ambiguity. Thus, to break this, a circular array is assumed to be full if the write pointer is one\n",
|
||||||
|
" position behind the read pointer. To preserve the inituitiveness of the class interface, the internal\n",
|
||||||
|
" size property is incremented by 1, a sentinel element (so this way the user won't be surprised that their\n",
|
||||||
|
" array that supposedly fits 10 elements only accomodates 9).\n",
|
||||||
|
" \"\"\"\n",
|
||||||
|
" return self._read == (self._write + 1) % self._size\n",
|
||||||
|
" \n",
|
||||||
|
" def queue(self, item):\n",
|
||||||
|
" \"\"\"\n",
|
||||||
|
" Enqueues an item in the circular buffer.\n",
|
||||||
|
" \"\"\"\n",
|
||||||
|
" if self.full:\n",
|
||||||
|
" raise BufferError('Queue is full')\n",
|
||||||
|
" self._items[self._write] = item\n",
|
||||||
|
" self._write = (self._write + 1) % self._size\n",
|
||||||
|
" \n",
|
||||||
|
" def dequeue(self):\n",
|
||||||
|
" \"\"\"\n",
|
||||||
|
" Dequeues an item from the buffer.\n",
|
||||||
|
" \"\"\"\n",
|
||||||
|
" if self.empty:\n",
|
||||||
|
" raise BufferError('Queue is empty')\n",
|
||||||
|
" item = self._items[self._read]\n",
|
||||||
|
" self._items[self._read] = None\n",
|
||||||
|
" self._read = (self._read + 1) % self._size\n",
|
||||||
|
" return item"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"metadata": {
|
||||||
|
"anaconda-cloud": {},
|
||||||
|
"kernelspec": {
|
||||||
|
"display_name": "Python [py35]",
|
||||||
|
"language": "python",
|
||||||
|
"name": "Python [py35]"
|
||||||
|
},
|
||||||
|
"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.5.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nbformat": 4,
|
||||||
|
"nbformat_minor": 0
|
||||||
|
}
|
|
@ -0,0 +1,51 @@
|
||||||
|
class CircularArray:
|
||||||
|
"""
|
||||||
|
Python class implementing a circular array.
|
||||||
|
"""
|
||||||
|
def __init__(self, size):
|
||||||
|
"""
|
||||||
|
Constructor. Refer to `full()` for explanation for `size+1`.
|
||||||
|
"""
|
||||||
|
self._size = size + 1
|
||||||
|
self._items = [None for _ in range(self._size)]
|
||||||
|
self._read = 0 # read pointer
|
||||||
|
self._write = 0 # write pointer
|
||||||
|
|
||||||
|
@property
|
||||||
|
def empty(self):
|
||||||
|
"""
|
||||||
|
Returns whether the queue is empty.
|
||||||
|
"""
|
||||||
|
return self._read == self._write
|
||||||
|
|
||||||
|
@property
|
||||||
|
def full(self):
|
||||||
|
"""
|
||||||
|
Return wheter the queue is full.
|
||||||
|
In a naive implementation, full and empty are both indicated by read == write, which introduces an
|
||||||
|
ambiguity. Thus, to break this, a circular array is assumed to be full if the write pointer is one
|
||||||
|
position behind the read pointer. To preserve the inituitiveness of the class interface, the internal
|
||||||
|
size property is incremented by 1, a sentinel element (so this way the user won't be surprised that their
|
||||||
|
array that supposedly fits 10 elements only accomodates 9).
|
||||||
|
"""
|
||||||
|
return self._read == (self._write + 1) % self._size
|
||||||
|
|
||||||
|
def queue(self, item):
|
||||||
|
"""
|
||||||
|
Enqueues an item in the circular buffer.
|
||||||
|
"""
|
||||||
|
if self.full:
|
||||||
|
raise BufferError('Queue is full')
|
||||||
|
self._items[self._write] = item
|
||||||
|
self._write = (self._write + 1) % self._size
|
||||||
|
|
||||||
|
def dequeue(self):
|
||||||
|
"""
|
||||||
|
Dequeues an item from the buffer.
|
||||||
|
"""
|
||||||
|
if self.empty:
|
||||||
|
raise BufferError('Queue is empty')
|
||||||
|
item = self._items[self._read]
|
||||||
|
self._items[self._read] = None
|
||||||
|
self._read = (self._read + 1) % self._size
|
||||||
|
return item
|
Loading…
Reference in New Issue