Skip to content

Commit 1ae8bda

Browse files
authored
[FEATURE] Add Jump Search Algorithm Implementation in R (#216)
1 parent 65e82bf commit 1ae8bda

File tree

1 file changed

+287
-0
lines changed

1 file changed

+287
-0
lines changed

searches/jump_search.r

Lines changed: 287 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,287 @@
1+
# Jump Search Algorithm Implementation in R
2+
# An efficient search algorithm for sorted arrays
3+
# Works by jumping ahead by fixed steps then performing linear search
4+
# Time complexity: O(√n) where n is the array length
5+
# Space complexity: O(1)
6+
7+
library(R6)
8+
9+
#' JumpSearch Class
10+
#' @description R6 class implementing the Jump Search algorithm
11+
#' @details Jump Search is a searching algorithm for sorted arrays that works by:
12+
#' 1. Dividing the array into blocks of size √n
13+
#' 2. Jumping ahead by √n steps until finding a block where target might be
14+
#' 3. Performing linear search within that block
15+
#' Advantages:
16+
#' - Better than linear search: O(√n) vs O(n)
17+
#' - Better for systems with slow backward iteration compared to binary search
18+
#' - Simple implementation
19+
#' Limitations:
20+
#' - Requires sorted array
21+
#' - Slower than binary search: O(√n) vs O(log n)
22+
JumpSearch <- R6Class(
23+
"JumpSearch",
24+
25+
public = list(
26+
#' @description Initialize Jump Search
27+
#' @param data Sorted array to search in
28+
#' @param validate_sorted Whether to validate if array is sorted
29+
initialize = function(data = NULL, validate_sorted = TRUE) {
30+
if (!is.null(data)) {
31+
private$validate_input(data, validate_sorted)
32+
self$data <- data
33+
private$n <- length(data)
34+
private$optimal_jump <- floor(sqrt(private$n))
35+
}
36+
invisible(self)
37+
},
38+
39+
#' @description Search for a target value in the array
40+
#' @param target Value to search for
41+
#' @param jump_size Optional custom jump size (default: √n)
42+
#' @return List containing index, number of comparisons, and success status
43+
search = function(target, jump_size = NULL) {
44+
if (is.null(self$data)) {
45+
stop("No data available. Please initialize with data first.")
46+
}
47+
48+
# Use custom jump size or optimal jump size
49+
step <- if (is.null(jump_size)) private$optimal_jump else jump_size
50+
51+
if (step <= 0 || step != round(step)) {
52+
stop("Jump size must be a positive integer")
53+
}
54+
55+
prev <- 0
56+
comparisons <- 0
57+
58+
# Jump through array to find the block where target might be
59+
while (step <= private$n && self$data[step] < target) {
60+
comparisons <- comparisons + 1
61+
prev <- step
62+
step <- step + private$optimal_jump
63+
}
64+
65+
# If we've jumped past the end, adjust step to not exceed n
66+
if (prev >= private$n) {
67+
return(list(
68+
index = -1,
69+
comparisons = comparisons,
70+
found = FALSE
71+
))
72+
}
73+
74+
# Linear search in the identified block
75+
while ((prev + 1) <= private$n && self$data[prev + 1] <= target) {
76+
comparisons <- comparisons + 1
77+
prev <- prev + 1
78+
79+
if (self$data[prev] == target) {
80+
return(list(
81+
index = prev,
82+
comparisons = comparisons,
83+
found = TRUE
84+
))
85+
}
86+
}
87+
88+
# Target not found
89+
return(list(
90+
index = -1,
91+
comparisons = comparisons,
92+
found = FALSE
93+
))
94+
},
95+
96+
#' @description Search for multiple targets
97+
#' @param targets Vector of values to search for
98+
#' @return List of search results for each target
99+
search_multiple = function(targets) {
100+
if (!is.numeric(targets)) {
101+
stop("Targets must be numeric")
102+
}
103+
104+
results <- list()
105+
for (i in seq_along(targets)) {
106+
results[[i]] <- self$search(targets[i])
107+
results[[i]]$target <- targets[i]
108+
}
109+
return(results)
110+
},
111+
112+
#' @description Find the optimal jump size for the current data
113+
#' @return Optimal jump size (√n)
114+
get_optimal_jump_size = function() {
115+
if (is.null(self$data)) {
116+
stop("No data available. Please initialize with data first.")
117+
}
118+
return(private$optimal_jump)
119+
},
120+
121+
#' @description Compare performance with different jump sizes
122+
#' @param target Value to search for
123+
#' @param jump_sizes Vector of jump sizes to test
124+
#' @return Data frame with performance comparison
125+
compare_jump_sizes = function(target, jump_sizes = NULL) {
126+
if (is.null(self$data)) {
127+
stop("No data available. Please initialize with data first.")
128+
}
129+
130+
if (is.null(jump_sizes)) {
131+
jump_sizes <- c(
132+
floor(sqrt(private$n) / 2),
133+
private$optimal_jump,
134+
floor(sqrt(private$n) * 2)
135+
)
136+
}
137+
138+
results <- data.frame(
139+
jump_size = numeric(),
140+
comparisons = numeric(),
141+
found = logical(),
142+
stringsAsFactors = FALSE
143+
)
144+
145+
for (size in jump_sizes) {
146+
if (size > 0 && size <= private$n) {
147+
result <- self$search(target, jump_size = size)
148+
results <- rbind(results, data.frame(
149+
jump_size = size,
150+
comparisons = result$comparisons,
151+
found = result$found
152+
))
153+
}
154+
}
155+
156+
return(results)
157+
},
158+
159+
#' @description Update the data array
160+
#' @param new_data New sorted array
161+
#' @param validate_sorted Whether to validate if array is sorted
162+
update_data = function(new_data, validate_sorted = TRUE) {
163+
private$validate_input(new_data, validate_sorted)
164+
self$data <- new_data
165+
private$n <- length(new_data)
166+
private$optimal_jump <- floor(sqrt(private$n))
167+
invisible(self)
168+
},
169+
170+
# Public fields
171+
data = NULL
172+
),
173+
174+
private = list(
175+
n = NULL,
176+
optimal_jump = NULL,
177+
178+
validate_input = function(data, check_sorted) {
179+
if (!is.numeric(data)) {
180+
stop("Input data must be numeric")
181+
}
182+
if (any(is.na(data))) {
183+
stop("Input data contains missing values")
184+
}
185+
if (length(data) == 0) {
186+
stop("Input data cannot be empty")
187+
}
188+
if (check_sorted && !private$is_sorted(data)) {
189+
stop("Input data must be sorted in ascending order")
190+
}
191+
},
192+
193+
is_sorted = function(data) {
194+
all(diff(data) >= 0)
195+
}
196+
)
197+
)
198+
199+
# Demonstration
200+
demonstrate_jump_search <- function() {
201+
cat("=== Jump Search Algorithm Demo ===\n\n")
202+
203+
# Example 1: Basic usage
204+
cat("Example 1: Basic jump search\n")
205+
data <- c(1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29)
206+
cat("Sorted array:", paste(data, collapse = ", "), "\n")
207+
208+
js <- JumpSearch$new(data)
209+
cat(sprintf("Array size: %d, Optimal jump size: %d\n\n",
210+
length(data), js$get_optimal_jump_size()))
211+
212+
targets <- c(7, 19, 30)
213+
for (target in targets) {
214+
result <- js$search(target)
215+
if (result$found) {
216+
cat(sprintf("Target %d found at index %d (comparisons: %d)\n",
217+
target, result$index, result$comparisons))
218+
} else {
219+
cat(sprintf("Target %d not found (comparisons: %d)\n",
220+
target, result$comparisons))
221+
}
222+
}
223+
224+
# Example 2: Larger dataset
225+
cat("\nExample 2: Larger dataset\n")
226+
set.seed(42)
227+
large_data <- sort(sample(1:1000, 100))
228+
js2 <- JumpSearch$new(large_data)
229+
230+
cat(sprintf("Array size: %d, Optimal jump size: %d\n",
231+
length(large_data), js2$get_optimal_jump_size()))
232+
233+
search_targets <- c(large_data[25], large_data[75], 999)
234+
results <- js2$search_multiple(search_targets)
235+
236+
cat("\nMultiple search results:\n")
237+
for (i in seq_along(results)) {
238+
res <- results[[i]]
239+
cat(sprintf("Target %d: %s (index: %d, comparisons: %d)\n",
240+
res$target,
241+
ifelse(res$found, "Found", "Not found"),
242+
res$index,
243+
res$comparisons))
244+
}
245+
246+
# Example 3: Jump size comparison
247+
cat("\nExample 3: Comparing different jump sizes\n")
248+
test_data <- 1:100
249+
js3 <- JumpSearch$new(test_data)
250+
target <- 87
251+
252+
comparison <- js3$compare_jump_sizes(target)
253+
cat(sprintf("Searching for %d in array of size %d:\n\n", target, length(test_data)))
254+
print(comparison)
255+
256+
# Example 4: Performance analysis
257+
cat("\nExample 4: Performance analysis\n")
258+
sizes <- c(100, 1000, 10000)
259+
260+
cat("Average comparisons for different array sizes:\n")
261+
for (n in sizes) {
262+
test_array <- 1:n
263+
js_test <- JumpSearch$new(test_array)
264+
265+
# Test multiple searches
266+
num_tests <- 20
267+
total_comps <- 0
268+
for (i in 1:num_tests) {
269+
target <- sample(test_array, 1)
270+
result <- js_test$search(target)
271+
total_comps <- total_comps + result$comparisons
272+
}
273+
274+
avg_comps <- total_comps / num_tests
275+
theoretical_bound <- sqrt(n)
276+
277+
cat(sprintf("n = %5d: Avg comparisons = %.1f, Theoretical O(√n) = %.1f\n",
278+
n, avg_comps, theoretical_bound))
279+
}
280+
281+
cat("\n=== Demo Complete ===\n")
282+
}
283+
284+
# Run demonstration if not in interactive mode
285+
if (!interactive()) {
286+
demonstrate_jump_search()
287+
}

0 commit comments

Comments
 (0)