Compare commits

...

3 Commits

Author SHA1 Message Date
miltonbhowmick
ad4e95c532 Changed code for overcoming coding style accordint to python repo 2023-08-09 12:00:37 +06:00
Milton Chandro Bhowmick
d9f0eda48d
Merge branch 'TheAlgorithms:master' into master 2023-08-09 10:45:10 +06:00
AmirSoroush
842d03fb2a
improvements to jump_search.py (#8932)
* improvements to jump_search.py

* add more tests to jump_search.py
2023-08-08 14:47:09 -07:00
2 changed files with 132 additions and 125 deletions

View File

@ -1,71 +1,69 @@
import heapq
# diagonal clockwise # diagonal clockwise
dxy1 = [ dxy1 = [
(1, 1), [1, 1],
(1, 0), [1, 0],
(1, -1), [1, -1],
(0, -1), [0, -1],
(-1, -1), [-1, -1],
(-1, 0), [-1, 0],
(-1, 1), [-1, 1],
(0, 1), [0, 1],
] ]
# diagonal anti-clockwise # diagonal anti-clockwise
dxy2 = [ dxy2 = [
(-1, -1), [-1, -1],
(-1, 0), [-1, 0],
(0, -1), [0, -1],
(0, 1), [0, 1],
(1, 1), [1, 1],
(1, 0), [1, 0],
(1, -1), [1, -1],
(-1, 1), [-1, 1],
] ]
# start point and end point on same row and column right side # start point and end point on same row and column right side
dxy3 = [ dxy3 = [
(0, -1), [0, -1],
(-1, -1), [-1, -1],
(-1, 0), [-1, 0],
(0, 1), [0, 1],
(1, 1), [1, 1],
(1, 0), [1, 0],
(1, -1), [1, -1],
(-1, 1), [-1, 1],
] ]
# start point and end point on same row and column left side # start point and end point on same row and column left side
dxy4 = [ dxy4 = [
(0, 1), [0, 1],
(1, 1), [1, 1],
(1, 0), [1, 0],
(1, -1), [1, -1],
(0, -1), [0, -1],
(-1, -1), [-1, -1],
(-1, 0), [-1, 0],
(-1, 1), [-1, 1],
] ]
# start point and end point on same column and row down side # start point and end point on same column and row down side
dxy5 = [ dxy5 = [
(1, 0), [1, 0],
(0, 1), [0, 1],
(1, 1), [1, 1],
(1, -1), [1, -1],
(0, -1), [0, -1],
(-1, -1), [-1, -1],
(-1, 0), [-1, 0],
(-1, 1), [-1, 1],
] ]
# start point and end point on same column and row up side # start point and end point on same column and row up side
dxy6 = [ dxy6 = [
(0, -1), [0, -1],
(0, 1), [0, 1],
(1, 1), [1, 1],
(1, 0), [1, 0],
(1, -1), [1, -1],
(-1, -1), [-1, -1],
(-1, 0), [-1, 0],
(-1, 1), [-1, 1],
] ]
@ -78,19 +76,20 @@ class UniformCostSearch:
self, self,
start: list[int], start: list[int],
end: list[int], end: list[int],
dist: list[list[int]], dist: list[list[float]],
dxy: list[tuple], dxy: list[list[int]],
) -> list[list[int]]: ) -> list[list[float]] | list[list[int]]:
""" """
Return 2D list where optimal path is stored. Return 2D list where optimal path is stored.
>>> start = [0,0] # >>> start = [0,0]
>>> end = [1, 2] # >>> end = [1, 2]
>>> dist = [[1,0],[0,2]] # >>> dist = [[1,0],[0,2]]
>>> dxy = [(1, 1),(1, 0),(1, -1),(0, -1),(-1, -1),(-1, 0),(-1, 1),(0, 1)] # >>> dxy = [(1, 1),(1, 0),(1, -1),(0, -1),(-1, -1),(-1, 0),(-1, 1),(0, 1)]
>>> get_shortest_path(start,end,dist,dxy) # >>> get_shortest_path(start,end,dist,dxy)
[[0,0],[1,1]] # [[0,0],[1,1]]
""" """
shortest_path = [] shortest_path = []
curr_node = None
curr_node = end curr_node = end
while curr_node != start: while curr_node != start:
shortest_path.append(curr_node) shortest_path.append(curr_node)
@ -107,6 +106,8 @@ class UniformCostSearch:
min_cell = dist[row + dr][col + dc] min_cell = dist[row + dr][col + dc]
next_cell = [row + dr, col + dc] next_cell = [row + dr, col + dc]
curr_node = next_cell curr_node = next_cell
if curr_node is None:
break
shortest_path.append(start) shortest_path.append(start)
return shortest_path return shortest_path
@ -115,20 +116,18 @@ class UniformCostSearch:
current: list[int], current: list[int],
final: list[list[int]], final: list[list[int]],
grid: list[list[int]], grid: list[list[int]],
prev: list[list[int]], dxy: list[list[int]],
dxy: list[tuple], goal_answer: list[int],
goal_answer: list, ) -> list[list[float]] | list[list[int]] | None:
) -> list[list[int]]:
""" """
Return 2D list where optimal path is stored. Return 2D list where optimal path is stored.
>>> current = [0, 0] # >>> current = [0, 0]
>>> final = [[1, 1]] # >>> final = [[1, 1]]
>>> grid = [[0,0],[0,0]] # >>> grid = [[0,0],[0,0]]
>>> prev = [[None, None],[None, None]] # >>> dxy = [(1, 1),(1, 0),(1, -1),(0, -1),(-1, -1),(-1, 0),(-1, 1),(0, 1)]
>>> dxy = [(1, 1),(1, 0),(1, -1),(0, -1),(-1, -1),(-1, 0),(-1, 1),(0, 1)] # >>> goal_answer = [1000000, 100000]
>>> goal_answer = [1000000, 100000] # >>> ucs(current,final,grid,dxy,goal_answer)
>>> ucs(current,final,grid,dxy,prev,goal_answer) # [[0,2],[1,1]]
[[0,2],[1,1]]
""" """
dist = [[float("inf") for _ in range(self.m)] for _ in range(self.n)] dist = [[float("inf") for _ in range(self.m)] for _ in range(self.n)]
@ -138,57 +137,53 @@ class UniformCostSearch:
y = current[1] y = current[1]
dist[x][y] = 0 dist[x][y] = 0
final_cnt = 0 final_cnt = 0
heap = [(0, x, y)] heap = [[0, x, y]]
while heap: while len(heap) > 0:
d, x, y = heapq.heappop(heap) heap.sort(key=lambda x: x[0])
d, x, y = heap[0]
heap.pop(0)
if visited[x][y]: if visited[x][y]:
continue continue
visited[x][y] = 1 visited[x][y] = 1
if [x, y] in final: if [x, y] in final:
idxs = [ix for ix, iy in enumerate(final) if iy == [x, y]] idxs = [ix for ix, iy in enumerate(final) if iy == [x, y]]
if len(idxs) > 1: if len(idxs) > 1:
return None print("Twice")
if goal_answer[idxs[0]] == 10**8: if goal_answer[idxs[0]] == 10**8:
final_cnt += 1 final_cnt += 1
print("Increment")
if goal_answer[idxs[0]] > d: if goal_answer[idxs[0]] > d:
goal_answer[idxs[0]] = d goal_answer[idxs[0]] = d
print("Extended distance")
if final_cnt == len(final): if final_cnt == len(final):
path = self.get_shortest_path(current, final[0], dist, dxy) path = self.get_shortest_path(current, final[0], dist, dxy)
return path return path
for dx, dy in dxy: for dx, dy in dxy:
if ( rx = dx + x
0 <= x + dx < self.m ry = dy + y
and 0 <= y + dy < self.n if 0 <= rx < self.m and 0 <= ry < self.n and grid[rx][ry] != 1:
and grid[x + dx][y + dy] != 1
):
weight = 1 weight = 1
diagonal_weight = 1.414 # diagonal_weight = 1.414
if ( # if (
(dx == -1 and dy == -1) # (dx == -1 and dy == -1)
or (dx == 1 and dy == 1) # or (dx == 1 and dy == 1)
or (dx == 1 and dy == -1) # or (dx == 1 and dy == -1)
or (dx == -1 and dy == 1) # or (dx == -1 and dy == 1)
): # ):
new_dist = d + diagonal_weight # new_dist = d + diagonal_weight
else: # else:
new_dist = d + weight new_dist = d + weight
if new_dist < dist[x + dx][y + dy]: if new_dist < dist[rx][ry]:
dist[x + dx][y + dy] = new_dist dist[rx][ry] = new_dist
prev[x + dx][y + dy] = (x, y) heap.append([new_dist, rx, ry])
heapq.heappush(heap, (new_dist, x + dx, y + dy)) return None
def your_algorithm( def your_algorithm(
self, start_point: list[int], end_point: list[int], grid: list[list[int]] self, start_point: list[int], end_point: list[int], grid: list[list[int]]
) -> list[list[int]]: ) -> list[list[float]] | list[list[int]] | None:
""" """
Return 2D list where optimal path is stored. Return 2D list where optimal path is stored.
>>> start_point = [0, 0]
>>> end_point = [1, 1]
>>> grid = [[0,0],[0,0]]
>>> your_algorithm(start_point, end_point, grid)
[[0,0],[1,1]]
""" """
prev = [[None for _ in range(self.m)] for _ in range(self.n)]
dxy = [] dxy = []
if start_point[1] - end_point[1] == 0 and start_point[0] - end_point[0] < 0: if start_point[1] - end_point[1] == 0 and start_point[0] - end_point[0] < 0:
dxy = dxy5 dxy = dxy5
@ -205,16 +200,13 @@ class UniformCostSearch:
goal_answer = [] goal_answer = []
for _ in range(0, len(end_point)): for _ in range(0, len(end_point)):
goal_answer.append(10**8) goal_answer.append(10**8)
path = self.ucs(start_point, [end_point], grid, prev, dxy, goal_answer) path = self.ucs(start_point, [end_point], grid, dxy, goal_answer)
if path is None:
return None
return path return path
def run() -> None: if __name__ == "__main__":
"""
Return None. Its just running the UCS algorithm class.
>>> run()
None
"""
executed_object = UniformCostSearch( executed_object = UniformCostSearch(
[ [
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
@ -266,7 +258,3 @@ def run() -> None:
], ],
) )
print(path_result) print(path_result)
if __name__ == "__main__":
run()

