C program to simulate Nondeterministic Finite Automata (NFA)

In this problem, we will create a C program to simulate Non-deterministic Finite Automata (NFA). NFA is a finite state machine that can move to any combination of states for an input symbol, meaning there is no exact state to which the machine will move.

Syntax

struct node {
    int data;
    struct node* next;
    char edgetype;
};

int nfa(node** graph, int current, char* input, int* accept, int start);

Formal Definition of NFA

NFA can be represented by 5-tuple (Q, ?, ?, q0, F) where −

  • Q is a finite set of states.
  • ? is a finite set of symbols called the alphabets.
  • ? is the transition function where ?: Q × ? ? 2^Q (power set of Q because from a state, transition can occur to any combination of states)
  • q0 is the initial state from where any input is processed (q0 ? Q).
  • F is a set of final state/states of Q (F ? Q).

NFA Representation

1 2 3 4 1 1 1 0 0,1 0 Start

Starting state ? 1, Final state (accepting state) ? 4

Example: NFA Simulation Program

This program creates an NFA using adjacency lists and checks if input strings are accepted −

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <math.h>

int row = 0;

struct node {
    int data;
    struct node* next;
    char edgetype;
} typedef node;

// Adds an edge to an adjacency list
node* push(node* first, char edgetype, int data) {
    node* new_node = (node*)malloc(sizeof(node));
    new_node->edgetype = edgetype;
    new_node->data = data;
    new_node->next = NULL;
    
    if (first == NULL) {
        first = new_node;
        return new_node;
    }
    first->next = push(first->next, edgetype, data);
    return first;
}

// Recursive function to check acceptance of input
int nfa(node** graph, int current, char* input, int* accept, int start) {
    if (start == (int)strlen(input))
        return accept[current];
    
    node* temp = graph[current];
    while (temp != NULL) {
        if (input[start] == temp->edgetype) {
            if (nfa(graph, temp->data, input, accept, start + 1) == 1) {
                return 1;
            }
        }
        temp = temp->next;
    }
    return 0;
}

// Function to generate binary strings of size n
void generate(char** arr, int size, char *a) {
    if (size == 0) {
        strcpy(arr[row], a);
        row++;
        return;
    }
    
    char b0[20] = {'\0'};
    char b1[20] = {'\0'};
    b0[0] = '0';
    b1[0] = '1';
    generate((char**)arr, size - 1, strcat(b0, a)); // Add 0 in front
    generate((char**)arr, size - 1, strcat(b1, a)); // Add 1 in front
    return;
}

int main() {
    int n;
    int i, j;
    scanf("%d", &n); // Number of nodes
    
    node* graph[n + 1]; // Create a graph
    for (i = 0; i < n + 1; i++)
        graph[i] = NULL;
    
    int accept[n + 1]; // Array to store state of vertex
    
    for (i = 0; i < n; i++) {
        // Index of vertex, Acceptance state, Number of edges
        int index, acc, number_nodes;
        scanf("%d%d%d", &index, &acc, &number_nodes);
        accept[index] = acc; // Store acceptance
        
        for (j = 0; j < number_nodes; j++) { // Add all edges
            int node_add;
            int edge;
            scanf("%d%d", &edge, &node_add);
            graph[index] = push(graph[index], '0' + edge, node_add);
        }
    }
    
    int size = 1; // Size of input
    int count = 0; // Keep count of output strings
    
    if (accept[1] == 1) { // Check for empty string
        printf("e<br>");
        count++;
    }
    
    while (count < 11) {
        char** arr;
        int power = pow(2, size);
        arr = (char**)malloc(power * sizeof(char*));
        for (i = 0; i < power; i++)
            arr[i] = (char*)malloc(size * sizeof(char));
        
        char a[20] = {'\0'};
        generate((char**)arr, size, a); // Generate inputs
        
        for (i = 0; i < power; i++) {
            char input[20] = {'\0'};
            for (j = 0; j < size; j++) {
                char foo[2];
                foo[0] = arr[i][size - 1 - j];
                foo[1] = '\0';
                strcat(input, foo);
                // Copy generated string input
            }
            
            int result = nfa(graph, 1, input, accept, 0);
            // Store result of nfa
            if (result == 1) {
                printf("%s<br>", input);
                count++;
            }
            if (count == 10)
                break;
        }
        
        // Free allocated memory
        for (i = 0; i < power; i++)
            free(arr[i]);
        free(arr);
        
        size++; // Increment size of binary string input
        row = 0;
    }
    return 0;
}

Input Format

4
1 0 4 0 1 0 2 1 1 1 3
2 0 1 0 4
3 0 1 1 4
4 1 2 0 4 1 4

Output

00
11
000
001
011
100
110
111
0000
0001

How It Works

  • The program uses an adjacency list representation of the NFA graph
  • Each node contains the target state and the edge label (0 or 1)
  • The nfa() function recursively explores all possible paths for a given input string
  • If any path leads to an accepting state after consuming the entire input, the string is accepted

Conclusion

This NFA simulation demonstrates how non-deterministic finite automata can accept multiple paths for the same input. The recursive approach explores all possible state transitions to determine string acceptance in the language defined by the NFA.

Updated on: 2026-03-15T12:53:39+05:30

4K+ Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements