Recursive and non-recursive algorithms implement pre-, middle-, and post-order traversal of binary trees

introduction

The binary tree is a very important data structure, and many other data structures are evolved based on the binary tree. For binary trees, there are depth traversal and breadth traversal. Depth traversal has three traversal methods: preorder, inorder and postorder. Breadth traversal is what we usually call hierarchical traversal. Because the definition of the tree itself is a recursive definition, it is not only easy to understand and the code is very simple to implement the three traversals of the tree using the recursive method, but for the breadth traversal, it needs the support of other data structures, such as heaps.

Here we mainly introduce three traversal methods of binary trees: pre-order, in-order, and post-order, among which in-order traversal is the most important.

The main idea of ​​traversal:
Preorder traversal: root node -> left subtree -> right subtree

Inorder traversal: left subtree -> root node -> right subtree

Post-order traversal: left subtree —> right subtree —> root node

Take the following figure as an example:
insert image description hereA: root node, B: left node, C: right node, the preorder order is ABC; the inorder order is BAC; the postorder order is BCA

Look at a more complex tree:
insert image description here
pre-order traversal: ABCDEFGHK; middle-order traversal: BDCAEHGKF; post-order traversal: DCBHKGFEA

The recursive method realizes the front, middle and back order traversal

Let's first define the structure of a binary tree:

typedef struct BinaryTreeNode
{
    
    
    TelemType data;
    struct BinaryTreeNode *Left;
    struct BinaryTreeNode *Right;
}Node;

Create a binary tree in the order root node -> left subtree -> right subtree:

Node* createBinaryTree()
{
    
    
    Node *p;
    TelemType ch;
    cin>>ch;
    if(ch == 0)     //如果到了叶子节点,接下来的左、右子树分别赋值为0
    {
    
    
        p = NULL;
    }
    else
    {
    
    
        p = (Node*)malloc(sizeof(Node));
        p->data = ch;
        p->Left  = createBinaryTree();  //递归创建左子树
        p->Right = createBinaryTree();  //递归创建右子树
    }
    return p;
}

Preorder traversal:

void preOrderTraverse(Node* root)
{
    
    
    if( root )
    {
    
    
        cout<<root->data<<' ';
        preOrderTraverse(root->Left);
        preOrderTraverse(root->Right);
    }
}

Inorder traversal:

void inOrderTraverse(Node* root)
{
    
    
    if( root )
    {
    
    
        inOrderTraverse(root->Left);
        cout<<root->data<<' ';
        inOrderTraverse(root->Right);
    }
}

Postorder traversal:

void lastOrderTraverse(Node* root)
{
    
    
    if( root )
    {
    
    
        lastOrderTraverse(root->Left);
        lastOrderTraverse(root->Right);
        cout<<root->data<<' ';
    }
}

The following is the total number of nodes, depth, and number of leaf nodes of the binary tree

//二叉树节点总数目
int Nodenum(Node* root)
{
    
    
    if(root == NULL)
    {
    
    
        return 0;
    }
    else
    {
    
    
        return 1+Nodenum(root->Left)+Nodenum(root->Right);
 
    }
}
 
//二叉树的深度
int DepthOfTree(Node* root)
{
    
    
    if(root)
    {
    
    
        return DepthOfTree(root->Left)>DepthOfTree(root->Right)?DepthOfTree(root->Left)+1:DepthOfTree(root->Right)+1;
    }
    if( root == NULL )
    {
    
    
        return 0;
    }
}
 
//二叉树叶子节点数
int Leafnum(Node* root)
{
    
    
    if(!root)
    {
    
    
        return 0;
    }
    else if(  (root->Left == NULL) && (root->Right == NULL) )
    {
    
    
        return 1;
    }
    else
    {
    
    
        return  (Leafnum(root->Left) + Leafnum(root->Right)) ;
    }
}

Full code:

#include <iostream>
#include<cstdio>
#include<cstdlib>
 
using namespace std;
 
typedef int TelemType;
 
typedef struct BinaryTreeNode
{
    
    
    TelemType data;
    struct BinaryTreeNode *Left;
    struct BinaryTreeNode *Right;
}Node;
 
 
//创建二叉树,顺序依次为中间节点->左子树->右子树
Node* createBinaryTree()
{
    
    
    Node *p;
    TelemType ch;
    cin>>ch;
    if(ch == 0)     //如果到了叶子节点,接下来的左、右子树分别赋值为0
    {
    
    
        p = NULL;
    }
    else
    {
    
    
        p = (Node*)malloc(sizeof(Node));
        p->data = ch;
        p->Left  = createBinaryTree();  //递归创建左子树
        p->Right = createBinaryTree();  //递归创建右子树
    }
    return p;
}
 
//先序遍历
void preOrderTraverse(Node* root)
{
    
    
    if( root )
    {
    
    
        cout<<root->data<<' ';
        preOrderTraverse(root->Left);
        preOrderTraverse(root->Right);
    }
}
 
//中序遍历
void inOrderTraverse(Node* root)
{
    
    
    if( root )
    {
    
    
        inOrderTraverse(root->Left);
        cout<<root->data<<' ';
        inOrderTraverse(root->Right);
    }
}
 
//后序遍历
void lastOrderTraverse(Node* root)
{
    
    
    if( root )
    {
    
    
        lastOrderTraverse(root->Left);
        lastOrderTraverse(root->Right);
        cout<<root->data<<' ';
    }
}
 
