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

upper_bound and lower_bound functions added #351

Merged
merged 14 commits into from
Mar 27, 2021
4 changes: 3 additions & 1 deletion pydatastructs/linear_data_structures/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
cocktail_shaker_sort,
quick_sort,
longest_common_subsequence,
is_ordered
is_ordered,
upper_bound,
lower_bound
)
__all__.extend(algorithms.__all__)
122 changes: 122 additions & 0 deletions pydatastructs/linear_data_structures/algorithms.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
'cocktail_shaker_sort',
'quick_sort',
'longest_common_subsequence',
'upper_bound',
'lower_bound',
'is_ordered'
]

Expand Down Expand Up @@ -843,3 +845,123 @@ def is_ordered(array, **kwargs):
if comp(array[i], array[i - 1]):
return False
return True

def upper_bound(array, value, **kwargs):
"""
Finds the index of the first occurence of an element greater than value according
to an order defined,in the given sorted OneDimensionalArray

Parameters
========
array: OneDimensionalArray
The sorted array (sorted according to a custom comparator function) in which the
upper bound has to be found

start: int
The staring index of the portion of the array in which the upper bound
of a given value has to be looked for

end: int
The ending index of the portion of the array in which the upper bound
of a given value has to be looked for
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
start: int
The staring index of the portion of the array in which the upper bound
of a given value has to be looked for
end: int
The ending index of the portion of the array in which the upper bound
of a given value has to be looked for
start: int, optional.
The staring index of the portion of the array in which the upper bound
of a given value has to be looked for. By default is 0.
end: int, optional
The ending index of the portion of the array in which the upper bound
of a given value has to be looked for. By default is len(array)
comp: boolean funtion, optional
A function that takes two paramters and returns True if 1st parameter is strictly
smaller than 2nd parameter


Returns
=======

output: int
czgdp1807 marked this conversation as resolved.
Show resolved Hide resolved
Index of the upper bound of the given value in the given sorted OneDimensionalArray
czgdp1807 marked this conversation as resolved.
Show resolved Hide resolved

Examples
========
>>> from pydatastructs import upper_bound, OneDimensionalArray as ODA
>>> arr = ODA(int, [4, 5, 5, 6, 7])
>>> upperBound = upper_bound(arr, 5, start = 0, end = 4)
>>> upperBound
3
>>> arr = ODA(int, [7, 6, 5, 5, 4])
>>> upperBound = upper_bound(arr, 5, comp = lambda x, y: x > y)
>>> upperBound
4

Note
====

The OneDimensionalArray must be sorted beforehand
"""
start = kwargs.get('start', 0)
end = kwargs.get('end', len(array))
comp = kwargs.get('comp', lambda x,y: x < y)
# if comp is None:
# comp = lambda a, b: (a < b)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this comment

index = end
inclusive_end = end - 1
if comp(value, array[start]):
index = start
while start <= inclusive_end:
mid = (start + inclusive_end)//2
if not comp(value, array[mid]):
start = mid + 1
else:
index = mid
inclusive_end = mid - 1
return index

def lower_bound(array, value, **kwargs):
"""
Finds the the index of the first occurence of an element which is not
less than value according to an order defined, in the given OneDimensionalArray

Parameters
========
array: OneDimensionalArray
The sorted array (sorted according to a custom comparator function)
in which the lower bound has to be found

start: int
The staring index of the portion of the array in which the lower
bound of a given value has to be looked for

end: int
The ending index of the portion of the array in which the lower
bound of a given value has to be looked for

Returns
=======
output: int
czgdp1807 marked this conversation as resolved.
Show resolved Hide resolved
Index of the lower bound of the given value in the given sorted OneDimensionalArray

Examples
========

>>> from pydatastructs import lower_bound, OneDimensionalArray as ODA
>>> arr = ODA(int, [4, 5, 5, 6, 7])
>>> lowerBound = lower_bound(arr, 5, end = 4, comp = lambda x, y : x < y)
>>> lowerBound
1
>>> arr = ODA(int, [7, 6, 5, 5, 4])
>>> lowerBound = lower_bound(arr, 5, start = 0, comp = lambda x, y : x > y)
>>> lowerBound
2

Note
====

The OneDimensionalArray must be sorted beforehand
"""
start = kwargs.get('start', 0)
end = kwargs.get('end', len(array))
comp = kwargs.get('comp', lambda x, y: x < y)
# if comp is None:
# comp = lambda a, b: (a < b)
index = end
inclusive_end = end - 1
if not comp(array[start], value):
index = start
while start <= inclusive_end:
mid = (start + inclusive_end)//2
if comp(array[mid], value):
start = mid + 1
else:
index = mid
inclusive_end = mid - 1
return index
92 changes: 88 additions & 4 deletions pydatastructs/linear_data_structures/tests/test_algorithms.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
from pydatastructs import (
merge_sort_parallel, DynamicOneDimensionalArray,
OneDimensionalArray, brick_sort, brick_sort_parallel,
heapsort, matrix_multiply_parallel, counting_sort, bucket_sort,
cocktail_shaker_sort, quick_sort, longest_common_subsequence, is_ordered)

