Skip to lab content

WEEK 5 · ADVANCED DATA STRUCTURES LAB

Jump search in a sorted array

B.Tech CSE & Allied Branches · II Year, I Semester · AR25C173 tested sample runs

THE SYLLABUS TASK

What you need to solve

Implement Jump Search on a sorted list of integers.
Input format & conventions

n (1–100), n values in nondecreasing order, then key. Values and key may be signed. Reported indexes start at zero; duplicate keys return the first occurrence.

UNDERSTAND THE IDEA

Explanation

Jump search skips blocks by comparing the key with each block’s final value. Once that value is at least the key, the key can only lie in the current block or be absent.

A short linear scan searches that candidate block. The step size is floor(sqrt(n)), calculated once without needing a math-library square root.

The complete demonstration also verifies sorted input before starting the search. That validation affects the complete program’s complexity.

TURN THE IDEA INTO STEPS

Step-by-step algorithm

  1. Validate n, values and the sorted-order prerequisite.
  2. Choose a positive integer block length near sqrt(n).
  3. Skip blocks while their last value is below the key.
  4. Scan the bounded candidate block until the key matches or larger values rule it out.
  5. Return the zero-based index or print Not found.

SEE THE CONTROL FLOW

Flowcharts

Diamonds show decisions; labeled arrows select a branch. Returning arrows repeat work. Helper-function steps group the operations explained above and in the code. These charts focus on the named core operation. On a phone, scroll within the diagram or open the full-size version.

Find and scan a candidate block

Find and scan a candidate block

Open full-size flowchart ↗

C17

Complete C program

Download .c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>

/* Read one entire token; reject malformed, oversized and out-of-range input. */
int readToken(char text[], size_t capacity) {
    int ch; size_t used = 0; int fits = 1;
    while ((ch = getchar()) != EOF && isspace((unsigned char)ch)) { }
    if (ch == EOF) return 0;
    do {
        if (ch == 0) fits = 0;
        if (used + 1 < capacity) text[used++] = (char)ch;
        else fits = 0;
        ch = getchar();
    } while (ch != EOF && !isspace((unsigned char)ch));
    text[used] = '\0';
    return fits;
}
int readInt(int *value) {
    char token[64], *end;
    if (!readToken(token, sizeof token)) return 0;
    errno = 0; long result = strtol(token, &end, 10);
    if (errno || end == token || *end || result < -1000000 || result > 1000000) return 0;
    *value = (int)result; return 1;
}
int invalid(void) { puts("Invalid or incomplete input."); return 1; }

#define MAX_N 100
int readArray(int a[], int *n, int nonnegative) {
    if (!readInt(n) || *n < 1 || *n > MAX_N) return 0;
    for (int i = 0; i < *n; ++i)
        if (!readInt(&a[i]) || (nonnegative && a[i] < 0)) return 0;
    return 1;
}
void printArray(const int a[], int n) {
    printf("Sorted:"); for (int i = 0; i < n; ++i) printf(" %d",a[i]); putchar('\n');
}

int jumpSearch(const int a[], int n, int key) {
    int block = 1; while ((block + 1) * (block + 1) <= n) ++block;
    int start = 0, end = block < n ? block : n;
    while (a[end - 1] < key) {
        start = end; if (start >= n) return -1;
        end = start + block < n ? start + block : n;
    }
    for (int i = start; i < end && a[i] <= key; ++i) if (a[i] == key) return i;
    return -1;
}

/* n, n ascending values, then key. Results use zero-based indexes. */
int main(void) {
    int a[MAX_N], n, key;
    if (!readArray(a,&n,0) || !readInt(&key)) return invalid();
    for (int i = 1; i < n; ++i) if (a[i] < a[i - 1]) { puts("Array must be sorted."); return 1; }
    int result = jumpSearch(a,n,key);
    if (result < 0) puts("Not found."); else printf("Found at index %d\n",result);
    return 0;
}

Local compile: gcc -std=c17 jump-search.c -o program -lm

Open in C compiler transfers the source. Copy the sample input into the compiler’s input box separately before running.

UNDERSTAND THE CODE

Line-by-line explanation

Follow the exact source above, from input handling through the algorithm and its result. Line numbers count blank lines; related statements are grouped into steps. Start with main to follow execution, then open the functions it calls.

