A desktop spell checker application built with C++ and Qt, featuring intelligent word suggestions and auto-completion using a Trie data structure.
✨ Spell Checking - Verify if words are correctly spelled against a dictionary
- Real-time validation with visual feedback (green for correct, red for incorrect)
- Support for alphabetic characters only
- Input validation to ensure only letters are processed
🔍 Smart Suggestions - Get intelligent word recommendations using Levenshtein distance algorithm
- Provides up to 10 suggestions for misspelled words
- Suggestions sorted by edit distance and alphabetically
- Maximum edit distance of 2 for optimal relevance
- Click any suggestion to instantly check it
⚡ Auto-Complete - Predictive text completion as you type
- Displays up to 10 matching words based on your prefix
- Alphabetically sorted results
- Efficient prefix matching using Trie structure
- Interactive list - click any word to use it as the new prefix
The application uses a Trie as its core data structure for efficient word storage and retrieval:
- Structure: Each node represents a single character, with 26 possible children (one for each letter a-z)
- Word Storage: Complete words are formed by following paths from the root to nodes marked as "end of word"
- Efficiency: Searching for a word takes O(m) time where m is the word length, regardless of dictionary size
- Memory Efficient: Common prefixes are shared, reducing redundant storage
Why Trie? Unlike a simple list or hash table, a Trie excels at prefix-based operations, making it perfect for auto-complete functionality.
For spelling suggestions, the application uses the Levenshtein distance (edit distance) algorithm:
- What it measures: The minimum number of single-character edits needed to transform one word into another
- Edit operations: Insertions, deletions, and substitutions
- Implementation: Recursive approach that explores all possible edit paths
- Filtering: Only words within 2 edits are considered for suggestions
- Sorting: Results are ordered by similarity (lower distance first) and then alphabetically
Example: "cat" → "bat" requires 1 substitution (distance = 1), while "cat" → "cats" requires 1 insertion (distance = 1)
When the application starts, it reads dictionary.txt and inserts each word into the Trie. The process:
- Converts each word to lowercase for case-insensitive matching
- Validates that words contain only letters
- Creates Trie nodes for each character in the word
- Marks the final node as "end of word"
To verify a word's spelling:
- Convert input to lowercase
- Traverse the Trie character by character
- If any character path doesn't exist, the word is not in the dictionary
- If we reach the end and the node is marked as "end of word", it's correctly spelled
When a word is misspelled:
- Collect all words from the dictionary (by traversing the entire Trie)
- Calculate Levenshtein distance between the input and each dictionary word
- Keep only words within the maximum allowed distance (2 edits)
- Sort by distance first, then alphabetically
- Return the top 10 matches
For predictive text:
- Navigate through the Trie following the input prefix
- If the prefix doesn't exist, return empty results
- From the prefix node, collect all complete words underneath it
- Sort results alphabetically
- Return up to 10 matches
The application implements a custom StringArray class that automatically grows as needed:
- Initial capacity: 10 strings
- Growth strategy: Doubles in size when full
- Why custom?: Avoids standard library dependencies and demonstrates manual memory management
- Methods:
pushBack()for adding elements with automatic resizing
- C++ - Core application logic, memory management, and algorithms
- Qt Framework - Cross-platform GUI development
QMainWindow- Main application windowQLineEdit- Text input fieldsQListWidget- Displaying suggestions and auto-complete resultsQPushButton- Trigger actionsQLabel- Display status messagesQGroupBox- Organize related UI elementsQStatusBar- Show dictionary load status
- Custom Data Structures - Trie and dynamic array implementations
Spell-Checker/
├��─ main.cpp # Application entry point - creates Qt app and main window
├── MainWindow.h # Main window class declaration
├── MainWindow.cpp # GUI implementation, event handlers, user interaction logic
├── SpellChecker.h # Spell checker class, Trie node, and StringArray declarations
├── SpellChecker.cpp # Core algorithms: Trie operations, Levenshtein distance, suggestions
├── MainWindow.ui # Qt UI design file (designer layout)
└── dictionary.txt # Word dictionary - one word per line
SpellChecker.cpp/h - The brain of the application
- Trie node implementation and memory management
- Word insertion and lookup algorithms
- Recursive Levenshtein distance calculation
- Trie traversal for collecting words
- Dictionary loading from text file
MainWindow.cpp/h - The user interface
- Qt widget setup and layout management
- Signal-slot connections for button clicks
- Input validation (letters only)
- Display formatting (colors, styling)
- Interactive list item selection
main.cpp - Simple entry point
- Creates Qt application instance
- Instantiates and displays main window
- Starts the event loop
Before building this project, ensure you have:
- C++ Compiler - Supporting C++11 or later (GCC, Clang, MSVC)
- Qt Framework - Version 5.x or 6.x
- Qt Core
- Qt Widgets
- Qt GUI
- CMake or qmake - For building the project
- Dictionary file -
dictionary.txtin the same directory as the executable
git clone https://github.com/Mahmoud7111/Spell-Checker.git
cd Spell-CheckerUbuntu/Debian:
sudo apt-get install qt5-default qtbase5-devmacOS (using Homebrew):
brew install qtWindows: Download and install from Qt Official Website
Using qmake:
qmake
makeUsing Qt Creator:
- Open Qt Creator
- File → Open File or Project
- Select the project files
- Configure build settings
- Build → Build Project
- Run
Ensure dictionary.txt is in the same directory as your executable. The file should contain one word per line:
apple
banana
cherry
dictionary
...
Run the compiled executable:
./Spell-CheckerOn launch, the status bar displays the number of words loaded from the dictionary.
- Enter a word in the "Spell Check" input field
- Click "Check Word" or press Enter
- View the result:
- ✅ Green text: "The word is spelled correctly."
- ❌ Red text: "The word is NOT in the dictionary."
- Review suggestions in the list below (if word is incorrect)
- Click any suggestion to auto-fill it and check again
- Type a prefix in the "Auto-complete" input field (e.g., "app")
- Click "Auto-complete" button
- Browse results - all words starting with your prefix appear
- Click any word to use it as the new prefix and see more completions
- Only alphabetic characters (A-Z, a-z) are accepted
- Numbers, symbols, and special characters trigger a warning dialog
- Empty input is rejected
- Dictionary Loading: O(n × m) where n = number of words, m = average word length
- Word Check: O(m) - constant time relative to dictionary size
- Auto-Complete: O(k) where k = number of matching words
- Suggestions: O(n × m²) - needs optimization for very large dictionaries
- Trie Storage: O(ALPHABET_SIZE × n × m) = O(26 × n × m)
- Shared prefixes reduce actual memory usage significantly
The Levenshtein distance implementation is currently recursive without memoization. For better performance with larger dictionaries, dynamic programming with a 2D table would reduce time complexity from exponential to O(m₁ × m₂).
- Dynamic Programming - Optimize Levenshtein distance with memoization or iterative DP
- Word Frequency - Prioritize common words in suggestions using frequency data
- Multi-language Support - Load different dictionaries for various languages
- Custom Dictionary Management - GUI to add/remove words from the dictionary
- File Spell Check - Open and check entire text documents
- Persistent Custom Words - Save user-added words between sessions
- Keyboard Shortcuts - Enter key for checking, Ctrl+K for quick check
- Dark Mode / Themes - User-selectable color schemes
- Phonetic Matching - Suggest words that sound similar (Soundex algorithm)
- Contextual Suggestions - Use previous words to improve suggestions
- Manual Trie node allocation and deallocation without memory leaks
- Recursive destructor properly frees all child nodes
- Dynamic array that grows without leaving orphaned memory
- Recursive Levenshtein distance without standard library helpers
- Efficient Trie traversal for word collection
- Sorting without STL algorithms (bubble sort for small datasets)
- Signal-slot connections for responsive UI
- Lambda functions for inline event handling
- Proper widget lifecycle management within Qt's parent-child system
Contributions are welcome! If you'd like to improve this project:
- Fork the repository
- Create a feature branch (
git checkout -b feature/AmazingFeature) - Commit your changes (
git commit -m 'Add some AmazingFeature') - Push to the branch (
git push origin feature/AmazingFeature) - Open a Pull Request
- Implementing dynamic programming for Levenshtein distance
- Adding unit tests
- Creating a CLI version alongside the GUI
- Improving UI/UX design
- Adding internationalization support
This project is open source and available
Mahmoud7111
- GitHub: @Mahmoud7111
- Qt Framework for providing excellent cross-platform GUI tools
- Trie data structure for efficient prefix-based operations
- Levenshtein distance algorithm for intelligent similarity matching
- Open-source community for inspiration and best practices
⭐ If you find this project helpful, please consider giving it a star!