Skip to content

Commit ec0b015

Browse files
Implemented Introsort (#549)
Co-authored-by: ਗਗਨਦੀਪ ਸਿੰਘ (Gagandeep Singh) <gdp.1807@gmail.com>
1 parent 1942891 commit ec0b015

File tree

7 files changed

+127
-8
lines changed

7 files changed

+127
-8
lines changed

.github/workflows/ci.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ on:
99
jobs:
1010
test-ubuntu-py38:
1111
runs-on: ${{matrix.os}}
12-
timeout-minutes: 10
12+
timeout-minutes: 20
1313
strategy:
1414
fail-fast: false
1515
matrix:
@@ -61,7 +61,7 @@ jobs:
6161
6262
test-ubuntu-py39-py310:
6363
runs-on: ${{matrix.os}}
64-
timeout-minutes: 10
64+
timeout-minutes: 20
6565
strategy:
6666
fail-fast: false
6767
matrix:
@@ -101,7 +101,7 @@ jobs:
101101
102102
test-macos:
103103
runs-on: ${{matrix.os}}
104-
timeout-minutes: 10
104+
timeout-minutes: 20
105105
strategy:
106106
fail-fast: false
107107
matrix:
@@ -142,7 +142,7 @@ jobs:
142142
143143
test-windows:
144144
runs-on: ${{matrix.os}}
145-
timeout-minutes: 15
145+
timeout-minutes: 20
146146
strategy:
147147
fail-fast: false
148148
matrix:

docs/source/pydatastructs/linear_data_structures/algorithms.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,5 @@ Algorithms
4444
.. autofunction:: pydatastructs.binary_search
4545

4646
.. autofunction:: pydatastructs.jump_search
47+
48+
.. autofunction:: pydatastructs.intro_sort

pydatastructs/linear_data_structures/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
binary_search,
4646
jump_search,
4747
selection_sort,
48-
insertion_sort
48+
insertion_sort,
49+
intro_sort
4950
)
5051
__all__.extend(algorithms.__all__)

pydatastructs/linear_data_structures/algorithms.py

Lines changed: 111 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@
2929
'binary_search',
3030
'jump_search',
3131
'selection_sort',
32-
'insertion_sort'
32+
'insertion_sort',
33+
'intro_sort'
3334
]
3435

3536
def _merge(array, sl, el, sr, er, end, comp):
@@ -1740,3 +1741,112 @@ def jump_search(array, value, **kwargs):
17401741
prev += 1
17411742

