Skip to content

Added Median of Medians Algorithm #9864

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

Merged
merged 5 commits into from
Oct 8, 2023
Merged
Changes from 2 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
118 changes: 118 additions & 0 deletions searches/median_of_medians.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
"""
A Python implementation of the Median of Medians algorithm
to select pivots for quick_select, which is efficient for
calculating the value that would appear in the index of a
list if it would be sorted, even if it is not already
sorted. Search in time complexity O(n) at any rank
deterministically
https://en.wikipedia.org/wiki/Median_of_medians
"""

"""
>>> quick_select([2, 4, 5, 7, 899, 54, 32], 5)
32
>>> quick_select([2, 4, 5, 7, 899, 54, 32], 1)
2
>>> quick_select([5, 4, 3, 2], 2)
3
>>> quick_select([3, 5, 7, 10, 2, 12], 3)
5
"""
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
"""
>>> quick_select([2, 4, 5, 7, 899, 54, 32], 5)
32
>>> quick_select([2, 4, 5, 7, 899, 54, 32], 1)
2
>>> quick_select([5, 4, 3, 2], 2)
3
>>> quick_select([3, 5, 7, 10, 2, 12], 3)
5
"""

There is no point in repeating the same tests here.



def median_of_five(arr: list) -> int:
"""
>>> median_of_five([2, 4, 5, 7, 899])
5
>>> median_of_five([5, 7, 899, 54, 32])
32
>>> median_of_five([5, 4, 3, 2])
3
Copy link
Collaborator

Choose a reason for hiding this comment

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

This test is failing:

>>> median_of_five([5, 4, 3, 2])
Expected:
    3
Got:
    4

>>> median_of_five([3, 5, 7, 10, 2])
5
"""
"""
Return the median of the input list
:param arr: Array to find median of
:return: median of arr
"""
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can you swap the order of the tests and explanation, and condense into a single docstring

arr = sorted(arr)
return arr[len(arr) // 2]


def median_of_medians(arr: list) -> int:
"""
>>> median_of_medians([2, 4, 5, 7, 899, 54, 32])
54
>>> median_of_medians([5, 7, 899, 54, 32])
32
>>> median_of_medians([5, 4, 3, 2])
4
>>> median_of_medians([3, 5, 7, 10, 2, 12])
12
"""
"""
Return a pivot to partition data on by calculating
Median of medians of input data
:param arr: The data to be checked (a list)
:return: median of medians of input array
"""
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can you swap the order of the tests and explanation, and condense into a single docstring

if len(arr) <= 5:
return median_of_five(arr)
medians = []
i = 0
while i < len(arr):
if (i + 4) <= len(arr):
medians.append(median_of_five(arr[i:].copy()))
else:
medians.append(median_of_five(arr[i : i + 5].copy()))
i += 5
return median_of_medians(medians)


def quick_select(arr: list, target: int) -> int:
"""
>>> quick_select([2, 4, 5, 7, 899, 54, 32], 5)
32
>>> quick_select([2, 4, 5, 7, 899, 54, 32], 1)
2
>>> quick_select([5, 4, 3, 2], 2)
3
>>> quick_select([3, 5, 7, 10, 2, 12], 3)
5
"""

"""
Two way partition the data into smaller and greater lists,
in relationship to the pivot
:param arr: The data to be searched (a list)
:param target: The rank to be searched
:return: element at rank target
"""
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can you swap the order of the tests and explanation, and condense into a single docstring


# Invalid Input
if target > len(arr):
return -1

# x is the estimated pivot by median of medians algorithm
x = median_of_medians(arr)
left = []
right = []
check = False
for i in range(len(arr)):
if arr[i] < x:
left.append(arr[i])
elif arr[i] > x:
right.append(arr[i])
elif arr[i] == x and not check:
check = True
else:
right.append(arr[i])
rank_x = len(left) + 1
if rank_x == target:
answer = x
elif rank_x > target:
answer = quick_select(left, target)
elif rank_x < target:
answer = quick_select(right, target - rank_x)
return answer