[Graphical data structure] Binary tree traversal

[TOC]

pull it off

mark

Yesterday, when watching the live broadcast of "How to Make a Good Career Choice - Knowing Your Career Anchor" by Mr. Yan Jiawei of "Geek Time", Mr. Yan talked about some issues about choice . I think some of them are very interesting. Very good, sum up and share with you.

Why is it so hard for people to choose?

To choose means to give up

When you choose one, you give up on the other. The closer the options are in front of you, the more difficult your choice will be, because it is not easy to give up any of these options. If there are obvious choices in front of you, then it will be much easier to choose, and almost everyone will choose the "good" option without hesitation and give up the "bad" option.

Choices are never perfect

Choices can never be perfect, they can only satisfy as many focuses as possible. The more focus you want to satisfy when choosing, the more difficult it may be to make a choice. So don't be too chasing perfection in your choices.

Be wary of avoidance options —not knowing where you're going and choosing to leave.

One option is to be dissatisfied with the status quo and want to escape from it, but don't know where to go. For example, the current company may have various problems, such as irregular development process, etc. If you leave because of these problems, you may jump from one pit to another bigger pit. When you decide to leave, you must have clear goals and know exactly what you want.

Binary tree traversal principle

The traversal of a binary tree refers to starting from the root node and visiting all the nodes in the binary tree in a certain order, so that each node is visited once and only once.

Why study binary tree traversal?

Because computers can only deal with linear sequences, and when we study traversal, we turn the nodes in the tree into a linear sequence of some kind, which brings benefits to the implementation of the program.

Creation of a binary tree

Before traversing a binary tree, we must first have a binary tree. To create a binary tree as shown in the figure below, it is necessary to expand the binary tree first, that is, to lead the null pointer of each node of the binary tree to a virtual node whose value is a specific value, such as '#'. The processed binary tree is called the extended binary tree of the original binary tree. Each traversal sequence of the extended binary tree can determine a binary tree, and we use preorder traversal to create the binary tree. Preorder traversal sequence: 124##5##36##7##.

mark

mark

Define a binary linked list node:

/// <summary>
/// 二叉链表结点类
/// </summary>
/// <typeparam name="T"></typeparam>
public class TreeNode<T>
{
    /// <summary>
    /// 数据域
    /// </summary>
    public T Data { get; set; }
    /// <summary>
    /// 左孩子   
    /// </summary>
    public TreeNode<T> LChild { get; set; } 
    /// <summary>
    /// 右孩子
    /// </summary>
    public TreeNode<T> RChild { get; set; } 

    public TreeNode(T val, TreeNode<T> lp, TreeNode<T> rp)
    {
        Data = val;
        LChild = lp;
        RChild = rp;
    }

    public TreeNode(TreeNode<T> lp, TreeNode<T> rp)
    {
        Data = default(T);
        LChild = lp;
        RChild = rp;
    }

    public TreeNode(T val)
    {
        Data = val;
        LChild = null;
        RChild = null;
    }

    public TreeNode()
    {
        Data = default(T);
        LChild = null;
        RChild = null;
    }
}

Preorder recursively create a binary tree:

/// <summary>
/// 先序创建二叉树
/// </summary>
/// <param name="node"></param>
public static void CreateTree(TreeNode<char> node)
{
    node.Data = Console.ReadKey().KeyChar;

    if (node.Data == '#')
    {
        return;
    }

    node.LChild = new TreeNode<char>();

    CreateTree(node.LChild);

    if (node.LChild.Data == '#')
    {
        node.LChild = null;
    }

    node.RChild = new TreeNode<char>();

    CreateTree(node.RChild);

    if (node.RChild.Data == '#')
    {
        node.RChild = null;
    }
}

Binary tree traversal method

mark

mark

preorder traversal

mark

Preorder traversal recursively

Specific process:

  1. Visit the root node first
  2. Reorder traversal of left subtree
  3. Last-order traversal of the right subtree

