Recursion & Backtracking in C: Tree Traversals, N-Queens, Sudoku, Subsets & Permutations with Code Examples

1. What is recursion in programming?

Recursion is a process where a function calls itself to solve smaller instances of the same problem until a base case is reached. It's widely used in problems with a recursive structure, like tree traversals.

2. How does recursion relate to trees?

Trees are inherently recursive: each node has subtrees (left and right children). Recursive algorithms naturally fit tree operations like traversals, searching, or height calculation, as each subtree is a smaller problem instance.

3. What are the components of a recursive function?

4. Can you give an example of recursion with a binary tree in C?

Example: Inorder traversal of a binary tree.

#include <stdio.h>
#include <stdlib.h>

struct Node {
    int data;
    struct Node* left;
    struct Node* right;
};

struct Node* createNode(int data) {
    struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
    newNode->data = data;
    newNode->left = newNode->right = NULL;
    return newNode;
}

void inorder(struct Node* root) {
    if (root == NULL) return; // Base case
    inorder(root->left); // Recursive case: left subtree
    printf("%d ", root->data); // Process root
    inorder(root->right); // Recursive case: right subtree
}

int main() {
    struct Node* root = createNode(1);
    root->left = createNode(2);
    root->right = createNode(3);
    root->left->left = createNode(4);
    root->left->right = createNode(5);
    inorder(root); // Output: 4 2 5 1 3
    return 0;
}
      

5. What are the advantages and disadvantages of recursion?

6. What is the time and space complexity of recursion in trees?

For tree traversals (e.g., inorder):

7. What is backtracking?

Backtracking is an algorithmic technique that incrementally builds solutions and abandons partial solutions (backtracks) when they cannot lead to a valid solution. It's like exploring a decision tree and pruning invalid paths.

8. How does backtracking work?

9. What are key features of backtracking?

10. What are common backtracking problems?

N-Queens, Sudoku, Subsets, Permutations, Graph Coloring, Knapsack.

11. What is the time complexity of backtracking?

Typically exponential (e.g., O(n!) for permutations), but pruning reduces practical runtime. Specific problems vary (e.g., O(n!) for N-Queens).

12. What is the N-Queens problem?

The N-Queens problem involves placing N queens on an N×N chessboard such that no two queens threaten each other (no shared row, column, or diagonal).

13. How is backtracking used in N-Queens?

Place queens row by row, checking if each placement is safe. If a placement leads to a conflict, backtrack and try a different column.

14. Can you give an example of N-Queens in C?

#include <stdio.h>
#include <stdbool.h>

#define N 4

bool isSafe(int board[N][N], int row, int col) {
    for (int i = 0; i < col; i++) // Check row
        if (board[row][i]) return false;
    for (int i = row, j = col; i >= 0 && j >= 0; i--, j--) // Upper diagonal
        if (board[i][j]) return false;
    for (int i = row, j = col; i < N && j >= 0; i++, j--) // Lower diagonal
        if (board[i][j]) return false;
    return true;
}

bool solveNQueensUtil(int board[N][N], int col) {
    if (col >= N) return true; // All queens placed
    for (int i = 0; i < N; i++) {
        if (isSafe(board, i, col)) {
            board[i][col] = 1; // Place queen
            if (solveNQueensUtil(board, col + 1)) return true;
            board[i][col] = 0; // Backtrack
        }
    }
    return false;
}

void printBoard(int board[N][N]) {
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < N; j++) printf("%d ", board[i][j]);
        printf("\n");
    }
}

void solveNQueens() {
    int board[N][N] = {0};
    if (solveNQueensUtil(board, 0)) printBoard(board);
    else printf("No solution exists\n");
}

int main() {
    solveNQueens(); // Output: One valid placement (e.g., 0 1 0 0 \n 0 0 0 1 \n 1 0 0 0 \n 0 0 1 0)
    return 0;
}
      

15. What is the time complexity of N-Queens?

Time Complexity: O(n!) (trying all possible placements with pruning).

Space Complexity: O(n²) for the board and O(n) for recursion stack.

16. What is the Sudoku problem?

The Sudoku problem involves filling a 9×9 grid with digits 1–9 such that each row, column, and 3×3 subgrid contains unique digits, starting from a partially filled grid.

17. How is backtracking used in Sudoku?

Try placing digits 1–9 in empty cells, checking validity. If a digit leads to an invalid state, backtrack and try another digit.

18. Can you give an example of a Sudoku solver in C?

#include <stdio.h>
#include <stdbool.h>

#define N 9

bool isSafe(int grid[N][N], int row, int col, int num) {
    for (int x = 0; x < N; x++) // Check row and column
        if (grid[row][x] == num || grid[x][col] == num) return false;
    int startRow = row - row % 3, startCol = col - col % 3;
    for (int i = 0; i < 3; i++) // Check 3x3 subgrid
        for (int j = 0; j < 3; j++)
            if (grid[i + startRow][j + startCol] == num) return false;
    return true;
}