//二叉树节点总数目
int Nodenum(Node* root)
{
    
    
    if(root == NULL)
    {
    
    
        return 0;
    }
    else
    {
    
    
        return 1+Nodenum(root->Left)+Nodenum(root->Right);
 
    }
}
 
//二叉树的深度
int DepthOfTree(Node* root)
{
    
    
    if(root)
    {
    
    
        return DepthOfTree(root->Left)>DepthOfTree(root->Right)?DepthOfTree(root->Left)+1:DepthOfTree(root->Right)+1;
    }
    if( root == NULL )
    {
    
    
        return 0;
    }
}
 
//二叉树叶子节点数
int Leafnum(Node* root)
{
    
    
    if(!root)
    {
    
    
        return 0;
    }
    else if(  (root->Left == NULL) && (root->Right == NULL) )
    {
    
    
        return 1;
    }
    else
    {
    
    
        return  (Leafnum(root->Left) + Leafnum(root->Right)) ;
    }
}
 
 
int main()
{
    
    
    Node *root = NULL;
    root = createBinaryTree();
    printf("二叉树建立成功");
    cout<<endl;
 
    cout<<"二叉树总节点数为:"<<Nodenum(root)<<endl;
 
    cout<<"二叉树深度为:"<<DepthOfTree(root)<<endl;
 
    cout<<"二叉树叶子节点数为:"<<Leafnum(root)<<endl;
 
    cout<<"前序遍历结果:"<<endl;
    preOrderTraverse(root);
    cout<<endl;
 
    cout<<"中序遍历结果:"<<endl;
    inOrderTraverse(root);
    cout<<endl;
 
    cout<<"后序遍历结果:"<<endl;
    lastOrderTraverse(root);
    cout<<endl;
 
    return 0;
}

non-recursive to achieve

The main idea of ​​non-recursive traversal is to solve the problem of traversing binary trees through data structures such as loops and stacks.
Define the structure of the binary tree:

struct TreeNode {
    
    
    TreeNode(int val_) :val(val_), left(NULL), right(NULL) {
    
    }
    TreeNode* left;
    TreeNode* right;
    int val;
};

Pre-order traversal:
first visit the root node, and then visit the left and right child nodes respectively; non-recursive pre-order traversal uses a stack to simulate the traversal process:

  1. First put the root node on the stack
  2. Start the loop, visit the root node, and pop the root node out of the stack
  3. The left child node of the root node is pushed into the stack, and the right child node is pushed into the stack at the end, completing a cycle
  4. Next, the processing of the previous 3 steps is performed in a loop until the stack is empty, then the traversal is completed.
void PreOrderNonRecursive(TreeNode* root) {
    
    
    stack<TreeNode*> sta;
    if (root == NULL)
        return;
    sta.push(root);
    while (!sta.empty()) {
    
    
        TreeNode* pNode = sta.top();
        cout << pNode->val << endl;
        sta.pop();
        if (pNode->right != NULL)
            sta.push(pNode->right);
        if (pNode->left != NULL)
            sta.push(pNode->left);
    }
}

In-order traversal:
first visit the left child node, then visit the root node, and finally visit the right child node; also use the stack to traverse:

  1. Since the left child node is visited first, the leftmost node needs to be visited first, and the root node is first pushed into the stack, and an intermediate variable is used to record each node pushed into the stack, so as to determine whether it has a left child node
  2. If the node pushed in the middle has a left child node, then continue to push its left child node until there are no more left child nodes
  3. The top element of the stack is popped out, that is, the root node is accessed
  4. Determine whether the top element of the stack has a right child node, if so, push its right child node into the stack
  5. Cycle through steps 2-4 until the stack is empty and complete the traversal
void InOrderNonRecursive(TreeNode* root) {
    
    
    stack<TreeNode*> sta;
    if (root == NULL)
        return;
    sta.push(root);
    TreeNode* pNode = root;
    while (!sta.empty()) {
    
    
        while (pNode != NULL&&pNode->left != NULL) {
    
    
            pNode = pNode->left;
            sta.push(pNode);
        }
        pNode = sta.top();
        cout << pNode->val << endl;
        sta.pop();
        if (pNode->right != NULL) {
    
    
            sta.push(pNode->right);
            pNode = pNode->right;
        }
        else
            pNode = NULL;
    }
}

Post-order traversal:
First traverse the left and right child nodes, and finally traverse the root node. Non-recursive post-order traversal is the most complicated of the three traversal methods.The most important thing is: judge whether the left and right child nodes of each node are NULL, or whether its left and right child nodes have been visited, and if so, then visit the node.

  1. Boundary condition check, stack root node
  2. Record the current stack top element, if the left and right child nodes of the stack top element are NULL or have been visited, then visit the current node
  3. Otherwise, push its right child node and left child node into the stack in turn
  4. Loop step 2 and step 3 until the stack is empty
void PostOrderNonRecursive(TreeNode* root) {
    
    
    if (root == NULL)
        return;
    stack<TreeNode*> sta;
    TreeNode* curNode = root;
    TreeNode* preNode = NULL;
    sta.push(root);
    while (!sta.empty()) {
    
    
        curNode = sta.top();
        if ((curNode->left == NULL&&curNode->right == NULL) || 
            (preNode != NULL && (preNode == curNode->left || preNode == curNode->right))) {
    
    
            cout << curNode->val << endl;
            sta.pop();
            preNode = curNode;
        }
        else {
    
    
            if (curNode->right != NULL)
                sta.push(curNode->right);
            if (curNode->left != NULL)
                sta.push(curNode->left);
        }
    }
}

Guess you like

Origin blog.csdn.net/Chenjiahui_LYee/article/details/103089113