Start with main → · Algorithm and data structure →

Lines 1–5Include input, conversion and validation declarations
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>

stdio.h supplies terminal input/output. stdlib.h declares conversion and allocation functions. string.h supplies string and memory utilities. ctype.h supplies isspace, and errno.h supplies conversion error reporting. Headers declare facilities; including them does not execute an operation.

Lines 7–9Define a complete-token reader and initialise its state
/* Read one entire token; reject malformed, oversized and out-of-range input. */
int readToken(char text[], size_t capacity) {
    int ch; size_t used = 0; int fits = 1;

readToken receives a writable buffer and its capacity. ch is int so it can represent EOF as well as input characters. used counts stored characters, and fits starts as a success flag. One slot must remain for the null terminator.

Lines 10–11Skip leading whitespace and recognise end-of-file
    while ((ch = getchar()) != EOF && isspace((unsigned char)ch)) { }
    if (ch == EOF) return 0;

Read until a non-whitespace character appears. The unsigned-char cast supplies an allowed value to isspace. Return 0 if EOF arrives before a token begins.

Lines 12–15Collect a token without silently truncating it
    do {
        if (ch == 0) fits = 0;
        if (used + 1 < capacity) text[used++] = (char)ch;
        else fits = 0;

The do body handles the character already read. An embedded zero byte marks the token invalid. Store a character only while there is room for it and a null terminator; otherwise clear fits. Continue reading even after the buffer fills.

Lines 16–20Consume the full token and terminate the buffer
        ch = getchar();
    } while (ch != EOF && !isspace((unsigned char)ch));
    text[used] = '\0';
    return fits;
}

Read through the next whitespace or EOF, add a null character after the stored prefix, then return fits. A too-long token returns 0 rather than pretending that its stored prefix is the complete token.

Lines 21–23Wrap token input as a checked integer read
int readInt(int *value) {
    char token[64], *end;
    if (!readToken(token, sizeof token)) return 0;

value is an output address. A 64-slot local buffer receives the token; a failed token read returns 0 before attempting conversion.

Lines 24–25Convert base-ten text and check the whole result
    errno = 0; long result = strtol(token, &end, 10);
    if (errno || end == token || *end || result < -1000000 || result > 1000000) return 0;

Reset errno before strtol. &end receives the stopping address. Reject conversion errors, no converted digits, leftover characters, or values outside -1,000,000 to 1,000,000. Thus 12x is not accepted as the integer 12.

Lines 26–28Return the accepted value or a standard error status
    *value = (int)result; return 1;
}
int invalid(void) { puts("Invalid or incomplete input."); return 1; }

Store a validated integer through *value and return 1 from readInt. invalid is a separate helper that prints the error and returns 1 as main’s failure status; the same number has different roles in these two function contracts.

Lines 30–32Read a bounded nonempty array length
#define MAX_N 100
int readArray(int a[], int *n, int nonnegative) {
    if (!readInt(n) || *n < 1 || *n > MAX_N) return 0;

MAX_N is 100. readArray receives an array, the caller’s count address, and a flag requesting nonnegative values. Require a count from 1 to 100; return 0 before using an invalid count.

Lines 33–36Read every element and apply the requested sign rule
    for (int i = 0; i < *n; ++i)
        if (!readInt(&a[i]) || (nonnegative && a[i] < 0)) return 0;
    return 1;
}

readInt checks each complete integer token. If nonnegative is nonzero, negative elements are also rejected. Return 1 only after every requested element has been accepted.

Lines 37–39Display the used array elements
void printArray(const int a[], int n) {
    printf("Sorted:"); for (int i = 0; i < n; ++i) printf(" %d",a[i]); putchar('\n');
}

printArray reads the first n elements without modifying them. It prints the Sorted label, a space before each value, and a final newline.

