树的遍历总结

写在前面

本文是根据2篇参考文献整合的,后续有关于树的更好的思路会持续更新

树的定义

// lombok 标签 @Data
@Data
public class TreeNode
{ 
    public T Data;
    public TreeNode LChild;     
    public TreeNode RChild;
}

前序遍历

前序递归

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

前序非递归

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

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

中序遍历

中序递归

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

中序非递归

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

    TreeNode cur = treeNode;

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

后序遍历

后序递归

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

后序非递归

双栈法

class Solution {
    public List postorderTraversal(TreeNode root) {
         List result = new LinkedList<>();
         if (root == null) return result;
 
         Stack toVisit = new Stack<>();
         Stack reversedStack = new Stack<>();
         toVisit.push(root);
         TreeNode cur;
 
         while (!toVisit.isEmpty()) {
             cur = toVisit.pop();
              reversedStack.push(cur);  // result.add(cur.val);
             if (cur.left != null) toVisit.push(cur.left); // 左节点入栈
             if (cur.right != null) toVisit.push(cur.right); // 右节点入栈
         }
 
          while (!reversedStack.isEmpty()) {
              cur = reversedStack.pop();
              result.add(cur.val);
          }
         return result;
      }
}

单Stack

申请一个栈stack,将头节点压入stack,同时设置两个变量 h 和 c,在整个流程中,h代表最近一次弹出并打印的节点,c代表当前stack的栈顶节点,初始时令h为头节点,,c为null;
每次令c等于当前stack的栈顶节点,但是不从stack中弹出节点,此时分一下三种情况:
(1)如果c的左孩子不为空,并且h不等于c的左孩子,也不等于c的右孩子,则吧c的左孩子压入stack中
(2)如果情况1不成立,并且c的右孩子不为空,并且h不等于c的右孩子,则把c的右孩子压入stack中;
(3)如果情况1和2不成立,则从stack中弹出c并打印,然后令h等于c;
一直重复步骤2,直到stack为空.

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

    Stack> stack = new Stack>();
    stack.Push(treeNode);
    TreeNode h = treeNode;
    TreeNode 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 node = stack.Pop();
            Console.WriteLine(node.Data);
            h = c;
        }
    }
}

层次遍历

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

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

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

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

参考文献

文献1
文献2

你可能感兴趣的:(树的遍历总结)