17421743
return None
1744+
1745+
def intro_sort(array, **kwargs) -> Array:
1746+
"""
1747+
Performs intro sort on the given array.
1748+
1749+
Parameters
1750+
==========
1751+
1752+
array: Array
1753+
The array which is to be sorted.
1754+
start: int
1755+
The starting index of the portion
1756+
which is to be sorted.
1757+
Optional, by default 0
1758+
end: int
1759+
The ending index of the portion which
1760+
is to be sorted.
1761+
Optional, by default the index
1762+
of the last position filled.
1763+
maxdepth: Enables the user to define the maximum
1764+
recursion depth, takes value 2*log(length(A))
1765+
by default (ref: Wikipedia[1]).
1766+
ins_threshold: Threshold under which insertion
1767+
sort has to be performed, default value is
1768+
16 (ref: Wikipedia[1]).
1769+
backend: pydatastructs.Backend
1770+
The backend to be used.
1771+
Optional, by default, the best available
1772+
backend is used.
1773+
1774+
Returns
1775+
=======
1776+
1777+
output: Array
1778+
The sorted array.
1779+
1780+
Examples
1781+
========
1782+
1783+
>>> from pydatastructs import OneDimensionalArray as ODA, intro_sort
1784+
>>> arr = ODA(int, [5, 78, 1, 0])
1785+
>>> out = intro_sort(arr)
1786+
>>> str(out)
1787+
'[0, 1, 5, 78]'
1788+
>>> arr = ODA(int, [21, 37, 5])
1789+
>>> out = intro_sort(arr)
1790+
>>> str(out)
1791+
'[5, 21, 37]'
1792+
1793+
Note
1794+
====
1795+
1796+
This function does not support custom comparators as
1797+
is the case with other sorting functions in this file.
1798+
This is because of heapsort's limitation.
1799+
1800+
References
1801+
==========
1802+
1803+
.. [1] https://en.wikipedia.org/wiki/Introsort
1804+
"""
1805+
raise_if_backend_is_not_python(
1806+
intro_sort, kwargs.get('backend', Backend.PYTHON))
1807+
1808+
# Always sorts in increasing order, this is because of
1809+
# heapsort's limitation
1810+
comp = lambda u, v: u <= v
1811+
lower = kwargs.get('start', 0)
1812+
upper = kwargs.get('end', len(array) - 1)
1813+
n = upper - lower + 1
1814+
if n <= 0:
1815+
maxdepth = 0
1816+
else:
1817+
maxdepth = kwargs.get("maxdepth", int(2 * (log(n)/log(2))))
1818+
1819+
ins_threshold = kwargs.get("ins_threshold", 16)
1820+
1821+
def partition(array, lower, upper):
1822+
pivot = array[lower]
1823+
left = lower + 1
1824+
right = upper
1825+
done = False
1826+
while not done:
1827+
while left <= right and _comp(array[left], pivot, comp):
1828+
left += 1
1829+
while _comp(pivot, array[right], comp) and right >= left:
1830+
right -= 1
1831+
if right < left:
1832+
done = True
1833+
else:
1834+
array[left], array[right] = array[right], array[left]
1835+
left+=1
1836+
right-=1
1837+
1838+
array[lower], array[right] = array[right], array[lower]
1839+
return right
1840+
1841+
if n < ins_threshold:
1842+
return insertion_sort(array, start=lower, end=upper)
1843+
elif maxdepth == 0:
1844+
heapsort(array, start=lower, end=upper)
1845+
return array
1846+
else:
1847+
p = partition(array, lower, upper)
1848+
1849+
intro_sort(array, start=lower, end=p-1, maxdepth=maxdepth-1, ins_threshold=ins_threshold)
1850+
intro_sort(array, start=p+1, end=upper, maxdepth=maxdepth-1, ins_threshold=ins_threshold)
1851+
1852+
return array

pydatastructs/linear_data_structures/tests/benchmarks/test_algorithms.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@ def test_quick_sort():
4141
def test_bubble_sort():
4242
_test_common_sort(bubble_sort, size=2000)
4343

44+
@pytest.mark.xfail
45+
def test_intro_sort():
46+
_test_common_sort(intro_sort, size=2000)
4447

4548
@pytest.mark.xfail
4649
def test_selection_sort():

pydatastructs/linear_data_structures/tests/test_algorithms.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
cocktail_shaker_sort, quick_sort, longest_common_subsequence, is_ordered,
66
upper_bound, lower_bound, longest_increasing_subsequence, next_permutation,
77
prev_permutation, bubble_sort, linear_search, binary_search, jump_search,
8-
selection_sort, insertion_sort, Backend)
8+
selection_sort, insertion_sort, intro_sort, Backend)
99

1010
from pydatastructs.utils.raises_util import raises
1111
import random
@@ -115,6 +115,9 @@ def test_quick_sort():
115115
_test_common_sort(quick_sort)
116116
_test_common_sort(quick_sort, backend=Backend.CPP)
117117

118+
def test_intro_sort():
119+
_test_common_sort(intro_sort)
120+
118121
def test_bubble_sort():
119122
_test_common_sort(bubble_sort)
120123
_test_common_sort(bubble_sort, backend=Backend.CPP)

pydatastructs/utils/tests/test_code_quality.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ def _apis():
174174
pyds.Trie, pyds.TrieNode, pyds.SkipList, pyds.RangeQueryStatic, pyds.RangeQueryDynamic, pyds.SparseTable,
175175
pyds.miscellaneous_data_structures.segment_tree.OneDimensionalArraySegmentTree,
176176
pyds.bubble_sort, pyds.linear_search, pyds.binary_search, pyds.jump_search,
177-
pyds.selection_sort, pyds.insertion_sort, pyds.quick_sort]
177+
pyds.selection_sort, pyds.insertion_sort, pyds.quick_sort, pyds.intro_sort]
178178

179179
def test_public_api():
180180
pyds = pydatastructs

0 commit comments

Comments
 (0)