Lines 41–43Choose a block width and the initial block boundary
int jumpSearch(const int a[], int n, int key) {
    int block = 1; while ((block + 1) * (block + 1) <= n) ++block;
    int start = 0, end = block < n ? block : n;

Compute floor(sqrt(n)) using a small integer loop, then set start to 0 and end to the smaller of block and n. end is an exclusive bound, so end - 1 identifies the block’s final element. The caller guarantees n >= 1.

Lines 44–47Skip blocks whose final element is still below the key
    while (a[end - 1] < key) {
        start = end; if (start >= n) return -1;
        end = start + block < n ? start + block : n;
    }

Move start to the old end. If it reaches n, no elements remain. Otherwise advance end by one block, capped at n. This avoids reading past the array on the final partial block.

Lines 48–50Search only the candidate block sequentially
    for (int i = start; i < end && a[i] <= key; ++i) if (a[i] == key) return i;
    return -1;
}

Scan start..end-1 while values have not exceeded key. Return the first encountered equality or -1 if none exists. Ascending order justifies stopping once an element is greater than the target.

Lines 52–53Document sorted input and begin main
/* n, n ascending values, then key. Results use zero-based indexes. */
int main(void) {

The input is n, then n ascending values, then a search key. Found indexes are zero-based, so the first element is index 0.

Lines 54–56Read the array and verify ascending order
    int a[MAX_N], n, key;
    if (!readArray(a,&n,0) || !readInt(&key)) return invalid();
    for (int i = 1; i < n; ++i) if (a[i] < a[i - 1]) { puts("Array must be sorted."); return 1; }

Read the count, signed elements and target. Then reject any adjacent descent before calling the search; the search logic relies on ascending order. Equal adjacent elements are permitted.

Lines 57–60Run the search and interpret its result
    int result = jumpSearch(a,n,key);
    if (result < 0) puts("Not found."); else printf("Found at index %d\n",result);
    return 0;
}

Call jumpSearch and save the returned index. Negative means not found; otherwise print the zero-based index. Return success after a completed search, even when the key is absent.

FOLLOW THE VALUES

Dry run

  1. For [1,3,5,7,9,11], the block length is 2.
  2. Block [1,3] ends below key 7, so it is skipped.
  3. Block [5,7] ends at 7, so it is the candidate.
  4. The local scan checks 5 then 7 and returns index 3.

CHECK THE BEHAVIOUR

Sample input & output

These outputs were captured by running the exact C source shown above. Commands use the stated input format; the programs omit repeated menu prompts so the same sample can be pasted and run.

Sample 1

INPUT
6
1 3 5 7 9 11
7
OUTPUT
Found at index 3

Sample 2

INPUT
5
1 3 3 3 8
3
OUTPUT
Found at index 1

Sample 3

INPUT
4
1 2 3 4
9
OUTPUT
Not found.

Common mistakes

  • Always cap the last block at n before reading its final element.
  • Do not let the block length become zero.
  • Search complexity excludes this program’s full sorted-validation pass.

WHY THIS GROWTH RATE?

Time and space complexity

Search O(sqrt(n)); sorted validation and input O(n); auxiliary search space O(1).

With block length s, at most about n/s block checks and s local checks are needed. Balancing these terms gives s near sqrt(n).

This example calculates the integer block size with O(sqrt(n)) small steps once, retaining the search bound.

Reading n values and checking adjacent sorted order take O(n), so the whole demonstration is O(n). No additional search array or recursive stack is created.

Big-O describes growth in the stated input quantity. The educational limits keep examples safe; complexity discussions state which bounds depend on a generalized input size. Arithmetic on the accepted native numeric types is treated as constant-time.

PREPARE FOR YOUR LAB VIVA

Related viva questions & answers

6 focused questions

Try answering aloud, then expand the answer to check your reasoning. These questions focus on the concepts used in this program.

How is the jump block length selected in this program?

It is the largest integer whose square does not exceed n. The program computes it once and ensures it is at least one.

Why is the last element of a block sufficient to skip that block?

In nondecreasing order, every value in the block is at most its last value. If that last value is below the key, the entire block is too small.

Why is the final partial block capped at n?

The array length may not be a multiple of the step size. Capping the end prevents a block-boundary comparison from reading beyond the final element.

Why does this jump-search implementation return the first duplicate match?

It skips only blocks whose last value is strictly below the key, then scans the candidate block forward. It therefore does not skip an earlier equal value.

What happens when the key is larger than the entire array?

Blocks are skipped until start reaches n. The function returns not found before attempting to read another block or scan beyond the array.

Why is one enormous jump not an efficient general strategy?

It would leave nearly the entire array for the local scan. The square-root block length balances the number of jumps against the work within the candidate block.