Adding improvements to bisect.py

This commit is contained in:
Anindhiths 2025-03-17 18:36:50 +05:30 committed by GitHub
parent 38d9a77c9a
commit 11b8b923fc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -1,72 +1,123 @@
"""Bisection algorithms."""
def insort_right(a, x, lo=0, hi=None):
"""Insert item x in list a, and keep it sorted assuming a is sorted.
If x is already in a, insert it to the right of the rightmost x.
Optional args lo (default 0) and hi (default len(a)) bound the
slice of a to be searched.
"""
lo = bisect_right(a, x, lo, hi)
a.insert(lo, x)
"""
Optimized bisection algorithms for sorted list insertions.
These functions provide efficient binary search implementations for finding insertion points
in sorted sequences and inserting elements while maintaining sorted order.
"""
def bisect_right(a, x, lo=0, hi=None):
"""Return the index where to insert item x in list a, assuming a is sorted.
The return value i is such that all e in a[:i] have e <= x, and all e in
a[i:] have e > x. So if x already appears in the list, a.insert(x) will
insert just after the rightmost x already there.
Optional args lo (default 0) and hi (default len(a)) bound the
slice of a to be searched.
a[i:] have e > x. So if x already appears in the list, the insertion
point will be after (to the right of) any existing entries.
Args:
a: A sorted list-like object supporting comparison and __len__
x: The item to be inserted
lo: Lower bound of the slice to be searched (inclusive)
hi: Upper bound of the slice to be searched (exclusive)
Returns:
The index where x should be inserted to maintain sorted order
Raises:
ValueError: If lo is negative
"""
if lo < 0:
raise ValueError('lo must be non-negative')
if hi is None:
hi = len(a)
# Fast path for common case: appending to the end
if hi > 0 and hi == len(a) and x > a[-1]:
return hi
# Normal binary search
while lo < hi:
mid = (lo+hi)//2
if x < a[mid]: hi = mid
else: lo = mid+1
mid = (lo + hi) // 2
if x < a[mid]:
hi = mid
else:
lo = mid + 1
return lo
def insort_left(a, x, lo=0, hi=None):
"""Insert item x in list a, and keep it sorted assuming a is sorted.
If x is already in a, insert it to the left of the leftmost x.
Optional args lo (default 0) and hi (default len(a)) bound the
slice of a to be searched.
"""
lo = bisect_left(a, x, lo, hi)
a.insert(lo, x)
def bisect_left(a, x, lo=0, hi=None):
"""Return the index where to insert item x in list a, assuming a is sorted.
The return value i is such that all e in a[:i] have e < x, and all e in
a[i:] have e >= x. So if x already appears in the list, a.insert(x) will
insert just before the leftmost x already there.
Optional args lo (default 0) and hi (default len(a)) bound the
slice of a to be searched.
a[i:] have e >= x. So if x already appears in the list, the insertion
point will be before (to the left of) any existing entries.
Args:
a: A sorted list-like object supporting comparison and __len__
x: The item to be inserted
lo: Lower bound of the slice to be searched (inclusive)
hi: Upper bound of the slice to be searched (exclusive)
Returns:
The index where x should be inserted to maintain sorted order
Raises:
ValueError: If lo is negative
"""
if lo < 0:
raise ValueError('lo must be non-negative')
if hi is None:
hi = len(a)
# Fast path for common case: appending to the end
if hi > 0 and hi == len(a) and x > a[-1]:
return hi
# Fast path for common case: inserting at the beginning
if lo == 0 and hi > 0 and x < a[0]:
return 0
# Normal binary search
while lo < hi:
mid = (lo+hi)//2
if a[mid] < x: lo = mid+1
else: hi = mid
mid = (lo + hi) // 2
if a[mid] < x:
lo = mid + 1
else:
hi = mid
return lo
# Create aliases
def insort_right(a, x, lo=0, hi=None):
"""Insert item x in list a, and keep it sorted assuming a is sorted.
If x is already in a, insert it to the right of the rightmost x.
Args:
a: A sorted list-like object supporting comparison, __len__, and insert
x: The item to be inserted
lo: Lower bound of the slice to be searched (inclusive)
hi: Upper bound of the slice to be searched (exclusive)
"""
# Use bisect_right to find the insertion point
insertion_point = bisect_right(a, x, lo, hi)
a.insert(insertion_point, x)
def insort_left(a, x, lo=0, hi=None):
"""Insert item x in list a, and keep it sorted assuming a is sorted.
If x is already in a, insert it to the left of the leftmost x.
Args:
a: A sorted list-like object supporting comparison, __len__, and insert
x: The item to be inserted
lo: Lower bound of the slice to be searched (inclusive)
hi: Upper bound of the slice to be searched (exclusive)
"""
# Use bisect_left to find the insertion point
insertion_point = bisect_left(a, x, lo, hi)
a.insert(insertion_point, x)
# Create aliases for backward compatibility
bisect = bisect_right
insort = insort_right