Skip to lab content

WEEK 5 · ADVANCED DATA STRUCTURES LAB

Fibonacci 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 Fibonacci Search on a sorted list of integers.
Input format & conventions

n (1–100), n nondecreasing signed values, then key. Indexes start at zero. With duplicates, any matching occurrence may be returned.

UNDERSTAND THE IDEA

Explanation

Fibonacci search uses three neighboring Fibonacci numbers to describe the current search range. It first grows them until the largest covers the array length.

Offset records the end of the discarded prefix. A probe is offset plus the smaller Fibonacci number, capped at n−1.

A comparison discards one Fibonacci-sized portion and updates the triple using subtraction. A final bounded check handles a possible remaining element.

TURN THE IDEA INTO STEPS

Step-by-step algorithm

  1. Validate the sorted array and grow f2, f1, f until f ≥ n.
  2. Initialize offset to −1 and calculate a capped probe.
  3. If the probed value is too small, discard the prefix and step down one Fibonacci level.
  4. If too large, retain the left portion and step down two levels.
  5. Return a match; otherwise check the final candidate only if offset+1 < n.

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.

Fibonacci interval reduction

Fibonacci interval reduction

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 fibonacciSearch(const int a[], int n, int key) {
    int f2 = 0, f1 = 1, f = 1, offset = -1;
    while (f < n) { f2 = f1; f1 = f; f = f1 + f2; }
    while (f > 1) {
        int i = offset + f2; if (i >= n) i = n - 1;
        if (a[i] < key) { f = f1; f1 = f2; f2 = f - f1; offset = i; }
        else if (a[i] > key) { f = f2; f1 -= f2; f2 = f - f1; }
        else return i;
    }
    if (f1 && offset + 1 < n && a[offset + 1] == key) return offset + 1;
    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 = fibonacciSearch(a,n,key);
    if (result < 0) puts("Not found."); else printf("Found at index %d\n",result);
    return 0;
}

Local compile: gcc -std=c17 fibonacci-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–43Build Fibonacci numbers covering the array length
int fibonacciSearch(const int a[], int n, int key) {
    int f2 = 0, f1 = 1, f = 1, offset = -1;
    while (f < n) { f2 = f1; f1 = f; f = f1 + f2; }

f2, f1 and f track consecutive Fibonacci values. Increase them until f is at least n. offset = -1 marks the boundary before the initially unexplored array.

Lines 44–45Choose a Fibonacci-spaced comparison index
    while (f > 1) {
        int i = offset + f2; if (i >= n) i = n - 1;

While the current Fibonacci range is larger than one, test offset + f2, capped at n - 1. Capping makes the comparison safe when the Fibonacci coverage exceeds the actual array length.

Line 46Move right when the tested value is too small
        if (a[i] < key) { f = f1; f1 = f2; f2 = f - f1; offset = i; }

Discard positions through i by moving offset to i. Update the Fibonacci sizes to represent the remaining right-side search range.

Lines 47–49Move left for a larger value or return on equality
        else if (a[i] > key) { f = f2; f1 -= f2; f2 = f - f1; }
        else return i;
    }

A larger a[i] reduces the Fibonacci coverage to the left without advancing offset. Equality returns i immediately. The brace closes the shrinking-range loop.

Lines 50–52Check a possible last candidate before reporting absence
    if (f1 && offset + 1 < n && a[offset + 1] == key) return offset + 1;
    return -1;
}

When one candidate can remain, check its index bound and value. Return its index on equality; otherwise return -1.

Lines 54–55Document 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 56–58Read 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 59–62Run the search and interpret its result
    int result = fibonacciSearch(a,n,key);
    if (result < 0) puts("Not found."); else printf("Found at index %d\n",result);
    return 0;
}

Call fibonacciSearch 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 covering Fibonacci triple is f=8, f1=5, f2=3.
  2. With offset −1, the first probe is index 2, value 5.
  3. For key 9, update offset to 2 and reduce the triple to 5,3,2.
  4. The next probe is index 4, value 9, so the search succeeds.

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
9
OUTPUT
Found at index 4

Sample 2

INPUT
1
7
7
OUTPUT
Found at index 0

Sample 3

INPUT
4
1 2 3 4
9
OUTPUT
Not found.

Common mistakes

  • The final offset+1 test must be bounded before array access.
  • Update the Fibonacci triple in the correct dependency order.
  • Do not claim the first duplicate occurrence without a dedicated leftmost-search extension.

WHY THIS GROWTH RATE?

Time and space complexity

Search O(log n); complete input/validation O(n); auxiliary search space O(1).

Fibonacci numbers grow exponentially with their index, so building a covering number and stepping down through the sequence each require O(log n) steps.

The function keeps only a fixed triple, an offset and a probe, giving O(1) extra search space.

The accepted n≤100 bounds all Fibonacci additions. Reading and verifying sorted input scan n values, making the full demonstration O(n), even though the search itself is logarithmic.

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.

What does offset represent in Fibonacci search?

It is the last index of the prefix already ruled out as too small. The initial value −1 means no prefix has been discarded.

Why must the initial Fibonacci number be at least n?

The range representation must cover all n elements. A smaller covering number could leave final positions outside the represented search interval.

Why is a probe capped at n − 1?

A covering Fibonacci range can be longer than the actual array. Capping keeps a probe within valid storage while still comparing the largest remaining array position when necessary.

How does a too-small probe change the Fibonacci triple?

The search keeps the right portion by stepping from f to f1, shifting f1 to f2 and deriving the new smaller term by subtraction. Offset advances to the probe.

Why is the final remaining-element check conditional on its index?

A prior comparison can already have discarded the complete array. Checking offset + 1 < n prevents an out-of-range read in that absent-key case.

Does Fibonacci search build or store a whole Fibonacci sequence?

No. This implementation maintains only three neighboring terms. Their additions and subtractions are enough to choose successive ranges without storing an array of Fibonacci values.