heapsort, matrix_multiply_parallel, counting_sort, bucket_sort, cocktail_shaker_sort, quick_sort, longest_common_subsequence,
is_ordered, upper_bound, lower_bound)

from pydatastructs.utils.raises_util import raises
import random
Expand Down Expand Up @@ -149,11 +148,96 @@ def test_is_ordered():

expected_result = True
arr3 = ODA(int, [0, -1, -2, -3, -4, 4])
output = is_ordered(arr3, start=1, end=4, comp=lambda u, v: u > v)
output = is_ordered(arr3, start = 1, end = 4, comp = lambda u, v: u > v)
assert output == expected_result

expected_result = True
arr4 = DODA(int, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
arr4.delete(0)
output = is_ordered(arr4)
assert output == expected_result

def test_upper_bound():
ODA = OneDimensionalArray
arr1 = ODA(int, [3, 3, 3])
output = upper_bound(arr1, 3)
expected_result = 3
assert expected_result == output

arr2 = ODA(int, [4, 4, 5, 6])
output = upper_bound(arr2, 4, end = 3)
expected_result = 2
assert expected_result == output

arr3 = ODA(int, [6, 6, 7, 8, 9])
output = upper_bound(arr3, 5, start = 2, end = 4)
expected_result = 2
assert expected_result == output

arr4 = ODA(int, [3, 4, 4, 6])
output = upper_bound(arr4, 5, start = 1, end = 3)
expected_result = 3
assert expected_result == output

arr5 = ODA(int, [7, 6, 6, 6, 6, 5, 4, 3])
output = upper_bound(arr5, 6, comp = lambda x, y: x > y)
expected_result = 5
assert expected_result == output

arr6 = ODA(int, [7, 6, 6, 6, 6, 5, 4, 3])
output = upper_bound(arr6, 2, start = 2, comp = lambda x, y: x > y)
expected_result = 8
assert expected_result == output

arr7 = ODA(int, [7, 6, 6, 6, 6, 5, 4, 3])
output = upper_bound(arr7, 9, start = 3, end = 7, comp = lambda x, y: x > y)
expected_result = 3
assert expected_result == output

arr8 = ODA(int, [7, 6, 6, 6, 6, 5, 4, 3])
output = upper_bound(arr8, 6, end = 3, comp = lambda x, y: x > y)
expected_result = 3
assert expected_result == output


def test_lower_bound():
ODA = OneDimensionalArray
arr1 = ODA(int, [3, 3, 3])
output = lower_bound(arr1, 3, start = 1)
expected_result = 1
assert expected_result == output

arr2 = ODA(int, [4, 4, 4, 4, 5, 6])
output = lower_bound(arr2, 5, end = 3)
expected_result = 3
assert expected_result == output

arr3 = ODA(int, [6, 6, 7, 8, 9])
output = lower_bound(arr3, 5, end = 3)
expected_result = 0
assert expected_result == output

arr4 = ODA(int, [3, 4, 4, 4])
output = lower_bound(arr4, 5)
expected_result = 4
assert expected_result == output

arr5 = ODA(int, [7, 6, 6, 6, 6, 5, 4, 3])
output = lower_bound(arr5, 5, comp = lambda x, y: x > y)
expected_result = 5
assert expected_result == output

arr6 = ODA(int, [7, 6, 6, 6, 6, 5, 4, 3])
output = lower_bound(arr6, 2, start = 4, comp = lambda x, y: x > y)
expected_result = 8
assert expected_result == output

arr7 = ODA(int, [7, 6, 6, 6, 6, 5, 4, 3])
output = lower_bound(arr7, 9, end = 5, comp = lambda x, y: x > y)
expected_result = 0
assert expected_result == output

arr8 = ODA(int, [7, 6, 6, 6, 6, 5, 4, 3])
output = lower_bound(arr8, 6, end = 3, comp = lambda x, y: x > y)
expected_result = 1
assert expected_result == output