mirror of
				https://github.com/donnemartin/system-design-primer.git
				synced 2025-11-04 18:22:30 +03:00 
			
		
		
		
	Merge fc9de925a1 into 40d5d2edcc
				
					
				
			This commit is contained in:
		@@ -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,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
 | 
			
		||||
}
 | 
			
		||||
@@ -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
 | 
			
		||||
		Reference in New Issue
	
	Block a user