bool findEmpty(int grid[N][N], int* row, int* col) {
    for (*row = 0; *row < N; (*row)++)
        for (*col = 0; *col < N; (*col)++)
            if (grid[*row][*col] == 0) return true;
    return false;
}

bool solveSudoku(int grid[N][N]) {
    int row, col;
    if (!findEmpty(grid, &row, &col)) return true; // No empty cell
    for (int num = 1; num <= 9; num++) {
        if (isSafe(grid, row, col, num)) {
            grid[row][col] = num; // Place number
            if (solveSudoku(grid)) return true;
            grid[row][col] = 0; // Backtrack
        }
    }
    return false;
}

void printGrid(int grid[N][N]) {
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < N; j++) printf("%d ", grid[i][j]);
        printf("\n");
    }
}

int main() {
    int grid[N][N] = {
        {5, 3, 0, 0, 7, 0, 0, 0, 0},
        {6, 0, 0, 1, 9, 5, 0, 0, 0},
        {0, 9, 8, 0, 0, 0, 0, 6, 0},
        {8, 0, 0, 0, 6, 0, 0, 0, 3},
        {4, 0, 0, 8, 0, 3, 0, 0, 1},
        {7, 0, 0, 0, 2, 0, 0, 0, 6},
        {0, 6, 0, 0, 0, 0, 2, 8, 0},
        {0, 0, 0, 4, 1, 9, 0, 0, 5},
        {0, 0, 0, 0, 8, 0, 0, 7, 9}
    };
    if (solveSudoku(grid)) printGrid(grid);
    else printf("No solution exists\n");
    return 0;
}
      

19. What is the time complexity of Sudoku solver?

Time Complexity: O(9^(m)) (m = number of empty cells), but pruning reduces practical runtime.

Space Complexity: O(n²) for the grid and O(n²) for recursion stack.

20. What is the Subsets problem?

The Subsets problem involves generating all possible subsets of a given set of elements (e.g., for {1, 2}, subsets are {}, {1}, {2}, {1, 2}).

21. How is backtracking used in Subsets?

For each element, choose to include or exclude it, recursively generating all combinations and backtracking to try the other option.

22. Can you give an example of Subsets in C?

#include <stdio.h>
#include <stdlib.h>

void printSubset(int subset[], int size) {
    printf("{ ");
    for (int i = 0; i < size; i++) printf("%d ", subset[i]);
    printf("}\n");
}

void subsetsUtil(int arr[], int n, int subset[], int index, int subsetSize) {
    printSubset(subset, subsetSize); // Print current subset
    for (int i = index; i < n; i++) {
        subset[subsetSize] = arr[i]; // Include element
        subsetsUtil(arr, n, subset, i + 1, subsetSize + 1);
        // Exclude element by not adding it (backtrack implicitly)
    }
}

void subsets(int arr[], int n) {
    int* subset = (int*)malloc(n * sizeof(int));
    subsetsUtil(arr, n, subset, 0, 0);
    free(subset);
}

int main() {
    int arr[] = {1, 2};
    int n = 2;
    subsets(arr, n); // Output: { }, { 1 }, { 2 }, { 1 2 }
    return 0;
}
      

23. What is the time complexity of Subsets?

Time Complexity: O(2^n) (generates all 2^n subsets).

Space Complexity: O(n) for recursion stack and subset array.

24. What is the Permutations problem?

The Permutations problem involves generating all possible orderings of a given set of elements (e.g., for {1, 2}, permutations are {1, 2}, {2, 1}).

25. How is backtracking used in Permutations?

Choose each element for the current position, swap it, recursively generate permutations for the remaining elements, and backtrack by undoing the swap.

26. Can you give an example of Permutations in C?

#include <stdio.h>
#include <stdlib.h>

void swap(int* a, int* b) {
    int temp = *a;
    *a = *b;
    *b = temp;
}

void printPermutation(int arr[], int n) {
    for (int i = 0; i < n; i++) printf("%d ", arr[i]);
    printf("\n");
}

void permute(int arr[], int start, int n) {
    if (start == n) {
        printPermutation(arr, n);
        return;
    }
    for (int i = start; i < n; i++) {
        swap(&arr[start], &arr[i]); // Choose element
        permute(arr, start + 1, n); // Recurse
        swap(&arr[start], &arr[i]); // Backtrack
    }
}

int main() {
    int arr[] = {1, 2, 3};
    int n = 3;
    permute(arr, 0, n); // Output: 1 2 3, 1 3 2, 2 1 3, 2 3 1, 3 2 1, 3 1 2
    return 0;
}
      

27. What is the time complexity of Permutations?

Time Complexity: O(n!) (generates all n! permutations).

Space Complexity: O(n) for recursion stack.