1、四种遍历概念

      (1)先序遍历:先访问根节点,再访问左子树,最后访问右子树。

          (2)  后序遍历:先左子树,再右子树,最后根节点。

        (3)中序遍历:先左子树,再根节点,最后右子树。

        (4)层序遍历:每一层从左到右访问每一个节点。

     每一个子树遍历时依然按照此时的遍历顺序。

如下图:

使用JavaScript/TypeScript实现树的先中后序遍历 树的先序中序后序遍历_入栈

    先序遍历:FCADBEHGM

    后序遍历:ABDCHMGEF

    中序遍历:ACBDFHEMG

    层序遍历:FCEADHGBM,层序遍历一般很少用。

2、实现

(1)递归实现,递归实现难理解但是很容易实现,先序遍历先操作根节点,之后递归先左后右。中序遍历先递归左子树,再操作根节点,再递归右子树。后序遍历先递归左子树再递归右子树之后再操作根节点。这样实现起来就很简单了。

//遍历实现先序
//根左右
void PreOrder(Tree T)
{
	if(T)
	{
		printf("%d",T->Element);//输出根节点,可以是其他操作
		PreOrder(T->Left);
		PreOrder(T->Right);
	}
}
//遍历实现中序
//左根右
void PreOrder(Tree T)
{
	if(T)
	{
		
		PreOrder(T->Left);
		printf("%d",T->Element);//输出根节点,可以是其他操作
		PreOrder(T->Right);
	}
}
//遍历实现后序
//左右根
void PreOrder(Tree T)
{
	if(T)
	{
		
		PreOrder(T->Left);
		
		PreOrder(T->Right);
		printf("%d",T->Element);//输出根节点,可以是其他操作
	}
}

(2)非递归实现,非递归实现比较麻烦但是好理解,麻烦的是需要用到栈。

       1、先序:首先把根节点压入栈中,此时根节点作为栈顶元素弹出访问。将当前节点的右子树和左子树分别入栈,考虑栈是先入后出因此必须先右子树先入栈,左子树后入栈。重复上述步骤直到栈为空。

       2、中序:中序遍历的非递归版本比前序稍微复杂一点,除了用到辅助栈之外,还需要一个指针 p 指向下一个待访问的节点。如果 p 非空,则将 p 入栈,p 指向 p 的左子树。如果 p 为空,说明此时左子树已经访问到尽头了,弹出当前栈顶元素,进行访问,并把 p 设置成 p 的右子树的左子树,即下一个待访问的节点。

        3、后序:采用一个辅助栈和两个指针 p 和 r,p 代表下一个需要访问的节点,r 代表上一次需要访问的节点。如果 p 非空,则将 p 入栈,p 指向 p 的左子树。如果 p 为空,代表左子树到了尽头,此时判断栈顶元素,如果栈顶元素存在右子树且没有被访问过 (等于 r 代表被访问过),则右子树入栈,p 指向右子树的左子树,如果栈顶元素不存在或者已经被访问过,则弹出栈顶元素,访问,然后 p 置为 null,r 记录上一次访问的节点 p。