Fibonacci Search Visualizer using PyQt5

The Fibonacci Search is an efficient algorithm for searching sorted arrays using Fibonacci numbers. Here, we'll create a visual demonstration of this algorithm using PyQt5 to help understand how it divides the search space.

How Fibonacci Search Works

The algorithm uses Fibonacci numbers to divide the sorted array into unequal parts, similar to binary search but with golden ratio proportions. It finds two consecutive Fibonacci numbers that are greater than or equal to the array length.

Algorithm Steps

Step 1: Find the smallest Fibonacci number greater than or equal to the array length.

Step 2: Initialize three Fibonacci numbers: fib2 = 0, fib1 = 1, fib = 1.

Step 3: Use these numbers to calculate division points in the array.

Step 4: Compare the target with the element at the division point and eliminate sections accordingly.

Step 5: Repeat until the element is found or the search space is exhausted.

PyQt5 Implementation

The visualizer uses QLabel widgets to represent array elements and highlights the search process ?

# importing libraries
from PyQt5.QtWidgets import *
from PyQt5 import QtCore, QtGui
from PyQt5.QtGui import *
from PyQt5.QtCore import *
import sys


class FibonacciSearchVisualizer(QMainWindow):
    def __init__(self):
        super().__init__()
        self.numbers = [1, 3, 5, 8, 12, 15, 18, 21, 25, 30]
        self.target = 15
        self.setup_ui()
        self.setup_fibonacci_search()
        
    def setup_ui(self):
        self.setWindowTitle("Fibonacci Search Visualizer")
        self.setGeometry(100, 100, 800, 500)
        
        # Create labels for array elements
        self.element_labels = []
        for i, num in enumerate(self.numbers):
            label = QLabel(str(num), self)
            label.setStyleSheet("""
                border: 2px solid black;
                background-color: lightblue;
                font-size: 14px;
                font-weight: bold;
            """)
            label.setAlignment(Qt.AlignCenter)
            label.setGeometry(50 + i * 70, 100, 60, 40)
            self.element_labels.append(label)
        
        # Control buttons
        self.start_button = QPushButton("Start Search", self)
        self.start_button.setGeometry(100, 200, 120, 40)
        self.start_button.clicked.connect(self.start_search)
        
        self.pause_button = QPushButton("Pause", self)
        self.pause_button.setGeometry(250, 200, 120, 40)
        self.pause_button.clicked.connect(self.pause_search)
        
        self.reset_button = QPushButton("Reset", self)
        self.reset_button.setGeometry(400, 200, 120, 40)
        self.reset_button.clicked.connect(self.reset_search)
        
        # Status label
        self.status_label = QLabel(f"Ready to search for: {self.target}", self)
        self.status_label.setGeometry(50, 300, 600, 40)
        self.status_label.setStyleSheet("""
            border: 2px solid black;
            padding: 10px;
            font-size: 12px;
            background-color: lightyellow;
        """)
        self.status_label.setAlignment(Qt.AlignCenter)
        
        # Timer for animation
        self.timer = QTimer(self)
        self.timer.timeout.connect(self.animate_search)
        
    def setup_fibonacci_search(self):
        self.is_searching = False
        self.search_complete = False
        
        # Initialize Fibonacci numbers
        self.fib2 = 0
        self.fib1 = 1
        self.fib = self.fib1 + self.fib2
        
        # Find smallest Fibonacci number >= array length
        while self.fib < len(self.numbers):
            self.fib2 = self.fib1
            self.fib1 = self.fib
            self.fib = self.fib1 + self.fib2
        
        self.offset = -1
        self.step = 0
        
    def start_search(self):
        if not self.is_searching and not self.search_complete:
            self.is_searching = True
            self.status_label.setText("Starting Fibonacci search...")
            self.timer.start(1000)  # 1 second intervals
            
    def pause_search(self):
        if self.is_searching:
            self.is_searching = False
            self.timer.stop()
            self.status_label.setText("Search paused")
            
    def reset_search(self):
        self.timer.stop()
        self.is_searching = False
        self.search_complete = False
        self.setup_fibonacci_search()
        
        # Reset all labels
        for label in self.element_labels:
            label.setStyleSheet("""
                border: 2px solid black;
                background-color: lightblue;
                font-size: 14px;
                font-weight: bold;
            """)
        
        self.status_label.setText(f"Ready to search for: {self.target}")
        
    def animate_search(self):
        if not self.is_searching:
            return
            
        # Check if search is complete
        if self.fib <= 1:
            self.status_label.setText("Element not found!")
            self.timer.stop()
            self.is_searching = False
            self.search_complete = True
            return
            
        # Calculate index to check
        i = min(self.offset + self.fib2, len(self.numbers) - 1)
        
        # Highlight current element being checked
        self.element_labels[i].setStyleSheet("""
            border: 3px solid orange;
            background-color: yellow;
            font-size: 14px;
            font-weight: bold;
        """)
        
        # Compare with target
        if self.numbers[i] < self.target:
            self.fib = self.fib1
            self.fib1 = self.fib2
            self.fib2 = self.fib - self.fib1
            self.offset = i
            self.status_label.setText(f"Element {self.numbers[i]} < {self.target}, searching right")
            
        elif self.numbers[i] > self.target:
            self.fib = self.fib2
            self.fib1 = self.fib1 - self.fib2
            self.fib2 = self.fib - self.fib1
            self.status_label.setText(f"Element {self.numbers[i]} > {self.target}, searching left")
            
        else:
            # Found the element
            self.element_labels[i].setStyleSheet("""
                border: 3px solid green;
                background-color: lightgreen;
                font-size: 14px;
                font-weight: bold;
            """)
            self.status_label.setText(f"Found {self.target} at index {i}!")
            self.timer.stop()
            self.is_searching = False
            self.search_complete = True
            

if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = FibonacciSearchVisualizer()
    window.show()
    sys.exit(app.exec_())

Key Features

The visualizer includes:

  • Array Visualization: Elements displayed as labeled boxes
  • Step-by-step Animation: Shows each comparison with color coding
  • Control Buttons: Start, pause, and reset functionality
  • Status Updates: Real-time information about the search progress

Time Complexity

Fibonacci search has a time complexity of O(log n), making it efficient for large sorted arrays. It's particularly useful when the cost of division is high, as it uses only addition and subtraction operations.

Conclusion

This Fibonacci Search Visualizer demonstrates how the algorithm efficiently narrows down the search space using Fibonacci numbers. The visual approach helps understand the golden ratio-based division strategy that makes this algorithm unique among search techniques.

---
Updated on: 2026-03-27T11:55:02+05:30

383 Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements