pull/178/merge
Bertalan Körmendy 2024-12-02 18:02:07 +00:00 committed by GitHub
commit d7e773db4d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 285 additions and 1 deletions

View File

@ -366,7 +366,7 @@ Check out the following links to get a better idea of what to expect:
| Design a deck of cards | [Solution](solutions/object_oriented_design/deck_of_cards/deck_of_cards.ipynb) |
| Design a parking lot | [Solution](solutions/object_oriented_design/parking_lot/parking_lot.ipynb) |
| Design a chat server | [Solution](solutions/object_oriented_design/online_chat/online_chat.ipynb) |
| Design a circular array | [Contribute](#contributing) |
| Design a circular array | [Solution](solutions/object_oriented_design/circular_array/circular_array.ipynb) |
| Add an object-oriented design question | [Contribute](#contributing) |
## System design topics: start here

View File

@ -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
}

View File

@ -0,0 +1,128 @@
{
"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"
]
},
{
"cell_type": "code",
"execution_count": 131,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"class CircularArray:\n",
" \"\"\"\n",
" Python class implementing a circular array.\n",
" Credits to Sarath S. Pillai for some edge cases (https://github.com/sarathsp06)\n",
" \"\"\"\n",
" def __init__(self, size):\n",
" \"\"\"\n",
" Constructor. Refer to `full()` for explanation for `size+1`.\n",
" \"\"\"\n",
" if (size < 0):\n",
" raise RuntimeError(\"Invalid size (smaller than zero)\")\n",
" self._size = size + 1\n",
" self._items = [None for _ in range(self._size)]\n",
" self._read = 0 # read pointer (head of list)\n",
" self._write = 0 # write pointer (tail of list)\n",
" \n",
" def __len__(self):\n",
" '''\n",
" Returns how many elements are in the array.\n",
" '''\n",
" return (self._write - self._read) % (self._size - 1)\n",
" \n",
" def __getitem__(self, index):\n",
" if index < 0:\n",
" raise IndexError(\"Key must be a positive interger\")\n",
" if index > len(self):\n",
" raise IndexError(\"Index out of range\")\n",
" return self._items[((self._read + key) % self._size)]\n",
" \n",
" def __repr__(self):\n",
" if self.empty:\n",
" return \"<CircularArray []>\"\n",
" if self._read < self._write:\n",
" return \"<CircularArray {}>\".format(self._items[self._read:self._write])\n",
" return \"<CircularArray {}>\".format(self._items[self._read:] + self._items[:self._write])\n",
" \n",
" @property\n",
" def capacity(self):\n",
" return self._size - 1\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",
" Returns 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
}

View File

@ -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