diff --git a/README.md b/README.md index ea03592..034353c 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,8 @@ Continually updated IPython Notebooks containing coding problems and solutions ( ## Stacks and Queues -* [Implement a stack with push, pop, and peek methods using a linked list.](http://nbviewer.ipython.org/github/donnemartin/algorithms-data-structures/blob/master/stacks-queues/stack.ipynb) +* [Implement a stack with push, pop, and peek methods using a linked list](http://nbviewer.ipython.org/github/donnemartin/algorithms-data-structures/blob/master/stacks-queues/stack.ipynb) +* [Implement a queue with enqueue and dequeue methods using a linked list](http://nbviewer.ipython.org/github/donnemartin/algorithms-data-structures/blob/master/stacks-queues/queue.ipynb) ## License diff --git a/stacks-queues/queue.ipynb b/stacks-queues/queue.ipynb new file mode 100644 index 0000000..027a833 --- /dev/null +++ b/stacks-queues/queue.ipynb @@ -0,0 +1,219 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Problem: Implement a queue with enqueue and dequeue methods using a linked list.\n", + "\n", + "* [Clarifying Questions](#Clarifying-Questions)\n", + "* [Test Cases](#Test-Cases)\n", + "* [Algorithm](#Algorithm)\n", + "* [Code](#Code)\n", + "* [Pythonic-Code](#Pythonic-Code)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Clarifying Questions\n", + "\n", + "* If there is one item in the list, do you expect the first and last pointers to both point to it?\n", + " * Yes\n", + "* If there are no items on the list, do you expect the first and last pointers to be NULL?\n", + " * Yes" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Test Cases\n", + "\n", + "### Enqueue\n", + "\n", + "* Enqueue to an empty queue\n", + "* Enqueue to a non-empty queue\n", + "\n", + "### Dequeue\n", + "\n", + "* Dequeue an empty queue\n", + "* Dequeue a queue with one element\n", + "* Dequeue a queue with more than one element" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Algorithm\n", + "\n", + "### Enqueue\n", + "\n", + "* If the list is empty, set first and last to node\n", + "* Else, set last to node\n", + "\n", + "Complexity:\n", + "* Time: O(1)\n", + "* Space: O(1)\n", + "\n", + "### Dequeue\n", + "\n", + "* If the list is empty, return NULL\n", + "* If the list has one node\n", + " * Save the first node's value\n", + " * Set first and last to NULL\n", + " * Return the saved value\n", + "* Else\n", + " * Save the first node's value\n", + " * Set first to its next node\n", + " * Return the saved value\n", + "\n", + "Complexity:\n", + "* Time: O(1)\n", + "* Space: O(1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Code" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "%%writefile queue.py\n", + "\n", + "class Node(object):\n", + " def __init__(self, data):\n", + " self.data = data\n", + " self.next = None\n", + "\n", + "class Queue(object):\n", + " def __init__(self):\n", + " self.first = None\n", + " self.last = None\n", + "\n", + " def enqueue(self, data):\n", + " node = Node(data)\n", + " if self.first is None and self.last is None:\n", + " self.first = node\n", + " self.last = node\n", + " else:\n", + " self.last.next = node\n", + " self.last = node\n", + "\n", + " def dequeue(self):\n", + " # Empty list\n", + " if self.first is None and self.last is None:\n", + " return None\n", + " # Remove only element from a one element list\n", + " elif self.first == self.last:\n", + " data = self.first.data\n", + " self.first = None\n", + " self.last = None\n", + " return data\n", + " else:\n", + " data = self.first.data\n", + " self.first = self.first.next\n", + " return data" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "%run queue.py" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "print('Dequeue an empty queue')\n", + "queue = Queue()\n", + "print(queue.dequeue())\n", + "print('Enqueue to an empty queue')\n", + "queue.enqueue(1)\n", + "print('Dequeue a queue with one element')\n", + "print(queue.dequeue())\n", + "print('Enqueue to a non-empty queue')\n", + "queue.enqueue(2)\n", + "queue.enqueue(3)\n", + "queue.enqueue(4)\n", + "print('Dequeue a queue with more than one element')\n", + "print(queue.dequeue())\n", + "print(queue.dequeue())\n", + "print(queue.dequeue())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Pythonic-Code" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Source: https://docs.python.org/2/tutorial/datastructures.html#using-lists-as-queues\n", + "
\n",
+    "It is possible to use a list as a queue, where the first element added is the first element retrieved (“first-in, first-out”); however, lists are not efficient for this purpose. While appends and pops from the end of list are fast, doing inserts or pops from the beginning of a list is slow (because all of the other elements have to be shifted by one).\n",
+    "\n",
+    "To implement a queue, use collections.deque which was designed to have fast appends and pops from both ends. For example:\n",
+    "\n",
+    ">>>\n",
+    ">>> from collections import deque\n",
+    ">>> queue = deque([\"Eric\", \"John\", \"Michael\"])\n",
+    ">>> queue.append(\"Terry\")           # Terry arrives\n",
+    ">>> queue.append(\"Graham\")          # Graham arrives\n",
+    ">>> queue.popleft()                 # The first to arrive now leaves\n",
+    "'Eric'\n",
+    ">>> queue.popleft()                 # The second to arrive now leaves\n",
+    "'John'\n",
+    ">>> queue                           # Remaining queue in order of arrival\n",
+    "deque(['Michael', 'Terry', 'Graham'])\n",
+    "
" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 2", + "language": "python", + "name": "python2" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 2 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython2", + "version": "2.7.9" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/stacks-queues/queue.py b/stacks-queues/queue.py new file mode 100644 index 0000000..cbe682c --- /dev/null +++ b/stacks-queues/queue.py @@ -0,0 +1,34 @@ + +class Node(object): + def __init__(self, data): + self.data = data + self.next = None + +class Queue(object): + def __init__(self): + self.first = None + self.last = None + + def enqueue(self, data): + node = Node(data) + if self.first is None and self.last is None: + self.first = node + self.last = node + else: + self.last.next = node + self.last = node + + def dequeue(self): + # Empty list + if self.first is None and self.last is None: + return None + # Remove only element from a one element list + elif self.first == self.last: + data = self.first.data + self.first = None + self.last = None + return data + else: + data = self.first.data + self.first = self.first.next + return data \ No newline at end of file