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(" \n Example 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(" \n Multiple 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(" \n Example 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(" \n Example 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