View File

@ -4,14 +4,28 @@ This algorithm iterates through a sorted collection with a step of n^(1/2),
until the element compared is bigger than the one searched. until the element compared is bigger than the one searched.
It will then perform a linear search until it matches the wanted number. It will then perform a linear search until it matches the wanted number.
If not found, it returns -1. If not found, it returns -1.
https://en.wikipedia.org/wiki/Jump_search
""" """
import math import math
from collections.abc import Sequence
from typing import Any, Protocol, TypeVar
def jump_search(arr: list, x: int) -> int: class Comparable(Protocol):
def __lt__(self, other: Any, /) -> bool:
...
T = TypeVar("T", bound=Comparable)
def jump_search(arr: Sequence[T], item: T) -> int:
""" """
Pure Python implementation of the jump search algorithm. Python implementation of the jump search algorithm.
Return the index if the `item` is found, otherwise return -1.
Examples: Examples:
>>> jump_search([0, 1, 2, 3, 4, 5], 3) >>> jump_search([0, 1, 2, 3, 4, 5], 3)
3 3
@ -21,31 +35,36 @@ def jump_search(arr: list, x: int) -> int:
-1 -1
>>> jump_search([0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610], 55) >>> jump_search([0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610], 55)
10 10
>>> jump_search(["aa", "bb", "cc", "dd", "ee", "ff"], "ee")
4
""" """
n = len(arr) arr_size = len(arr)
step = int(math.floor(math.sqrt(n))) block_size = int(math.sqrt(arr_size))
prev = 0 prev = 0
while arr[min(step, n) - 1] < x: step = block_size
while arr[min(step, arr_size) - 1] < item:
prev = step prev = step
step += int(math.floor(math.sqrt(n))) step += block_size
if prev >= n: if prev >= arr_size:
return -1 return -1
while arr[prev] < x: while arr[prev] < item:
prev = prev + 1 prev += 1
if prev == min(step, n): if prev == min(step, arr_size):
return -1 return -1
if arr[prev] == x: if arr[prev] == item:
return prev return prev
return -1 return -1
if __name__ == "__main__": if __name__ == "__main__":
user_input = input("Enter numbers separated by a comma:\n").strip() user_input = input("Enter numbers separated by a comma:\n").strip()
arr = [int(item) for item in user_input.split(",")] array = [int(item) for item in user_input.split(",")]
x = int(input("Enter the number to be searched:\n")) x = int(input("Enter the number to be searched:\n"))
res = jump_search(arr, x)
res = jump_search(array, x)
if res == -1: if res == -1:
print("Number not found!") print("Number not found!")
else: else: