From aa57bc1a33bc85af34dd43eee1ddb2f0137b278f Mon Sep 17 00:00:00 2001 From: Omkar Pathak Date: Tue, 19 Sep 2017 21:00:10 +0530 Subject: [PATCH 01/28] Modified BST --- Trees/BinarySearchTree.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Trees/BinarySearchTree.py b/Trees/BinarySearchTree.py index 7992615..2b6333a 100644 --- a/Trees/BinarySearchTree.py +++ b/Trees/BinarySearchTree.py @@ -47,7 +47,7 @@ def minValueNode(self, node): def delete(self, data): ''' For deleting the node ''' if self is None: - return root + return None # if current node's data is less than that of root node, then only search in left subtree else right subtree if data < self.data: From e3713eb421a97dd8330b8dccee5acf6a1d5dd95a Mon Sep 17 00:00:00 2001 From: Omkar Pathak Date: Tue, 19 Sep 2017 21:00:28 +0530 Subject: [PATCH 02/28] Added Bubble Sort --- Sorting/1. Bubble_Sort.ipynb | 204 +++++++++++++++++++++++++++++++++++ 1 file changed, 204 insertions(+) create mode 100644 Sorting/1. Bubble_Sort.ipynb diff --git a/Sorting/1. Bubble_Sort.ipynb b/Sorting/1. Bubble_Sort.ipynb new file mode 100644 index 0000000..1728a9f --- /dev/null +++ b/Sorting/1. Bubble_Sort.ipynb @@ -0,0 +1,204 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Bubble Sort" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def bubble_sort(array):\n", + " for i in range(len(array) - 1):\n", + " for j in range(len(array) - 1):\n", + " if array[j] > array[j + 1]:\n", + " array[j], array[j + 1] = array[j + 1], array[j] # swap" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Optimized Bubble Sort" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# optimized bubble sort does not increase or decrease asymtotic notations\n", + "# however number of iterations can be reduced to some extent\n", + "def optimized_bubble_sort(array):\n", + " global iterations\n", + " iterations = 0\n", + " for i in range(len(array) - 1):\n", + " swapped = False\n", + " for j in range(len(array) - 1):\n", + " iterations += 1\n", + " if array[j] > array[j + 1]:\n", + " array[j], array[j + 1] = array[j + 1], array[j]\n", + " swapped = True\n", + " # if no swapping is performed that means sorting is complete\n", + " # hence break out of the loop\n", + " if not swapped: \n", + " break" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Time Complexity:\n", + "\n", + "- Best Case: O(n)\n", + "- Average Case: O(n * n)\n", + "- Worst Case: O(n * n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Code for executing and seeing the difference in time complexities" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Best Case Performance:" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "18\n" + ] + } + ], + "source": [ + "# elements are already sorted\n", + "array = [i for i in range(1, 20)]\n", + "\n", + "optimized_bubble_sort(array)\n", + "# 20 ALREADY sorted elements need 18 iterations approx = n\n", + "print(iterations)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Average Case Performance:" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "324\n" + ] + } + ], + "source": [ + "import random\n", + "# elements are randomly shuffled\n", + "array = [i for i in range(1, 20)]\n", + "random.shuffle(array)\n", + "\n", + "optimized_bubble_sort(array)\n", + "# 20 shuffled elements need 324 iterations approx = n * n\n", + "print(iterations)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Worst Case Performance:" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "324\n" + ] + } + ], + "source": [ + "# elements are reverse sorted\n", + "array = [i for i in range(1, 20)]\n", + "# reversing the array\n", + "array = array[::-1]\n", + "\n", + "optimized_bubble_sort(array)\n", + "# 20 REVERSE sorted elements need 324 iterations approx = n * n\n", + "\n", + "print(iterations)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Applications" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "When you're doing something quick and dirty and for some reason you can't just use the standard library's sorting algorithm. The only advantage this has over insertion sort is being slightly easier to implement." + ] + } + ], + "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.5.2" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} From 0eb9eded17a1252d7a710665263d7f8c945caa82 Mon Sep 17 00:00:00 2001 From: Omkar Pathak Date: Wed, 20 Sep 2017 07:25:24 +0530 Subject: [PATCH 03/28] Added Selection Sort --- Sorting/2. Selection_Sort.ipynb | 182 ++++++++++++++++++++++++++++++++ 1 file changed, 182 insertions(+) create mode 100644 Sorting/2. Selection_Sort.ipynb diff --git a/Sorting/2. Selection_Sort.ipynb b/Sorting/2. Selection_Sort.ipynb new file mode 100644 index 0000000..189abe7 --- /dev/null +++ b/Sorting/2. Selection_Sort.ipynb @@ -0,0 +1,182 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Selection Sort" + ] + }, + { + "cell_type": "code", + "execution_count": 77, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def selection_sort(array):\n", + " global iterations\n", + " iterations = 0\n", + " for i in range(len(array)):\n", + " minimum_index = i\n", + " for j in range(i + 1, len(array)):\n", + " iterations += 1\n", + " if array[minimum_index] > array[j]:\n", + " minimum_index = j\n", + " \n", + " # Swap the found minimum element with \n", + " # the first element\n", + " if minimum_index != i:\n", + " array[i], array[minimum_index] = array[minimum_index], array[i]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Time Complexity:\n", + "\n", + "- Best Case: O(n * n)\n", + "- Average Case: O(n * n)\n", + "- Worst Case: O(n * n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Code for executing and seeing the difference in time complexities" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Best Case Performance:" + ] + }, + { + "cell_type": "code", + "execution_count": 54, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]\n", + "190\n" + ] + } + ], + "source": [ + "# When array is already sorted\n", + "array = [i for i in range(20)]\n", + "selection_sort(array)\n", + "\n", + "print(array)\n", + "print(iterations)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Average Case Performance:" + ] + }, + { + "cell_type": "code", + "execution_count": 55, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]\n", + "190\n" + ] + } + ], + "source": [ + "# when array is shuffled\n", + "import random\n", + "array = [i for i in range(20)]\n", + "random.shuffle(array)\n", + "\n", + "selection_sort(array)\n", + "\n", + "print(array)\n", + "print(iterations)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Worst Case Performance:" + ] + }, + { + "cell_type": "code", + "execution_count": 78, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]\n", + "190\n" + ] + } + ], + "source": [ + "# when array is reverse sorted\n", + "array = [i for i in range(20)]\n", + "array = array[::-1]\n", + "\n", + "selection_sort(array)\n", + "print(array)\n", + "print(iterations)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Applications:" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "No real life applications as such because of O(n * n) behaviour. However, bubble sort, selection sort and insertion sort are the basic sorting algorithm taught for every beginner" + ] + } + ], + "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.5.2" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} From f9823d7dd99006369b9a722408062d9397213f6b Mon Sep 17 00:00:00 2001 From: Omkar Pathak Date: Thu, 21 Sep 2017 07:45:50 +0530 Subject: [PATCH 04/28] Added Insertion Sort --- Sorting/3. Insertion_Sort.ipynb | 184 ++++++++++++++++++++++++++++++++ 1 file changed, 184 insertions(+) create mode 100644 Sorting/3. Insertion_Sort.ipynb diff --git a/Sorting/3. Insertion_Sort.ipynb b/Sorting/3. Insertion_Sort.ipynb new file mode 100644 index 0000000..3018325 --- /dev/null +++ b/Sorting/3. Insertion_Sort.ipynb @@ -0,0 +1,184 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Insertion Sort" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def insertion_sort(array):\n", + " global iterations\n", + " iterations = 0\n", + " for i in range(1, len(array)):\n", + " current_value = array[i]\n", + " for j in range(i - 1, -1, -1):\n", + " iterations += 1\n", + " if array[j] > current_value:\n", + " array[j], array[j + 1] = array[j + 1], array[j] # swap\n", + " else:\n", + " array[j + 1] = current_value\n", + " break" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Time Complexity:\n", + "\n", + "- Best Case: O(n)\n", + "- Average Case: O(n * n)\n", + "- Worst Case: O(n * n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Code for executing and seeing the difference in time complexities" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Best Case Performance:" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]\n", + "18\n" + ] + } + ], + "source": [ + "# elements are already sorted\n", + "array = [i for i in range(1, 20)]\n", + "\n", + "insertion_sort(array)\n", + "# 20 ALREADY sorted elements need 18 iterations approx = n\n", + "print(array)\n", + "print(iterations)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Average Case Performance:" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]\n", + "89\n" + ] + } + ], + "source": [ + "import random\n", + "# elements are randomly shuffled\n", + "array = [i for i in range(1, 20)]\n", + "random.shuffle(array)\n", + "\n", + "insertion_sort(array)\n", + "# 20 shuffled elements need 324 iterations approx = n * n\n", + "print(array)\n", + "print(iterations)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Worst Case Performance:" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]\n", + "171\n" + ] + } + ], + "source": [ + "# elements are reverse sorted\n", + "array = [i for i in range(1, 20)]\n", + "# reversing the array\n", + "array = array[::-1]\n", + "\n", + "insertion_sort(array)\n", + "# 20 REVERSE sorted elements need 324 iterations approx = n * n\n", + "\n", + "print(array)\n", + "print(iterations)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Applications" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "More efficient that other sorts when N is comparatively smaller, say < 30." + ] + } + ], + "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.5.2" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} From 94fa99313d6b6777cdbacd2409220095ddc3a41b Mon Sep 17 00:00:00 2001 From: Omkar Pathak Date: Fri, 22 Sep 2017 08:40:24 +0530 Subject: [PATCH 05/28] Added Merge Sort --- Sorting/4. Merge_Sort.ipynb | 209 ++++++++++++++++++++++++++++++++++++ 1 file changed, 209 insertions(+) create mode 100644 Sorting/4. Merge_Sort.ipynb diff --git a/Sorting/4. Merge_Sort.ipynb b/Sorting/4. Merge_Sort.ipynb new file mode 100644 index 0000000..4baecb8 --- /dev/null +++ b/Sorting/4. Merge_Sort.ipynb @@ -0,0 +1,209 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Merge Sort" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": {}, + "outputs": [], + "source": [ + "def merge_sort(array):\n", + " if len(array) < 2:\n", + " return array\n", + " \n", + " mid = len(array) // 2\n", + " left = merge_sort(array[:mid])\n", + " right = merge_sort(array[mid:])\n", + " \n", + " return merge(left, right)\n", + "\n", + "def merge(left, right):\n", + " result = []\n", + " i, j = 0, 0\n", + " while i < len(left) or j < len(right):\n", + " if left[i] <= right[j]:\n", + " result.append(left[i])\n", + " i += 1\n", + " else:\n", + " result.append(right[j])\n", + " j += 1\n", + " if i == len(left) or j == len(right):\n", + " result.extend(left[i:] or right[j:])\n", + " break\n", + " \n", + " return result" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "### Time Complexity:\n", + "\n", + "- Best Case: O(n log2(n))\n", + "- Average Case: O(n log2(n))\n", + "- Worst Case: O(n log2(n))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Why O(n log n) ?" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If you are given two sorted arrays(say A & B) of length n/2 then it will take O(n) time to merge and make a sorted array of length n.\n", + "\n", + "But if A and B are not sorted then we need to sort them first. For this we first divide array A and B of length n/2 each into two arrays of length n/4 and suppose these two arrays are already sorted.\n", + "\n", + "Now to merge two sorted array of length n/4 to make array A of length n/2 will take O(n/2) time and similarly array B formation will also take O(n/2) time.\n", + "\n", + "So total time to make array A and B both also took O(n). So at every stage it is taking O(n) time. So the total time for merge sort will be O(no. of stages * n).\n", + "\n", + "Here we are dividing array into two parts at every stage and we will continue dividing untill length of two divided array is one.\n", + "\n", + "So if length of array is eight then we need to divide it three times to get arrays of length one like this\n", + "\n", + "8 = 4+4 = 2+2+2+2 = 1+1+1+1+1+1+1+1\n", + "\n", + "So\n", + "\n", + "no. of stages = log2(8) = 3\n", + "\n", + "That is why merge sort is O(nlog(n)) with log2(n) iteration.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Code for executing and seeing the difference in time complexities" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Best Case Performance:" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]\n", + "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]\n" + ] + } + ], + "source": [ + "# elements are already sorted\n", + "array = [i for i in range(1, 20)]\n", + "\n", + "print(array)\n", + "# 20 ALREADY sorted elements need 18 iterations approx = n\n", + "print(merge_sort(array))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Average Case Performance:" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[5, 2, 17, 15, 3, 13, 9, 12, 7, 19, 11, 18, 14, 10, 1, 16, 4, 8, 6]\n", + "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]\n" + ] + } + ], + "source": [ + "import random\n", + "# elements are randomly shuffled\n", + "array = [i for i in range(1, 20)]\n", + "random.shuffle(array)\n", + "print(array)\n", + "# 20 shuffled elements need 324 iterations approx = n * n\n", + "print(merge_sort(array))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Worst Case Performance:" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1]\n", + "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]\n" + ] + } + ], + "source": [ + "# elements are reverse sorted\n", + "array = [i for i in range(1, 20)]\n", + "# reversing the array\n", + "array = array[::-1]\n", + "\n", + "print(array)\n", + "# 20 REVERSE sorted elements need 324 iterations approx = n * n\n", + "print(merge_sort(array))" + ] + } + ], + "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.5.2" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} From f0f63186ab01b9127b858176ac294854c4a10ef5 Mon Sep 17 00:00:00 2001 From: Omkar Pathak Date: Mon, 23 Oct 2017 20:58:51 +0530 Subject: [PATCH 06/28] Added QuickSort --- .../5. Quick_Sort-checkpoint.ipynb | 210 ++++++++++++++++++ Sorting/5. Quick_Sort.ipynb | 210 ++++++++++++++++++ 2 files changed, 420 insertions(+) create mode 100644 Sorting/.ipynb_checkpoints/5. Quick_Sort-checkpoint.ipynb create mode 100644 Sorting/5. Quick_Sort.ipynb diff --git a/Sorting/.ipynb_checkpoints/5. Quick_Sort-checkpoint.ipynb b/Sorting/.ipynb_checkpoints/5. Quick_Sort-checkpoint.ipynb new file mode 100644 index 0000000..9e2186d --- /dev/null +++ b/Sorting/.ipynb_checkpoints/5. Quick_Sort-checkpoint.ipynb @@ -0,0 +1,210 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Quick Sort" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [], + "source": [ + "def partition(array, low, high):\n", + " i = low - 1\n", + " pivot = array[high]\n", + " \n", + " for j in range(low, high):\n", + " if array[j] < pivot:\n", + " i += 1\n", + " array[i], array[j] = array[j], array[i]\n", + " \n", + " array[i + 1], array[high] = array[high], array[i + 1]\n", + " return i + 1\n", + "\n", + "def quick_sort(array, low, high):\n", + " if low < high:\n", + " temp = partition(array, low, high)\n", + " \n", + " quick_sort(array, low, temp - 1)\n", + " quick_sort(array, temp + 1, high)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "### Time Complexity:\n", + "\n", + "- Best Case: O(n log2(n))\n", + "- Average Case: O(n log2(n))\n", + "- Worst Case: O(n * n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Code for executing and seeing the difference in time complexities" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Best Case Performance:" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]\n", + "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]\n" + ] + } + ], + "source": [ + "# elements are already sorted\n", + "array = [i for i in range(1, 20)]\n", + "\n", + "print(array)\n", + "# 20 ALREADY sorted elements need 18 iterations approx = n\n", + "quick_sort(array, 0, len(array) - 1)\n", + "\n", + "print(array)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Average Case Performance:" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[1, 3, 2, 13, 6, 17, 5, 7, 9, 11, 8, 19, 18, 4, 16, 10, 14, 12, 15]\n", + "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]\n" + ] + } + ], + "source": [ + "import random\n", + "# elements are randomly shuffled\n", + "array = [i for i in range(1, 20)]\n", + "random.shuffle(array)\n", + "print(array)\n", + "# 20 shuffled elements need 324 iterations approx = n * n\n", + "quick_sort(array, 0, len(array) - 1)\n", + "print(array)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Worst Case Performance:" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1]\n", + "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]\n" + ] + } + ], + "source": [ + "# elements are reverse sorted\n", + "array = [i for i in range(1, 20)]\n", + "# reversing the array\n", + "array = array[::-1]\n", + "\n", + "print(array)\n", + "# 20 REVERSE sorted elements need 324 iterations approx = n * n\n", + "quick_sort(array, 0, len(array) - 1)\n", + "print(array)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Why Quick Sort is preferred over MergeSort for sorting Arrays" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Quick Sort in its general form is an in-place sort (i.e. it doesn’t require any extra storage) whereas merge sort requires O(N) extra storage, N denoting the array size which may be quite expensive. Allocating and de-allocating the extra space used for merge sort increases the running time of the algorithm. Comparing average complexity we find that both type of sorts have O(NlogN) average complexity but the constants differ. For arrays, merge sort loses due to the use of extra O(N) storage space.\n", + "\n", + "Most practical implementations of Quick Sort use randomized version. The randomized version has expected time complexity of O(nLogn). The worst case is possible in randomized version also, but worst case doesn’t occur for a particular pattern (like sorted array) and randomized Quick Sort works well in practice.\n", + "\n", + "Quick Sort is also a cache friendly sorting algorithm as it has good locality of reference when used for arrays.\n", + "\n", + "Quick Sort is also tail recursive, therefore tail call optimizations is done." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Why MergeSort is preferred over QuickSort for Linked Lists?" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In case of linked lists the case is different mainly due to difference in memory allocation of arrays and linked lists. Unlike arrays, linked list nodes may not be adjacent in memory. Unlike array, in linked list, we can insert items in the middle in O(1) extra space and O(1) time. Therefore merge operation of merge sort can be implemented without extra space for linked lists.\n", + "\n", + "In arrays, we can do random access as elements are continuous in memory. Let us say we have an integer (4-byte) array A and let the address of A[0] be x then to access A[i], we can directly access the memory at (x + i*4). Unlike arrays, we can not do random access in linked list. Quick Sort requires a lot of this kind of access. In linked list to access i’th index, we have to travel each and every node from the head to i’th node as we don’t have continuous block of memory. Therefore, the overhead increases for quick sort. Merge sort accesses data sequentially and the need of random access is low." + ] + } + ], + "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.5.2" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/Sorting/5. Quick_Sort.ipynb b/Sorting/5. Quick_Sort.ipynb new file mode 100644 index 0000000..9e2186d --- /dev/null +++ b/Sorting/5. Quick_Sort.ipynb @@ -0,0 +1,210 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Quick Sort" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [], + "source": [ + "def partition(array, low, high):\n", + " i = low - 1\n", + " pivot = array[high]\n", + " \n", + " for j in range(low, high):\n", + " if array[j] < pivot:\n", + " i += 1\n", + " array[i], array[j] = array[j], array[i]\n", + " \n", + " array[i + 1], array[high] = array[high], array[i + 1]\n", + " return i + 1\n", + "\n", + "def quick_sort(array, low, high):\n", + " if low < high:\n", + " temp = partition(array, low, high)\n", + " \n", + " quick_sort(array, low, temp - 1)\n", + " quick_sort(array, temp + 1, high)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "### Time Complexity:\n", + "\n", + "- Best Case: O(n log2(n))\n", + "- Average Case: O(n log2(n))\n", + "- Worst Case: O(n * n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Code for executing and seeing the difference in time complexities" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Best Case Performance:" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]\n", + "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]\n" + ] + } + ], + "source": [ + "# elements are already sorted\n", + "array = [i for i in range(1, 20)]\n", + "\n", + "print(array)\n", + "# 20 ALREADY sorted elements need 18 iterations approx = n\n", + "quick_sort(array, 0, len(array) - 1)\n", + "\n", + "print(array)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Average Case Performance:" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[1, 3, 2, 13, 6, 17, 5, 7, 9, 11, 8, 19, 18, 4, 16, 10, 14, 12, 15]\n", + "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]\n" + ] + } + ], + "source": [ + "import random\n", + "# elements are randomly shuffled\n", + "array = [i for i in range(1, 20)]\n", + "random.shuffle(array)\n", + "print(array)\n", + "# 20 shuffled elements need 324 iterations approx = n * n\n", + "quick_sort(array, 0, len(array) - 1)\n", + "print(array)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Worst Case Performance:" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1]\n", + "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]\n" + ] + } + ], + "source": [ + "# elements are reverse sorted\n", + "array = [i for i in range(1, 20)]\n", + "# reversing the array\n", + "array = array[::-1]\n", + "\n", + "print(array)\n", + "# 20 REVERSE sorted elements need 324 iterations approx = n * n\n", + "quick_sort(array, 0, len(array) - 1)\n", + "print(array)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Why Quick Sort is preferred over MergeSort for sorting Arrays" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Quick Sort in its general form is an in-place sort (i.e. it doesn’t require any extra storage) whereas merge sort requires O(N) extra storage, N denoting the array size which may be quite expensive. Allocating and de-allocating the extra space used for merge sort increases the running time of the algorithm. Comparing average complexity we find that both type of sorts have O(NlogN) average complexity but the constants differ. For arrays, merge sort loses due to the use of extra O(N) storage space.\n", + "\n", + "Most practical implementations of Quick Sort use randomized version. The randomized version has expected time complexity of O(nLogn). The worst case is possible in randomized version also, but worst case doesn’t occur for a particular pattern (like sorted array) and randomized Quick Sort works well in practice.\n", + "\n", + "Quick Sort is also a cache friendly sorting algorithm as it has good locality of reference when used for arrays.\n", + "\n", + "Quick Sort is also tail recursive, therefore tail call optimizations is done." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Why MergeSort is preferred over QuickSort for Linked Lists?" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In case of linked lists the case is different mainly due to difference in memory allocation of arrays and linked lists. Unlike arrays, linked list nodes may not be adjacent in memory. Unlike array, in linked list, we can insert items in the middle in O(1) extra space and O(1) time. Therefore merge operation of merge sort can be implemented without extra space for linked lists.\n", + "\n", + "In arrays, we can do random access as elements are continuous in memory. Let us say we have an integer (4-byte) array A and let the address of A[0] be x then to access A[i], we can directly access the memory at (x + i*4). Unlike arrays, we can not do random access in linked list. Quick Sort requires a lot of this kind of access. In linked list to access i’th index, we have to travel each and every node from the head to i’th node as we don’t have continuous block of memory. Therefore, the overhead increases for quick sort. Merge sort accesses data sequentially and the need of random access is low." + ] + } + ], + "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.5.2" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} From c1eb99dcb2b66546ec92afaef0fb10f24d4876a3 Mon Sep 17 00:00:00 2001 From: JagritiJ Date: Sun, 4 Feb 2018 17:11:16 +0530 Subject: [PATCH 07/28] Update Arrays.ipynb Hi Omkar, I was looking for Algo and DS in Python when I found this repo. I was reading through the first few lines and found some spelling mistakes. Proposing to change that. --- Arrays/Arrays.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Arrays/Arrays.ipynb b/Arrays/Arrays.ipynb index 955a607..e6e8803 100644 --- a/Arrays/Arrays.ipynb +++ b/Arrays/Arrays.ipynb @@ -26,7 +26,7 @@ "metadata": {}, "source": [ "* Array is a data structure used to store homogeneous elements at contiguous locations.\n", - "* One memory block is allocated for the entire array Lo hold the clements of the arTny. The array elements can be accessed in constant time by using the index of the parliculnr element as the subscript." + "* One memory block is allocated for the entire array to hold the elements of the arrayy. The array elements can be accessed in constant time by using the index of the parliculnr element as the subscript." ] }, { From 717028822200af9ff0547a389570b419e43a313f Mon Sep 17 00:00:00 2001 From: Omkar Pathak Date: Wed, 4 Apr 2018 07:27:34 +0530 Subject: [PATCH 08/28] Bug fixes --- Queue/Queue.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Queue/Queue.py b/Queue/Queue.py index 0305c4f..38edddc 100644 --- a/Queue/Queue.py +++ b/Queue/Queue.py @@ -35,7 +35,7 @@ def dequeue(self): if self.isEmpty(): return -1 # queue underflow else: - self.queue.pop() + self.queue.pop(0) self.size -= 1 if self.size == 0: self.front = self.rear = 0 From eb580e07d8b488128c286d2ab859d0f5c8ea5cb3 Mon Sep 17 00:00:00 2001 From: SAYAN SANYAL <37104041+s-sanyal@users.noreply.github.com> Date: Thu, 4 Oct 2018 08:45:01 +0530 Subject: [PATCH 09/28] Changed P05_CheckForPairSum.py (#4) * Changes made in Arrays * Added Sieve Of Eratosthenes * Made the code Python 3 compatible * Changed the function name --- Arrays/P05_CheckForPairSum.py | 24 +++++++------- .../P04_SieveOfEratosthenes.py | 32 +++++++++++++++++++ 2 files changed, 45 insertions(+), 11 deletions(-) create mode 100644 Dynamic Programming/P04_SieveOfEratosthenes.py diff --git a/Arrays/P05_CheckForPairSum.py b/Arrays/P05_CheckForPairSum.py index 45b42e5..d71e6db 100644 --- a/Arrays/P05_CheckForPairSum.py +++ b/Arrays/P05_CheckForPairSum.py @@ -4,8 +4,10 @@ # in S whose sum is exactly x. def checkSum(array, sum): - # sort the array in descending order - array = quickSort(array) + # sort the array in ascending order + # new changes : made use of Python's inbuilt Merge Sort method + # Reason for such change : Worst case Time complexity of Quick Sort is O(n^2) whereas Worst Case Complexity of Merge Sort is O(nlog(n)) + array = sorted(array) leftIndex = 0 rightIndex = len(array) - 1 @@ -20,14 +22,14 @@ def checkSum(array, sum): return False, False -def quickSort(array): - if len(array) <= 1: - return array - pivot = array[len(array) // 2] - left = [x for x in array if x < pivot] - middle = [x for x in array if x == pivot] - right = [x for x in array if x > pivot] - return quickSort(left) + middle + quickSort(right) +##def quickSort(array): +## if len(array) <= 1: +## return array +## pivot = array[len(array) // 2] +## left = [x for x in array if x < pivot] +## middle = [x for x in array if x == pivot] +## right = [x for x in array if x > pivot] +## return quickSort(left) + middle + quickSort(right) if __name__ == '__main__': myArray = [10, 20, 30, 40, 50] @@ -37,4 +39,4 @@ def quickSort(array): if(number1 and number2): print('Array has elements:', number1, 'and', number2, 'with sum:', sum) else: - print('Array doesn\'t has elements with the sum:', sum) + print('Array doesn\'t have elements with the sum:', sum) diff --git a/Dynamic Programming/P04_SieveOfEratosthenes.py b/Dynamic Programming/P04_SieveOfEratosthenes.py new file mode 100644 index 0000000..4c980fd --- /dev/null +++ b/Dynamic Programming/P04_SieveOfEratosthenes.py @@ -0,0 +1,32 @@ + +# Python program to print all primes smaller than or equal to +# n using Sieve of Eratosthenes + +def sieve_of_eratosthenes(n): + + # Create a boolean array "prime[0..n]" and initialize + # all entries it as true. A value in prime[i] will + # finally be false if i is Not a prime, else true. + prime = [True for i in range(n+1)] + p = 2 + while (p * p <= n): + + # If prime[p] is not changed, then it is a prime + if (prime[p] == True): + + # Update all multiples of p + for i in range(p * 2, n+1, p): + prime[i] = False + p += 1 + + # Print all prime numbers + for p in range(2, n): + if prime[p]: + print (p), + +# driver program +if __name__=='__main__': + n = 30 + print ("Following are the prime numbers smaller"), + print ("than or equal to", n ) + sieve_of_eratosthenes(n) From de0512059254cc9b7c6b9ca0b917595cf0523a57 Mon Sep 17 00:00:00 2001 From: parameswaran-natarajan Date: Wed, 24 Oct 2018 20:35:09 +0530 Subject: [PATCH 10/28] Create ListViewUsingTree.py (#7) Add an n-ary tree to construct list view --- Trees/ListViewUsingTree.py | 67 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 Trees/ListViewUsingTree.py diff --git a/Trees/ListViewUsingTree.py b/Trees/ListViewUsingTree.py new file mode 100644 index 0000000..5f12065 --- /dev/null +++ b/Trees/ListViewUsingTree.py @@ -0,0 +1,67 @@ +# Author: Parameswaran + +# sample object +class Sample: + def __init__(self, data_description, node_id, parent_id=""): + self.data_description = data_description + self.node_id = node_id + self.parent_id = parent_id + + +# Node structure (Basically N-ary Tree) +class Node: + def __init__(self, data): + self.data = Sample(data['data_description'], data['node_id'], data['parent_id']) + self.children = [] + + +class Tree: + def __init__(self, data): + self.Root = data + + def insert_child(self, root, new_node): + + # if the list item's parent_id is equal to the current node it will append the node in their child array. + + if root.data.node_id == new_node.data.parent_id: + root.children.append(new_node) + + # else it will check all the node and their children list whether the parent_id is same. + + elif len(root.children) > 0: + for each_child in root.children: + # it will create a recursive call for all nodes to treate as a root and search for all its child_list nodes + self.insert_child(each_child, new_node) + + def print_tree(self, root, point): + print(point, root.data.node_id, root.data.parent_id, root.data.data_description) + if len(root.children) > 0: + point += "_" + for each_child in root.children: + self.print_tree(each_child, point) + + +data = {'data_description': 'Sample_root_1', 'node_id': '1', 'parent_id': ''} +data1 = {'data_description': 'Sample_root_2', 'node_id': '2', 'parent_id': '1'} +data2 = {'data_description': 'Sample_root_3', 'node_id': '3', 'parent_id': '1'} +data3 = {'data_description': 'Sample_root_4', 'node_id': '4', 'parent_id': '2'} +data4 = {'data_description': 'Sample_root_5', 'node_id': '5', 'parent_id': '3'} +data5 = {'data_description': 'Sample_root_6', 'node_id': '6', 'parent_id': '4'} +data6 = {'data_description': 'Sample_root_7', 'node_id': '7', 'parent_id': '4'} + +a = Tree(Node(data)) +a.insert_child(a.Root, Node(data1)) +a.insert_child(a.Root, Node(data2)) +a.insert_child(a.Root, Node(data3)) +a.insert_child(a.Root, Node(data4)) +a.insert_child(a.Root, Node(data5)) +a.insert_child(a.Root, Node(data6)) +a.print_tree(a.Root, "|_") + +# |_ 1 Sample_root_1 +# |__ 2 1 Sample_root_2 +# |___ 4 2 Sample_root_4 +# |____ 6 4 Sample_root_6 +# |____ 7 4 Sample_root_7 +# |__ 3 1 Sample_root_3 +# |___ 5 3 Sample_root_5 From 49e16d69f64257f789c38c307bfe8b11b15238ac Mon Sep 17 00:00:00 2001 From: Viraj Gite <31462837+virajgite@users.noreply.github.com> Date: Mon, 17 Dec 2018 22:46:46 -0500 Subject: [PATCH 11/28] queue rear and pop edited (#8) previously..... 1. updating queue rear before incrementing queue size in the queue.enqueue( ) sets queue rear to actual rear-1 2. queue.pop( ) pops elements from rear, instead from the front. --- Queue/Queue.ipynb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Queue/Queue.ipynb b/Queue/Queue.ipynb index 806a9b3..1126cf7 100644 --- a/Queue/Queue.ipynb +++ b/Queue/Queue.ipynb @@ -77,6 +77,7 @@ " return -1 # queue overflow\n", " else:\n", " self.queue.append(data)\n", + " self.size += 1\n" " \n", " # assign the rear as size of the queue and front as 0\n", " if self.front is None:\n", @@ -84,14 +85,14 @@ " else:\n", " self.rear = self.size\n", " \n", - " self.size += 1\n", + " " \n", " # to pop an element from the front end of the queue\n", " def dequeue(self):\n", " if self.isEmpty():\n", " return -1 # queue underflow\n", " else:\n", - " self.queue.pop()\n", + " self.queue.pop(self.front)\n", " self.size -= 1\n", " if self.size == 0:\n", " self.front = self.rear = 0\n", From f9568d2ff371eadb2b5ee60720c19a24dd978df1 Mon Sep 17 00:00:00 2001 From: Viraj Gite <31462837+virajgite@users.noreply.github.com> Date: Fri, 21 Dec 2018 20:06:26 -0500 Subject: [PATCH 12/28] Revert "queue rear and pop edited (#8)" (#9) This reverts commit 49e16d69f64257f789c38c307bfe8b11b15238ac. --- Queue/Queue.ipynb | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Queue/Queue.ipynb b/Queue/Queue.ipynb index 1126cf7..806a9b3 100644 --- a/Queue/Queue.ipynb +++ b/Queue/Queue.ipynb @@ -77,7 +77,6 @@ " return -1 # queue overflow\n", " else:\n", " self.queue.append(data)\n", - " self.size += 1\n" " \n", " # assign the rear as size of the queue and front as 0\n", " if self.front is None:\n", @@ -85,14 +84,14 @@ " else:\n", " self.rear = self.size\n", " \n", - " + " self.size += 1\n", " \n", " # to pop an element from the front end of the queue\n", " def dequeue(self):\n", " if self.isEmpty():\n", " return -1 # queue underflow\n", " else:\n", - " self.queue.pop(self.front)\n", + " self.queue.pop()\n", " self.size -= 1\n", " if self.size == 0:\n", " self.front = self.rear = 0\n", From 76fe99e0f9174a3284fa9d813c4d3100702b09a2 Mon Sep 17 00:00:00 2001 From: Abhishak Varshney <35887568+abhishakvarshney@users.noreply.github.com> Date: Fri, 26 Apr 2019 16:39:42 +0530 Subject: [PATCH 13/28] Update Array (#11) --- Arrays/Arrays.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Arrays/Arrays.ipynb b/Arrays/Arrays.ipynb index e6e8803..cbc2cc1 100644 --- a/Arrays/Arrays.ipynb +++ b/Arrays/Arrays.ipynb @@ -26,7 +26,7 @@ "metadata": {}, "source": [ "* Array is a data structure used to store homogeneous elements at contiguous locations.\n", - "* One memory block is allocated for the entire array to hold the elements of the arrayy. The array elements can be accessed in constant time by using the index of the parliculnr element as the subscript." + "* One memory block is allocated for the entire array to hold the elements of the array. The array elements can be accessed in constant time by using the index of the parliculnr element as the subscript." ] }, { From e1fe0e03777e37cbcb5601e699c89165c4db7696 Mon Sep 17 00:00:00 2001 From: Raajesh Date: Wed, 7 Aug 2019 10:19:57 +0530 Subject: [PATCH 14/28] Fixed negative outputs for 0 and 1 as input (#12) --- Dynamic Programming/P01_Fibonnaci.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dynamic Programming/P01_Fibonnaci.py b/Dynamic Programming/P01_Fibonnaci.py index e3da115..05ea778 100644 --- a/Dynamic Programming/P01_Fibonnaci.py +++ b/Dynamic Programming/P01_Fibonnaci.py @@ -14,7 +14,7 @@ def fibonacci(number): # traditional recursive fibonacci function def fibonacciRec(number): - if number <= 1: + if number == 1 or number == 0: return number else: return (fibonacciRec(number - 1) + fibonacciRec(number - 2)) From 48882bc7d8847e849e12a9d3c683da7c496caf74 Mon Sep 17 00:00:00 2001 From: Saksham Jain <43048913+sakshamj74@users.noreply.github.com> Date: Wed, 2 Oct 2019 21:03:23 +0530 Subject: [PATCH 15/28] Circular Linked List (#13) --- Linked Lists/circular_linked_list.py | 55 ++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 Linked Lists/circular_linked_list.py diff --git a/Linked Lists/circular_linked_list.py b/Linked Lists/circular_linked_list.py new file mode 100644 index 0000000..30de914 --- /dev/null +++ b/Linked Lists/circular_linked_list.py @@ -0,0 +1,55 @@ +#Represents the node of list. +class Node: + def __init__(self,data): + self.data = data; + self.next = None; + +class CreateList: + #Declaring head and tail pointer as null. + def __init__(self): + self.head = Node(None); + self.tail = Node(None); + self.head.next = self.tail; + self.tail.next = self.head; + + #This function will add the new node at the end of the list. + def add(self,data): + newNode = Node(data); + #Checks if the list is empty. + if self.head.data is None: + #If list is empty, both head and tail would point to new node. + self.head = newNode; + self.tail = newNode; + newNode.next = self.head; + else: + #tail will point to new node. + self.tail.next = newNode; + #New node will become new tail. + self.tail = newNode; + #Since, it is circular linked list tail will point to head. + self.tail.next = self.head; + + #Displays all the nodes in the list + def display(self): + current = self.head; + if self.head is None: + print("List is empty"); + return; + else: + print("Nodes of the circular linked list: "); + #Prints each node by incrementing pointer. + print(current.data), + while(current.next != self.head): + current = current.next; + print(current.data), + + +class CircularLinkedList: + cl = CreateList(); + #Adds data to the list + cl.add(1); + cl.add(2); + cl.add(3); + cl.add(4); + #Displays all the nodes present in the list + cl.display(); From 1cee5b943d6f770813069082993eef5fa8fed6d5 Mon Sep 17 00:00:00 2001 From: Abhishek Jha <44729252+abhishek-kehsihba@users.noreply.github.com> Date: Wed, 2 Oct 2019 21:05:19 +0530 Subject: [PATCH 16/28] Added some commits in Sort section (#14) * Update1: Bubble Sort(Removing Extra Iterations) Removed the extra iterations in simple bubble_sort() function, so as the real meaning of bubble sort come out. * Update 1. Bubble_Sort.ipynb * Update Quick sort comments Added extra comments in functions, for better understanding. * Update 5. Quick_Sort.ipynb * Update P01_Fibonnaci.py Added the recursion+memoization method for Fibonacci sequence. --- Dynamic Programming/P01_Fibonnaci.py | 15 +++++++++++++++ Sorting/1. Bubble_Sort.ipynb | 5 +++-- Sorting/5. Quick_Sort.ipynb | 12 ++++++++++-- 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/Dynamic Programming/P01_Fibonnaci.py b/Dynamic Programming/P01_Fibonnaci.py index 05ea778..53d1745 100644 --- a/Dynamic Programming/P01_Fibonnaci.py +++ b/Dynamic Programming/P01_Fibonnaci.py @@ -19,6 +19,15 @@ def fibonacciRec(number): else: return (fibonacciRec(number - 1) + fibonacciRec(number - 2)) +# improved recursive fibonacci function +def fib_memoization(n, lookup): + if n == 0 or n == 1 : + lookup[n] = n + if lookup[n] is None: + lookup[n] = fib(n-1 , lookup) + fib(n-2 , lookup) + return lookup[n] + + if __name__ == '__main__': userInput = int(input('Enter the number: ')) @@ -37,3 +46,9 @@ def fibonacciRec(number): result = fibonacciRec(userInput) stopTime = time.time() print('Time:', (stopTime - startTime), 'Result:', result) + + startTime = time.time() + lookup=[None]*(101) + result = fib_memoization(userInput,lookup) + stopTime = time.time() + print('Time:', (stopTime - startTime), 'Result:', result) diff --git a/Sorting/1. Bubble_Sort.ipynb b/Sorting/1. Bubble_Sort.ipynb index 1728a9f..f8e6807 100644 --- a/Sorting/1. Bubble_Sort.ipynb +++ b/Sorting/1. Bubble_Sort.ipynb @@ -16,8 +16,9 @@ "outputs": [], "source": [ "def bubble_sort(array):\n", - " for i in range(len(array) - 1):\n", - " for j in range(len(array) - 1):\n", + " n=len(array)\n", + " for i in range(0,n):\n", + " for j in range(0,n-i-1):\n", " if array[j] > array[j + 1]:\n", " array[j], array[j + 1] = array[j + 1], array[j] # swap" ] diff --git a/Sorting/5. Quick_Sort.ipynb b/Sorting/5. Quick_Sort.ipynb index 9e2186d..cc2d444 100644 --- a/Sorting/5. Quick_Sort.ipynb +++ b/Sorting/5. Quick_Sort.ipynb @@ -14,11 +14,15 @@ "outputs": [], "source": [ "def partition(array, low, high):\n", - " i = low - 1\n", - " pivot = array[high]\n", + " i = low - 1 # index of smaller element\n", + " pivot = array[high] # pivot \n", " \n", " for j in range(low, high):\n", + " # If current element is smaller than the pivot\n", + " \n", " if array[j] < pivot:\n", + " # increment index of smaller element\n", + " \n", " i += 1\n", " array[i], array[j] = array[j], array[i]\n", " \n", @@ -27,8 +31,12 @@ "\n", "def quick_sort(array, low, high):\n", " if low < high:\n", + " # pi is partitioning index, arr[p] is now\n", + " # at right place \n", " temp = partition(array, low, high)\n", " \n", + " # Separately sort elements before\n", + " # partition and after partition \n", " quick_sort(array, low, temp - 1)\n", " quick_sort(array, temp + 1, high)" ] From 3a2855ffc86af8fd11249f8d1e7fde4b99442afc Mon Sep 17 00:00:00 2001 From: adi0311 <51120669+adi0311@users.noreply.github.com> Date: Wed, 2 Oct 2019 21:06:30 +0530 Subject: [PATCH 17/28] Added Segment Tree (#16) --- Segment Tree/SegmentTree.py | 66 ++++++++++++++++++++++++++++++++++++ Segment Tree/SegmentTree2.py | 56 ++++++++++++++++++++++++++++++ 2 files changed, 122 insertions(+) create mode 100644 Segment Tree/SegmentTree.py create mode 100644 Segment Tree/SegmentTree2.py diff --git a/Segment Tree/SegmentTree.py b/Segment Tree/SegmentTree.py new file mode 100644 index 0000000..0c0faba --- /dev/null +++ b/Segment Tree/SegmentTree.py @@ -0,0 +1,66 @@ +class SegmentTree: + def __init__(self, values): + self.valarr = values + self.arr = dict() + + #start is the starting index of node. + #end is the ending index of node. + #l is the lower bound of given query. + #r is the upper bound of given query. + + def buildTree(self, start, end, node): + if start == end: + self.arr[node] = self.valarr[start] + return + mid = (start+end)//2 + #Building the left subtree of the node. + self.buildTree(start, mid, node*2) + #Building the right subtree of the node. + self.buildTree(mid+1, end, node*2+1) + #Assign the value of node as the sum of its children. + self.arr[node] = self.arr[node*2]+self.arr[node*2+1] + + def rangeQuery(self, node, start, end, l, r): + #When start and end index of the given node lies between the query range[l, r]. + if (l <= start and r >= end): + return self.arr[node] + #When the start and end index of the given node lies completely outside of the query range[l, r]. + if (end < l or start > r): + return 0 + #In case of overlapping of the regions of the start and end index of node and query range[l, r]. + mid = (start+end)//2 + return self.rangeQuery(2*node, start, mid, l, r) + self.rangeQuery(2*node+1, mid+1, end, l, r) + + def update(self, node, newvalue, oldvalue, position, start, end): + #If position where the given value to be inserted lies within start and end index of the node. + if start <= position <= end: + self.arr[node] += (newvalue-oldvalue) + #Updating all those nodes where position lies within its start and end index. + if start != end: + mid = (start+end)//2 + self.update(node*2, newvalue, oldvalue, position, start, mid) + self.update(node*2+1, newvalue, oldvalue, position, mid+1, end) + +#Code to run the above functions +if __name__ == '__main__': + l = list(map(int, input("Enter the elements of the array separated by space:\n").split())) + st = SegmentTree(l) + st.buildTree(0, len(l)-1, 1) + + #I have assumed 1 as the base index instead of 0. + baseindex = 1 + endindex = len(l) + + #To print the constructed segment tree. + print(st.arr) + + #To print the sum of numbers between index 3 and 5. + print("Sum of numbers from index 3 and 5 is: ", st.rangeQuery(1, baseindex, endindex, 3, 5)) + + #Updating 3rd element of the array to 10. + updateindex = 3 + updatevalue = 10 + st.update(1, updatevalue, l[updateindex-1], updateindex, baseindex, endindex) + + #To print the sum of numbers between index 3 and 5 after updation + print("Updated sum of numbers from index 3 and 5 is: ", st.rangeQuery(1, baseindex, endindex, 3, 5)) \ No newline at end of file diff --git a/Segment Tree/SegmentTree2.py b/Segment Tree/SegmentTree2.py new file mode 100644 index 0000000..0b9291a --- /dev/null +++ b/Segment Tree/SegmentTree2.py @@ -0,0 +1,56 @@ +import sys + +class SegmentTree: + def __init__(self, values): + self.minarr = dict() + #Storing the original array for later use. + self.originalarr = values[:] + + # start is the starting index of node. + # end is the ending index of node. + # l is the lower bound of given query. + # r is the upper bound of given query. + + def buildminTree(self, start, end, node): + if start == end: + self.minarr[node] = self.originalarr[start] + return + mid = (start + end) // 2 + # Building the left subtree of the node. + self.buildminTree(start, mid, node*2) + # Building the right subtree of the node. + self.buildminTree(mid + 1, end, node*2 + 1) + # Assign the value of node as the sum of its children. + self.minarr[node] = min(self.minarr[node*2], self.minarr[node*2 + 1]) + + def minRangeQuery(self, node, start, end, l, r): + if l <= start and end <= r: + return self.minarr[node] + if r < start or l > end: + return sys.maxsize + mid = (start+end)//2 + return min(self.minRangeQuery(node*2, start, mid, l, r), self.minRangeQuery(node*2+1, mid+1, end, l, r)) + + def update(self, node, newvalue, position, start, end): + if start <= position <= end: + self.minarr[node] = min(self.minarr[node], newvalue) + # Updating all those nodes where position lies within its start and end index. + if start != end: + mid = (start + end) // 2 + self.update(node * 2, newvalue, position, start, mid) + self.update(node * 2 + 1, newvalue, position, mid + 1, end) + +arr = [10, 5, 9, 3, 4, 8, 6, 7, 2, 1] +st = SegmentTree(arr) +st.buildminTree(0, len(arr)-1, 1) +print("Segment Tree for given array", st.minarr) + +#Minimum from index 6 to 9. +print("Minimum of numbers from index 6 to 9 is: ", st.minRangeQuery(1, 1, len(arr), 6, 9)) +st.update(1, 2, 4, 1, len(arr)) + +print(st.minarr) + +print("Updated minimum of numbers from index 2 to 9 is: ", st.minRangeQuery(1, 1, len(arr), 2, 6)) + +#ALl the operations are same for max range Query. Just replace each min() with max and sys.maxsize with -(sys.maxsize). \ No newline at end of file From 9ad6519574a37bd6037b2fec8b759c78399b58dc Mon Sep 17 00:00:00 2001 From: Kshitiz-Jain Date: Wed, 2 Oct 2019 21:14:37 +0530 Subject: [PATCH 18/28] BST traversal (#17) * BST treversal Creates a tree of given values and gives inorder, preorder and postorder of a tree. * Make BST and its travesals * Delete TreeTravesal.py --- Trees/TreeTravesal.py | 59 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 Trees/TreeTravesal.py diff --git a/Trees/TreeTravesal.py b/Trees/TreeTravesal.py new file mode 100644 index 0000000..8f8ef4c --- /dev/null +++ b/Trees/TreeTravesal.py @@ -0,0 +1,59 @@ + + +class Node(object): + """docstring for Node""" + def __init__(self, val): + self.key = val + self.left=None + self.right=None + + +class Tree: + """docstring for Tree""" + def __init__(self,val): + self.root = Node(val) + + def insertNode(root,val): + if(root==None): + root=Node(val) + elif(root.key Date: Fri, 4 Oct 2019 04:18:21 +0100 Subject: [PATCH 19/28] Add queue-implementation-using-two-stacks.py (#18) --- .../P05_QueueImplementationUsingTwoStacks.py | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 Stack/P05_QueueImplementationUsingTwoStacks.py diff --git a/Stack/P05_QueueImplementationUsingTwoStacks.py b/Stack/P05_QueueImplementationUsingTwoStacks.py new file mode 100644 index 0000000..22afe9b --- /dev/null +++ b/Stack/P05_QueueImplementationUsingTwoStacks.py @@ -0,0 +1,49 @@ +class StackedQueue: + + def __init__(self): + self.stack = Stack() + self.alternateStack = Stack() + + def enqueue(self, item): + while(not self.stack.is_empty()): + self.alternateStack.push(self.stack.pop()) + + self.alternateStack.push(item) + + while(not self.alternateStack.is_empty()): + self.stack.push(self.alternateStack.pop()) + + def dequeue(self): + return self.stack.pop() + + def __repr__(self): + return repr(self.stack) + +class Stack: + def __init__(self): + self.items = [] + + def push(self, item): + self.items.append(item) + + def pop(self): + return self.items.pop() + + def size(self): + return len(self.items) + + def is_empty(self): + return self.items == [] + + def __repr__(self): + return str(self.items) + +if __name__ == "__main__": + structure = StackedQueue() + structure.enqueue(4) + structure.enqueue(3) + structure.enqueue(2) + structure.enqueue(1) + print(structure) + structure.dequeue() + print(structure) \ No newline at end of file From 9bc292262b5787dc5352373151aa2245faea8b03 Mon Sep 17 00:00:00 2001 From: Dhirendra Kumar Choudhary Date: Wed, 16 Oct 2019 15:43:23 +0530 Subject: [PATCH 20/28] Create heapsort.py (#23) --- Sorting/heapsort.py | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 Sorting/heapsort.py diff --git a/Sorting/heapsort.py b/Sorting/heapsort.py new file mode 100644 index 0000000..37b469c --- /dev/null +++ b/Sorting/heapsort.py @@ -0,0 +1,32 @@ +def heapify(nums, heap_size, root_index): + # Assume the index of the largest element is the root index + largest = root_index + left_child = (2 * root_index) + 1 + right_child = (2 * root_index) + 2 + + if left_child < heap_size and nums[left_child] > nums[largest]: + largest = left_child + + if right_child < heap_size and nums[right_child] > nums[largest]: + largest = right_child + + if largest != root_index: + nums[root_index], nums[largest] = nums[largest], nums[root_index] + # Heapify the new root element to ensure it's the largest + heapify(nums, heap_size, largest) + + +def heap_sort(nums): + n = len(nums) + + for i in range(n, -1, -1): + heapify(nums, n, i) + + # Move the root of the max heap to the end of + for i in range(n - 1, 0, -1): + nums[i], nums[0] = nums[0], nums[i] + heapify(nums, i, 0) + +random_list_of_nums = [35, 12, 43, 8, 51] +heap_sort(random_list_of_nums) +print(random_list_of_nums) From 2abee34a95c6368a8ad19f4bac5b54699be07ef9 Mon Sep 17 00:00:00 2001 From: 6ug Date: Wed, 16 Oct 2019 20:38:55 +0530 Subject: [PATCH 21/28] Adding radix sort to the list (#26) --- Sorting/Radix_Sort.py | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 Sorting/Radix_Sort.py diff --git a/Sorting/Radix_Sort.py b/Sorting/Radix_Sort.py new file mode 100644 index 0000000..f0c4184 --- /dev/null +++ b/Sorting/Radix_Sort.py @@ -0,0 +1,43 @@ +# Sorting Type: Radix +# +# Description: Radix sort is a sorting technique that +# sorts the elements by first grouping the individual +# digits of same place value. Then, sort the elements +# according to their increasing/decreasing order. + +from math import log10 +from random import randint + +def get_num(num, base, pos): + return (num // base ** pos) % base + +def prefix_sum(array): + for i in range(1, len(array)): + array[i] = array[i] + array[i-1] + return array + +def radixsort(l, base=10): + passes = int(log10(max(l))+1) + output = [0] * len(l) + + for pos in range(passes): + count = [0] * base + + for i in l: + digit = get_num(i, base, pos) + count[digit] +=1 + + count = prefix_sum(count) + + for i in reversed(l): + digit = get_num(i, base, pos) + count[digit] -= 1 + new_pos = count[digit] + output[new_pos] = i + + l = list(output) + return output + +l = [ randint(1, 99999) for x in range(100) ] +sorted = radixsort(l) +print(sorted) From 9033612f0883020552cf6aa7beb3daa0af723ea1 Mon Sep 17 00:00:00 2001 From: Ankit-555 <57088535+Ankit-555@users.noreply.github.com> Date: Tue, 29 Oct 2019 08:59:44 +0530 Subject: [PATCH 22/28] Added counting sort (#27) * Added counting sort * Longest Decreasing Subsequence --- .../LongestDecreasingSubsequence.py | 27 ++++++++++++++++ Sorting/Counting_sort.py | 32 +++++++++++++++++++ 2 files changed, 59 insertions(+) create mode 100644 Dynamic Programming/LongestDecreasingSubsequence.py create mode 100644 Sorting/Counting_sort.py diff --git a/Dynamic Programming/LongestDecreasingSubsequence.py b/Dynamic Programming/LongestDecreasingSubsequence.py new file mode 100644 index 0000000..e3381e9 --- /dev/null +++ b/Dynamic Programming/LongestDecreasingSubsequence.py @@ -0,0 +1,27 @@ +def lds(arr, n): + + lds = [0] * n + max = 0 + + # Initialize LDS with 1 for all index + # The minimum LDS starting with any + # element is always 1 + for i in range(n): + lds[i] = 1 + + # Compute LDS from every index + # in bottom up manner + for i in range(1, n): + for j in range(i): + if (arr[i] < arr[j] and + lds[i] < lds[j] + 1): + lds[i] = lds[j] + 1 + + # Select the maximum + # of all the LDS values + for i in range(n): + if (max < lds[i]): + max = lds[i] + + # returns the length of the LDS + return max diff --git a/Sorting/Counting_sort.py b/Sorting/Counting_sort.py new file mode 100644 index 0000000..f537321 --- /dev/null +++ b/Sorting/Counting_sort.py @@ -0,0 +1,32 @@ +def countSort(arr): + + # The output character array that will have sorted arr + output = [0 for i in range(256)] + + # Create a count array to store count of inidividul + # characters and initialize count array as 0 + count = [0 for i in range(256)] + + # For storing the resulting answer since the + # string is immutable + ans = ["" for _ in arr] + + # Store count of each character + for i in arr: + count[ord(i)] += 1 + + # Change count[i] so that count[i] now contains actual + # position of this character in output array + for i in range(256): + count[i] += count[i-1] + + # Build the output character array + for i in range(len(arr)): + output[count[ord(arr[i])]-1] = arr[i] + count[ord(arr[i])] -= 1 + + # Copy the output array to arr, so that arr now + # contains sorted characters + for i in range(len(arr)): + ans[i] = output[i] + return ans From 1572e6a87404c33542e30b06ef0cbfc6e5767b2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emre=20Do=C4=9Fan?= Date: Sun, 3 Nov 2019 05:05:53 +0300 Subject: [PATCH 23/28] Updated isEmpty function definition. (#31) 'return len(self.stack) == []' is a problematic definition. it should be either 'return len(self.stack) == 0' or 'self.stack == []' --- Stack/Stack.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Stack/Stack.ipynb b/Stack/Stack.ipynb index d494183..5fb3412 100644 --- a/Stack/Stack.ipynb +++ b/Stack/Stack.ipynb @@ -107,7 +107,7 @@ " \n", " # to check if stack is empty\n", " def isEmpty(self):\n", - " return len(self.stack) == []\n", + " return len(self.stack) == 0\n", " \n", " # for checking the size of stack\n", " def size(self):\n", From bcf7035381aca9dcfd8763721fcb68bbfa82b645 Mon Sep 17 00:00:00 2001 From: Imal Kumarage <52731064+imalK96@users.noreply.github.com> Date: Wed, 8 Jul 2020 08:35:19 +0530 Subject: [PATCH 24/28] Fixed issue 32 (#33) --- Arrays/Arrays.ipynb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Arrays/Arrays.ipynb b/Arrays/Arrays.ipynb index cbc2cc1..3c33a1c 100644 --- a/Arrays/Arrays.ipynb +++ b/Arrays/Arrays.ipynb @@ -26,7 +26,7 @@ "metadata": {}, "source": [ "* Array is a data structure used to store homogeneous elements at contiguous locations.\n", - "* One memory block is allocated for the entire array to hold the elements of the array. The array elements can be accessed in constant time by using the index of the parliculnr element as the subscript." + "* One memory block is allocated for the entire array to hold the elements of the array. The array elements can be accessed in constant time by using the index of the particular element as the subscript." ] }, { @@ -348,4 +348,4 @@ }, "nbformat": 4, "nbformat_minor": 2 -} +} \ No newline at end of file From 3cfcdf2e16f85baaa286a96062da6fd0b20f8848 Mon Sep 17 00:00:00 2001 From: SamithaDilan <43945182+SamithaDilan@users.noreply.github.com> Date: Sun, 12 Jul 2020 18:15:44 +0530 Subject: [PATCH 25/28] Changed the logic in circular queue (#34) * changed the methods in circularQueue * changed some comments Co-authored-by: Samitha --- Queue/CicularQueue.py | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/Queue/CicularQueue.py b/Queue/CicularQueue.py index 43f1086..59785c5 100644 --- a/Queue/CicularQueue.py +++ b/Queue/CicularQueue.py @@ -2,41 +2,49 @@ class CircularQueue(object): def __init__(self, limit = 10): - self.front = None - self.rear = None self.limit = limit - self.queue = [] + self.queue = [None for i in range(limit)] + self.front = self.rear = -1 # for printing the queue def __str__(self): - return ' '.join([str(i) for i in self.queue]) + if (self.rear >= self.front): + return ' '.join([str(self.queue[i]) for i in range(self.front, self.rear + 1)]) + + else: + q1 = ' '.join([str(self.queue[i]) for i in range(self.front, self.limit)]) + q2 = ' '.join([str(self.queue[i]) for i in range(0, self.rear + 1)]) + return q1 + ' ' + q2 # for checking if queue is empty def isEmpty(self): - return self.queue == [] + return self.front == -1 # for checking if the queue is full def isFull(self): - return len(self.queue) == self.limit + return (self.rear + 1) % self.limit == self.front - # for adding an element at the rear end + # for adding an element to the queue def enqueue(self, data): if self.isFull(): print('Queue is Full!') elif self.isEmpty(): - self.front = self.rear = 0 - self.queue.append(data) + self.front = 0 + self.rear = 0 + self.queue[self.rear] = data else: - self.rear += 1 - self.queue.append(data) + self.rear = (self.rear + 1) % self.limit + self.queue[self.rear] = data - # for deleting the deleting an element from front end + # for removing an element from the queue def dequeue(self): if self.isEmpty(): print('Queue is Empty!') + elif (self.front == self.rear): + self.front = -1 + self.rear = -1 else: - self.front += 1 - return self.queue.pop(0) + self.front = (self.front + 1) % self.limit if __name__ == '__main__': myCQ = CircularQueue(5) From a1858784e3b2909d7a5539496e5c7f8c5d4649fe Mon Sep 17 00:00:00 2001 From: Sandro Mirianashvili Date: Fri, 2 Oct 2020 07:32:25 +0400 Subject: [PATCH 26/28] min coin (#40) --- Dynamic Programming/mincoin.py | 29 +++++++++++++++++++++++++++++ README.md | 1 + 2 files changed, 30 insertions(+) create mode 100644 Dynamic Programming/mincoin.py diff --git a/Dynamic Programming/mincoin.py b/Dynamic Programming/mincoin.py new file mode 100644 index 0000000..da90708 --- /dev/null +++ b/Dynamic Programming/mincoin.py @@ -0,0 +1,29 @@ +import sys + +def min_coins(coins,sum): + + # dp[i] will be storing the minimum + dp = [0 for i in range(sum + 1)] + + # Base case + dp[0] = 0 + + # Initialize values as Infinite + for i in range(1, sum + 1): + dp[i] = sys.maxsize + + # for all values from 1 to sum + for i in range(1, sum + 1): + for j in range(len(coins)): + if (coins[j] <= i): + res = dp[i - coins[j]] + if (res != sys.maxsize and res + 1 < dp[i]): + dp[i] = res + 1 + return dp[sum] + + +if __name__ == "__main__": + coins = [9, 6, 5, 1] + m = len(coins) + amount = 11 + print("Minimum coins:",min_coins(coins,amount)) \ No newline at end of file diff --git a/README.md b/README.md index def3d69..a19c7d8 100644 --- a/README.md +++ b/README.md @@ -74,6 +74,7 @@ Pune, Maharashtra, India.
* [Fibonacci Series](Dynamic%20Programming/P01_Fibonnaci.py) * [Longest Increasing Subsequence](Dynamic%20Programming/P02_LongestIncreasingSubsequence.py) * [Longest Continuous Odd Subsequence](Dynamic%20Programming/P03_LongestContinuousOddSubsequence.py) +* [Count Minimum Number of Coins](Dynamic%20Programming/mincoin.py) # Donation From 362fec607e57bba06b925aebd3c170bba21b8d66 Mon Sep 17 00:00:00 2001 From: Sakshi Agrawal <66746828+SakshiiAgrawal@users.noreply.github.com> Date: Tue, 20 Oct 2020 08:53:41 +0530 Subject: [PATCH 27/28] zigzag traversal of a binary tree (#48) The idea is to use two stacks. We can use one stack for printing from left to right and other stack for printing from right to left. In every iteration, we have nodes of one level in one of the stacks. We print the nodes, and push nodes of next level in other stack. --- Trees/zigzagtraversal_iterative.py | 75 ++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 Trees/zigzagtraversal_iterative.py diff --git a/Trees/zigzagtraversal_iterative.py b/Trees/zigzagtraversal_iterative.py new file mode 100644 index 0000000..fa485b3 --- /dev/null +++ b/Trees/zigzagtraversal_iterative.py @@ -0,0 +1,75 @@ +class Node: + """ + A Node has data variable and pointers to its left and right nodes. + """ + + def __init__(self, data): + self.left = None + self.right = None + self.data = data + +def make_tree() -> Node: + root = Node(1) + root.left = Node(2) + root.right = Node(3) + root.left.left = Node(4) + root.left.right = Node(5) + return root + +def zigzag_iterative(root: Node): + """ + ZigZag traverse by iterative method: Print node left to right and right to left, alternatively. + """ + if root == None: + return + + # two stacks to store alternate levels + s1 = [] # For levels to be printed from right to left + s2 = [] # For levels to be printed from left to right + + # append first level to first stack 's1' + s1.append(root) + + # Keep printing while any of the stacks has some nodes + while not len(s1) == 0 or not len(s2) == 0: + + # Print nodes of current level from s1 and append nodes of next level to s2 + while not len(s1) == 0: + temp = s1[-1] + s1.pop() + print(temp.data, end = " ") + + # Note that is left is appended before right + if temp.left: + s2.append(temp.left) + if temp.right: + s2.append(temp.right) + + # Print nodes of current level from s2 and append nodes of next level to s1 + while not len(s2) == 0: + temp = s2[-1] + s2.pop() + print(temp.data, end = " ") + + # Note that is rightt is appended before left + if temp.right: + s1.append(temp.right) + if temp.left: + s1.append(temp.left) + +def main(): # Main function for testing. + """ + Create binary tree. + """ + root = make_tree() + print("\nZigzag order traversal(iterative) is: ") + zigzag_iterative(root) + print() + + +if __name__ == "__main__": + import doctest + + doctest.testmod() + main() + From c95666d39c198e90800c0c3d943aeaf958c6a0a2 Mon Sep 17 00:00:00 2001 From: Juzar Bharmal <53657281+Juzar10@users.noreply.github.com> Date: Tue, 26 Jan 2021 21:08:54 +0530 Subject: [PATCH 28/28] fixed one sided binary tree issue (#51) --- Trees/BinarySearchTree.py | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/Trees/BinarySearchTree.py b/Trees/BinarySearchTree.py index 2b6333a..ea0e15a 100644 --- a/Trees/BinarySearchTree.py +++ b/Trees/BinarySearchTree.py @@ -44,23 +44,45 @@ def minValueNode(self, node): return current - def delete(self, data): + def maxValueNode(self, node): + current = node + + # loop down to find the leftmost leaf + while(current.rightChild is not None): + current = current.rightChild + + return current + + + def delete(self, data,root): ''' For deleting the node ''' if self is None: return None # if current node's data is less than that of root node, then only search in left subtree else right subtree if data < self.data: - self.leftChild = self.leftChild.delete(data) + self.leftChild = self.leftChild.delete(data,root) elif data > self.data: - self.rightChild = self.rightChild.delete(data) + self.rightChild = self.rightChild.delete(data,root) else: # deleting node with one child if self.leftChild is None: + + if self == root: + temp = self.minValueNode(self.rightChild) + self.data = temp.data + self.rightChild = self.rightChild.delete(temp.data,root) + temp = self.rightChild self = None return temp elif self.rightChild is None: + + if self == root: + temp = self.maxValueNode(self.leftChild) + self.data = temp.data + self.leftChild = self.leftChild.delete(temp.data,root) + temp = self.leftChild self = None return temp @@ -69,7 +91,7 @@ def delete(self, data): # first get the inorder successor temp = self.minValueNode(self.rightChild) self.data = temp.data - self.rightChild = self.rightChild.delete(temp.data) + self.rightChild = self.rightChild.delete(temp.data,root) return self @@ -128,7 +150,7 @@ def insert(self, data): def delete(self, data): if self.root is not None: - return self.root.delete(data) + return self.root.delete(data,self.root) def find(self, data): if self.root: @@ -189,4 +211,4 @@ def postorder(self): print('\n\nAfter deleting 10') tree.delete(10) tree.inorder() - tree.preorder() + tree.preorder() \ No newline at end of file