Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Heap sort #251

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file.
240 changes: 240 additions & 0 deletions sorting_searching/heap_sort/heap_sort_solution.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,240 @@
{
"cells": [
{
"cell_type": "raw",
"metadata": {},
"source": [
"This notebook was prepared by [Donne Martin](http://donnemartin.com). Source and license info is on [GitHub](https://github.com/donnemartin/interactive-coding-challenges)."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Solution Notebook"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Problem: Implement heap sort.\n",
"\n",
"* [Constraints](#Constraints)\n",
"* [Test Cases](#Test-Cases)\n",
"* [Algorithm](#Algorithm)\n",
"* [Code](#Code)\n",
"* [Pythonic-Code](#Pythonic-Code)\n",
"* [Unit Test](#Unit-Test)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Constraints\n",
"\n",
"* Is a naive solution sufficient?\n",
" * Yes\n",
"* Are duplicates allowed?\n",
" * Yes\n",
"* Can we assume the input is valid?\n",
" * No\n",
"* Can we assume this fits memory?\n",
" * Yes"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Test Cases\n",
"\n",
"* None -> Exception\n",
"* Empty input -> []\n",
"* One element -> [element]\n",
"* Two or more elements"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Algorithm\n",
"\n",
"Wikipedia's animation:\n",
"![alt text](https://upload.wikimedia.org/wikipedia/commons/1/1b/Sorting_heapsort_anim.gif)\n",
"\n",
"* Convert a given list to a max-heap\n",
"* For i from n-1 to 0 (n is size of a given list) :\n",
" * Swap 0-th element with i-th element\n",
" * Heapfiy a sub-list(0 ~ i-1)\n",
"\n",
"Complexity:\n",
"* Time: O(n log(n)) average, best, worst\n",
"* Space: O(n)\n",
" * This implementation is in-place sort, so it needs no additional space.\n",
"\n",
"Misc:\n",
"\n",
"* Most implementations are not stable\n",
"\n",
"See [Heapsort on wikipedia](https://en.wikipedia.org/wiki/Heapsort):\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Code"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [],
"source": [
"from __future__ import division\n",
"\n",
"\n",
"class HeapSort(object):\n",
" \n",
" def heapify(self, data, n, root):\n",
" while (2*root + 1 < n):\n",
" ch = 2 * root + 1\n",
" if ch+1 < n and data[ch] < data[ch+1]:\n",
" ch += 1\n",
" if data[ch] < data[root]:\n",
" break\n",
" data[ch], data[root] = data[root], data[ch]\n",
" root = ch\n",
"\n",
" def sort(self, data):\n",
" if data is None:\n",
" raise TypeError('data cannot be None')\n",
" return self._sort(data)\n",
"\n",
" def _sort(self, data):\n",
" n = len(data)\n",
" if n < 2:\n",
" return data\n",
" for i in range(n//2 - 1, -1, -1):\n",
" self.heapify(data, n, i)\n",
" \n",
" # extract elements\n",
" for i in range(n-1, 0, -1):\n",
" data[i], data[0] = data[0], data[1]\n",
" self.heapify(data, i, 0)\n",
" return data # return sorted array in ascending order\n",
" "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Unit Test\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Overwriting test_heap_sort.py\n"
]
}
],
"source": [
"%%writefile test_heap_sort.py\n",
"from nose.tools import assert_equal, assert_raises\n",
"\n",
"\n",
"class TestHeapSort(object):\n",
"\n",
" def test_heap_sort(self):\n",
" sort = HeapSort()\n",
"\n",
" print('None input')\n",
" assert_raises(TypeError, sort.sort, None)\n",
"\n",
" print('Empty input')\n",
" assert_equal(sort.sort([]), [])\n",
"\n",
" print('One element')\n",
" assert_equal(sort.sort([5]), [5])\n",
"\n",
" print('Two or more elements')\n",
" data = [5, 1, 7, 2, 6, -3, 5, 7, -1]\n",
" assert_equal(sort.sort(data), sorted(data))\n",
"\n",
" print('Success: test_heap_sort\\n')\n",
"\n",
"\n",
"def main():\n",
" test = TestHeapSort()\n",
" test.test_heap_sort()\n",
"\n",
"\n",
"if __name__ == '__main__':\n",
" main()"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"None input\n",
"Empty input\n",
"One element\n",
"Two or more elements\n",
"Success: test_heap_sort\n",
"\n"
]
}
],
"source": [
"%run -i test_heap_sort.py"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"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.7.0"
}
},
"nbformat": 4,
"nbformat_minor": 1
}
31 changes: 31 additions & 0 deletions sorting_searching/heap_sort/test_heap_sort.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
from nose.tools import assert_equal, assert_raises


class TestHeapSort(object):

def test_heap_sort(self):
sort = HeapSort()

print('None input')
assert_raises(TypeError, sort.sort, None)

print('Empty input')
assert_equal(sort.sort([]), [])

print('One element')
assert_equal(sort.sort([5]), [5])

print('Two or more elements')
data = [5, 1, 7, 2, 6, -3, 5, 7, -1]
assert_equal(sort.sort(data), sorted(data))

print('Success: test_heap_sort\n')


def main():
test = TestHeapSort()
test.test_heap_sort()


if __name__ == '__main__':
main()