在二叉树中进行层次遍历

层次遍历是一种横向遍历二叉树的方法之一。在本文中,我们将讨论如何在C/C++中实现这个算法。

但在此之前,让我们先梳理一下我们的概念。


构建概念

二叉树是一种数据结构,每个节点最多有两个子节点。最上方的节点被称为根节点。

Binary Tree

遍历二叉树的常见方式有四种,分别是:

  • In order Traversal
  • Pre Order Traversal
  • Post Order Traversal
  • Level Order Traversal

让我们来了解二叉树中的层级意味着什么。

一个级别是树中与给定节点对应的父节点的数量。基本上就是从该节点到根节点的祖先数量。

所以,对于根节点(最顶层节点)而言,它的层级是0,因为它没有父节点。如果它有子节点,那么它们的层级都会是1,因为在根节点之前它们只有一个祖先,即根节点本身。

Binary Tree Level

我们还需要理解二叉树中的高度概念。这其实就是从根节点到树中最深节点的路径长度。

在这种情况下,高度将是从最深叶节点(40或50,因为它们具有最大层级)到根的长度。因此,树的高度为2。

现在我们已经掌握了概念,让我们来了解如何实施层序遍历。


层次遍历

层次遍历是一种总是根据树的层级进行遍历的方法。

所以,这个遍历首先遍历与Level 0相对应的节点,然后是Level 1,依此类推,从根节点开始。

在上面的二叉树例子中,层序遍历的顺序将会是:

(起始值)10 – > 20 -> 30 -> 40 -> 50

为了做到这一点,我们需要做两件事情。

    我们首先必须找出这棵树的高度。
    我们需要找到一种方法来打印每个层级对应的节点。

找到树的高度

首先我们会找到树的高度。要做到这一点,逻辑很简单。

由于树的高度被定义为从根节点到叶子节点的最长路径,因此我们可以递归地计算左右子树的高度,并找到子树中的最大高度。树的高度将简单地等于子树的高度加1。

C-风格的伪代码:

// Find height of a tree, defined by the root node
int tree_height(Node* root) {
    if (root == NULL) 
        return 0;
    else {
        // Find the height of left, right subtrees
        left_height = tree_height(root->left);
        right_height = tree_height(root->right);
        
        // Find max(subtree_height) + 1 to get the height of the tree
        return max(left_height, right_height) + 1;
}

打印每一级的所有节点。

现在我们已经有了树的高度,我们需要为每个层级打印节点。为了做到这一点,我们将使用一个for循环来迭代所有层级直到树的高度,并打印每个层级的节点。

void print_tree_level_order(Node* root) {
    int height = tree_height(root);
    for (int i=0; i<height; i++) {
        // Print the ith level
        print_level(root, i);
    }
}

观察到我们需要另一个函数来打印树的第i层。

再次,我们有一个类似的逻辑。但这次,在打印根节点后,我们将根节点更改为其左子节点和右子节点,并打印两个子树。

直到我们到达叶子节点,也就是辅助根节点在下一步将为NULL的时候,这将会继续进行。(因为叶子节点的左指向NULL且右指向NULL)

void print_level(Node* root, int level_no) {
    // Prints the nodes in the tree
    // having a level = level_no
    
    // We have a auxiliary root node
    // for printing the root of every
    // sub-tree
    if (!root)
        return;
    if (level_no == 0) {
        // We are at the top of a sub-tree
        // So print the auxiliary root node
        printf("%d -> ", root->value);
    }
    else {
        // Make the auxiliary root node to
        // be the left and right nodes for
        // the sub-trees and decrease level by 1, since
        // you are moving from top to bottom
        print_level(root->left, level_no - 1);
        print_level(root->right, level_no - 1);
    }

}

现在,我们终于完成了层序遍历!

我将在下面提供完整的程序,其中还包含使用插入方法构建二叉树的部分。


完整的 C/C++ 代码

尽管这原本是一段C程序,但同样可以在C++上编译。

/**
    Code for https://journaldev.com
    File Name: level_order.c
    Purpose: Find the Level Order Traversal of a Binary Tree

    @author Vijay Ramachandran
    @date 28/01/2020
*/

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

typedef struct Node Node;

// Define the Tree Node here
struct Node {
    int value;
    // Pointers to the left and right children
    Node* left, *right;
};


Node* init_tree(int data) {
    // Creates the tree and returns the
    // root node
    Node* root = (Node*) malloc (sizeof(Node));
    root->left = root->right = NULL;
    root->value = data;
    return root;
}

Node* create_node(int data) {
    // Creates a new node
    Node* node = (Node*) malloc (sizeof(Node));
    node->value = data;
    node->left = node->right = NULL;
    return node;
}

void free_tree(Node* root) {
    // Deallocates memory corresponding
    // to every node in the tree.
    Node* temp = root;
    if (!temp)
        return;
    free_tree(temp->left);
    free_tree(temp->right);
    if (!temp->left && !temp->right) {
        free(temp);
        return;
    }
}

int tree_height(Node* root) {
    // Get the height of the tree
    if (!root)
        return 0;
    else {
        // Find the height of both subtrees
        // and use the larger one
        int left_height = tree_height(root->left);
        int right_height = tree_height(root->right);
        if (left_height >= right_height)
            return left_height + 1;
        else
            return right_height + 1;
    }
}

void print_level(Node* root, int level_no) {
    // Prints the nodes in the tree
    // having a level = level_no
    
    // We have a auxiliary root node
    // for printing the root of every
    // subtree
    if (!root)
        return;
    if (level_no == 0) {
        // We are at the top of a subtree
        // So print the auxiliary root node
        printf("%d -> ", root->value);
    }
    else {
        // Make the auxiliary root node to
        // be the left and right nodes for
        // the subtrees and decrease level by 1, since
        // you are moving from top to bottom
        print_level(root->left, level_no - 1);
        print_level(root->right, level_no - 1);
    }

}

void print_tree_level_order(Node* root) {
    if (!root)
        return;
    int height = tree_height(root);
    for (int i=0; i<height; i++) {
        printf("Level %d: ", i);
        print_level(root, i);
        printf("\n");
    }
    printf("\n\n-----Complete Level Order Traversal:-----\n");
    for (int i=0; i<height; i++) {
        print_level(root, i);
    }
    printf("\n");
}

int main() {
    // Program to demonstrate Level Order Traversal

    // Create the root node having a value of 10
    Node* root = init_tree(10);
    
    // Insert nodes onto the tree
    root->left = create_node(20);
    root->right = create_node(30);
    root->left->left = create_node(40);
    root->left->right = create_node(50);
    
    // Level Order Traversal
    print_tree_level_order(root);

    // Free the tree!
    free_tree(root);
    return 0;
}

输出

Level 0: 10 -> 
Level 1: 20 -> 30 -> 
Level 2: 40 -> 50 -> 


-----Complete Level Order Traversal:-----
10 -> 20 -> 30 -> 40 -> 50 -> 

您还可以通过我为此目的创建的Github gist下载它。(还包含插入代码的部分)


结论

希望你对如何在C/C++中实现层序遍历有了更好的理解。如果你有任何问题,请在下面的评论区随时提问!