Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Basic Binary Tree Operations in C

Tech 1

To implement binary tree operations in C, a queue is used for level - order traversal and checking if a tree is a complete binary tree (unlike C++ which may not need an external queue structure for some operations). Here are the core operations:

Constructing a Binary Tree Node

The CreateBinaryTree function builds a binary tree from a string (where # represents a null node) using recursion to create left and right sub - trees.

BinTreeNode* CreateBinaryTree(char* dataStr, int* index) {
    if (dataStr[*index] == '#') {
        (*index)++;
        return NULL;
    }
    BinTreeNode* node = (BinTreeNode*)malloc(sizeof(BinTreeNode));
    if (!node) {
        perror("Memory allocation failed");
        exit(EXIT_FAILURE);
    }
    node->data = dataStr[(*index)++];
    node->left = CreateBinaryTree(dataStr, index);
    node->right = CreateBinaryTree(dataStr, index);
    return node;
}

Destroying the Binary Tree

The DestroyBinaryTree function recursive frees all nodes by first destroying the left and right sub - trees and then the current node.

void DestroyBinaryTree(BinTreeNode** rootRef) {
    if (!rootRef) return;
    DestroyBinaryTree(&((*rootRef)->left));
    DestroyBinaryTree(&((*rootRef)->right));
    free(*rootRef);
    *rootRef = NULL;
}

Counting Nodes in the Binary Tree

The GetBinaryTreeSize function calculates the total number of nodes. For a null tree, it returns 0; otherwise, it sums the nodes in the left and right sub - trees and adds 1 for the current node.

int GetBinaryTreeSize(BinTreeNode* root) {
    return root ? (GetBinaryTreeSize(root->left) + GetBinaryTreeSize(root->right) + 1) : 0;
}

Counting Leaf Nodes

A leaf node has no left or right children. The GetLeafNodeCount function uses recursion to count such nodes.

int GetLeafNodeCount(BinTreeNode* root) {
    if (!root) return 0;
    if (!root->left && !root->right) return 1;
    return GetLeafNodeCount(root->left) + GetLeafNodeCount(root->right);
}

Counting Nodes at Level k

The GetLevelKNodeCount function counts the number of nodes at a specific level k. For level 1, it returns 1 (the root). For other levels, it sums the nodes in the left and right sub - trees at level k - 1.

int GetLevelKNodeCount(BinTreeNode* root, int k) {
    if (!root) return 0;
    if (k == 1) return 1;
    return GetLevelKNodeCount(root->left, k - 1) + GetLevelKNodeCount(root->right, k - 1);
}

Finding a Node with Value x

The FindNode functon searches for a node with a given value. It first checks the current node, then recursively searches the left and right sub - trees.

BinTreeNode* FindNode(BinTreeNode* root, char target) {
    if (!root) return NULL;
    if (root->data == target) return root;
    BinTreeNode* leftResult = FindNode(root->left, target);
    if (leftResult) return leftResult;
    return FindNode(root->right, target);
}

Pre - order Traversal

Pre - order traversal visits the root first, then the left sub - tree, and finally the right sub - tree.

void PreorderTraversal(BinTreeNode* node) {
    if (!node) return;
    printf("%c ", node->data);
    PreorderTraversal(node->left);
    PreorderTraversal(node->right);
}

In - order Traversal

In - order traversal visits the left sub - tree first, then the root, and then the right sub - tree.

void InorderTraversal(BinTreeNode* node) {
    if (!node) return;
    InorderTraversal(node->left);
    printf("%c ", node->data);
    InorderTraversal(node->right);
}

Post - order Traversal

Post - order traversal visits the left sub - tree first, then the right sub - tree, and finally the root.

void PostorderTraversal(BinTreeNode* node) {
    if (!node) return;
    PostorderTraversal(node->left);
    PostorderTraversal(node->right);
    printf("%c ", node->data);
}

Level - order Traversal

Level - order traversal visits nodes level by level. It uses a queue to enqueue nodes and process them in a first - in - first - out way.

void LevelorderTraversal(BinTreeNode* root) {
    Queue q;
    QueueInitialize(&q);
    if (root) {
        QueueEnqueue(&q, root);
    }
    while (!QueueIsEmpty(&q)) {
        BinTreeNode* front = QueueFront(&q);
        printf("%c ", front->data);
        QueueDequeue(&q);
        if (front->left) QueueEnqueue(&q, front->left);
        if (front->right) QueueEnqueue(&q, front->right);
    }
    QueueDestroy(&q);
}

Check if Binary Tree is Complete

A complete binary tree has all levels filled except possibly the last, and nodes are filled from left to right. The IsCompleteBinaryTree function uses a queue to check this.

int IsCompleteBinaryTree(BinTreeNode* root) {
    Queue q;
    QueueInitialize(&q);
    if (root) QueueEnqueue(&q, root);
    int endFlag = 0;
    while (!QueueIsEmpty(&q)) {
        BinTreeNode* front = QueueFront(&q);
        QueueDequeue(&q);
        if (!front) {
            endFlag = 1;
        } else {
            if (endFlag) return 0;
            QueueEnqueue(&q, front->left);
            QueueEnqueue(&q, front->right);
        }
    }
    QueueDestroy(&q);
    return 1;
}

Height of the Binary Tree

The height of a tree is the number of nodes along the longest path from the root to a leaf. The GetTreeHeight function recursively calculates the height of the left and right sub - trees and returns the maximum of the two plus 1.

int GetTreeHeight(BinTreeNode* root) {
    if (!root) return 0;
    int leftH = GetTreeHeight(root->left);
    int rightH = GetTreeHeight(root->right);
    return (leftH > rightH? leftH : rightH) + 1;
}

Source Code Structure

The code is split into three files:

  • binary_tree.h: Defines the binary tree node structure, function prototypes, and queue structure.
  • binary_tree.c: Implements the binary tree operations.
  • queue.c: Implements the queue operations (used for level - order traversal and complete tree check).
  • test.c: Tests the binary tree operations with a sample enput.

Sample Input/Output

For the input string 123###45##6## (representing a specific binary tree):

  • Leaf Node Count: 3
  • Total Nodes: 6
  • Nodes at Level 2: 2
  • Pre - order Traversal: 1 2 3 4 5 6 (actual output depends on the tree structure)
  • In - order Traversal: 3 2 1 5 4 6 (actual output depends on the tree structure)
  • Post - order Traversal: 3 2 5 6 4 1 (actual output depends on the tree structure)
  • Level - order Traversal: 1 2 4 3 5 6 (actual output depends on the tree structure)
  • Is Complete: 1
  • Tree Height: 3

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.