Code:

public static void PreOrderRecur(TreeNode<char> treeNode)
 {
     if (treeNode == null)
     {
         return;
     }
     Console.Write(treeNode.Data); 
     PreOrderRecur(treeNode.LChild);
     PreOrderRecur(treeNode.RChild);
 }

Preorder traversal in a non-recursive way

Specific process:

  1. First apply for a new stack, denoted as stack;
  2. Push the head node head into the stack;
  3. Each time the top node of the stack is popped from the stack, it is recorded as cur, and then the value of cur is printed. If the right child of cur is not empty, the right child is pushed into the stack; if the left child of cur is not empty, it is pushed into the stack middle;
  4. Repeat step 3 until stack is empty.

Code:

 public static void PreOrder(TreeNode<char> head)
{
    if (head == null)
    {
        return;
    }
    Stack<TreeNode<char>> stack = new Stack<TreeNode<char>>();
    stack.Push(head);
    while (!(stack.Count == 0))
    {
        TreeNode<char> cur = stack.Pop();
        Console.Write(cur.Data);

        if (cur.RChild != null)
        {
            stack.Push(cur.RChild);
        }
        if (cur.LChild != null)
        {
            stack.Push(cur.LChild);
        }
    }
}

Process simulation:

Results of the:mark

Inorder traversal

mark

In-order traversal recursively

Specific process:

  1. Traverse the left subtree in inorder first
  2. Revisit the root node
  3. Last inorder traversal of the right subtree

Code:

public static void InOrderRecur(TreeNode<char> treeNode)
{
    if (treeNode == null)
    {
        return;
    }  
    InOrderRecur(treeNode.LChild);
    Console.Write(treeNode.Data); 
    InOrderRecur(treeNode.RChild);
}

Non-recursive way to achieve in-order traversal

Specific process:

  1. Apply for a new stack, record it as stack, apply for a variable cur, and initially set cur as the head node;
  2. First push the cur node into the stack. For the entire subtree headed by the cur node, push the left subtree of the entire tree into the stack in turn, that is, keep cur=cur.left, and then repeat step 2;
  3. Repeat step 2 until it is found that cur is empty. At this time, a node is popped up from the stack and recorded as node, the value of node is printed, and cur = node.right, and then continue to repeat step 2;
  4. Ends when stack is empty and cur is empty.

Code:

public static void InOrder(TreeNode<char> treeNode)
{
    if (treeNode == null)
    {
        return;
    }
    Stack<TreeNode<char>> stack = new Stack<TreeNode<char>>();

    TreeNode<char> cur = treeNode;

    while (!(stack.Count == 0) || cur != null)
    {
        while (cur != null)
        {
            stack.Push(cur);
            cur = cur.LChild;
        }
        TreeNode<char> node = stack.Pop();
        Console.WriteLine(node.Data);
        cur = node.RChild;
    }
}

Process simulation:

Results of the:mark

post-order traversal

mark

Post-order traversal recursively

  1. Traverse the left subtree in order
  2. Then traverse the right subtree in post-order
  3. Last visit to the root node

Code:

public static void PosOrderRecur(TreeNode<char> treeNode)
{
    if (treeNode == null)
    {
        return;
    }
    PosOrderRecur(treeNode.LChild);
    PosOrderRecur(treeNode.RChild);
    Console.Write(treeNode.Data); 
}

Post-order traversal in a non-recursive way

Specific process:

Implemented using two stacks

  1. Apply for two stacks stack1, stack2, and then push the head node into stack1;
  2. The node popped from stack1 is recorded as cur, and then the left child of cur is pushed into stack1, and then the right child of cur is pushed into stack1;
  3. During the whole process, every node popped from stack1 is placed in the second stack stack2;
  4. Repeat steps 2 and 3 until stack1 is empty and the process stops;
  5. Pop up nodes from stack2 and print them in sequence, and the order of printing is the order of post-order traversal;

Code:

public static void PosOrderOne(TreeNode<char> treeNode)
{
    if (treeNode == null)
    {
        return;
    }

    Stack<TreeNode<char>> stack1 = new Stack<TreeNode<char>>();
    Stack<TreeNode<char>> stack2 = new Stack<TreeNode<char>>();

    stack1.Push(treeNode);
    TreeNode<char> cur = treeNode;

    while (!(stack1.Count == 0))
    {
        cur = stack1.Pop();
        if (cur.LChild != null)
        {
            stack1.Push(cur.LChild);
        }
        if (cur.RChild != null)
        {
            stack1.Push(cur.RChild);
        }
        stack2.Push(cur);
    }

    while (!(stack2.Count == 0))
    {
        TreeNode<char> node = stack2.Pop();
        Console.WriteLine(node.Data); ;
    }
}

Process simulation:

Results of the:mark

Non-recursive way to achieve post-order traversal 2

Specific process:

Implemented using a stack

  1. Apply for a stack, push the head node into the stack, and set two variables h and c at the same time. In the whole process, h represents the node that was popped up and printed most recently, and c represents the top node of the current stack. Initially, h is the head node, c is null;

  2. Each time c is equal to the top node of the current stack, but the node is not popped from the stack, there are three cases at this time:

(1) If the left child of c is not empty, and h is not equal to the left child of c, nor is it equal to the right child of c, then push the left child of c into the stack

(2) If case 1 does not hold, and the right child of c is not empty, and h is not equal to the right child of c, push the right child of c into the stack;

(3) If cases 1 and 2 do not hold, pop c from the stack and print, and then set h equal to c;

  1. Repeat step 2 until stack is empty.

Code:

public static void PosOrderTwo(TreeNode<char> treeNode)
{
    if (treeNode == null)
    {
        return;
    }

    Stack<TreeNode<char>> stack = new Stack<TreeNode<char>>();
    stack.Push(treeNode);

    TreeNode<char> h = treeNode;
    TreeNode<char> c = null;
    while (!(stack.Count == 0))
    {
        c = stack.Peek();
        //c结点有左孩子 并且 左孩子没被遍历(输出)过 并且 右孩子没被遍历过
        if (c.LChild != null && h != c.LChild && h != c.RChild)
            stack.Push(c.LChild);
        //c结点有右孩子 并且 右孩子没被遍历(输出)过
        else if (c.RChild != null && h != c.RChild)
            stack.Push(c.RChild);
        //c结点没有孩子结点 或者孩子结点已经被遍历(输出)过
        else
        {
            TreeNode<char> node = stack.Pop();
            Console.WriteLine(node.Data);
            h = c;
        }
    }
}

Process simulation:

Results of the:mark

level-order traversal

mark

Specific process:

  1. First apply for a new queue, recorded as queue;
  2. Push the head node head into the queue;
  3. Each time it is dequeued from the queue, it is recorded as node, and then the node value is printed. If the left child of node is not empty, the left child is added to the queue; if the right child of node is not empty, the right child is added to the queue;
  4. Repeat step 3 until the queue is empty.

Code:

public static void LevelOrder(TreeNode<char> treeNode)
{
    if(treeNode == null)
    {
         return;
    }
    Queue<TreeNode<char>> queue = new Queue<TreeNode<char>>();
    queue.Enqueue(treeNode);

    while (queue.Any())
    {
        TreeNode<char> node = queue.Dequeue();
        Console.Write(node.Data);

        if (node.Left != null)
        {
            queue.Enqueue(node.Left);
        }

        if (node.Right != null)
        {
            queue.Enqueue(node.Right);
        }
    }
}

Results of the:mark

Reference: "Dahua Data Structure"





Disclaimer: This article is a summary of bloggers' learning and perceptions. The level is limited. If it is inappropriate, please correct me. If you think it is not bad, you may click the [ Recommended ] button below, thank you for your support. Please indicate the source when reprinting and citing.


Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325048867&siteId=291194637