二叉树遍历与构造

二叉树的遍历

  二叉树遍历其实很简单,三种遍历都是一样的,只不过顺序先后不一样罢了。

先序遍历

  访问根结点,先序遍历左子树,先序遍历右子树

void PreOrder(BitTree T){
    if( T != nullptr){
        visit(T);
        PreOrder(T->lchild);
        PreOrder(T->rchild);
    }
}

中序遍历

  中序遍历左子树,访问根结点,中序遍历右子树

void InOrder(BitTree T){
    if(T != nullptr){
        InOrder(T->lchild);
        visit(T);
        InOrder(T->rchild);
    }
}

后序遍历

后序遍历左子树,后序遍历右子树,访问根结点

  时间复杂度都为O(n),在递归遍历中,递归工作栈的栈深恰好为树的深度,在最坏情况下,二叉树是有n个结点且深度为 n 的单支树,遍历算法的空间复杂度为O(n)。

利用非递归方式遍历二叉树

  借助栈,可以将二叉树的递归遍历转换为非递归算法。以中序遍历为例,给出中序遍历非递归算法。先扫描(并非访问)根结点的所有左结点并将它们一一进栈,然后出栈一个结点*p,访问它。然后继续扫描该结点的右孩子结点,将其进栈,在扫描该孩子结点的所有左结点并一一进栈,如此继续,直到栈空。

  中序遍历的非递归算法如下:

  前序遍历的非递归算法:

  后序遍历的非递归算法:后序遍历的难点在于:需要判断上次访问的节点是位于左子树,还是右子树。若是位于左子树,则需跳过根节点,先进入右子树,再回头访问根节点;若是位于右子树,则直接访问根节点。直接看代码,代码中有详细的注释。

  层次遍历

  层次遍历需要借助队列。先将二叉树根结点入队,然后初岁,访问该结点,若它有左子树,则将左子树根节点入队;若它有右子树,则将右子树根结点入队。然后出队,对出队结点访问,如此反复,直到队列为空。

由遍历序列构造二叉树

  由二叉树的先序和中序序列可以唯一确定一棵二叉树,同样后序和中序序列也可以唯一确定一棵二叉树,但先序和后序不能确定一棵二叉树。

先序和中序序列构造一棵二叉树

  思路:我们知道先序序列的第一个值其实就是根节点的值,这样我们就可以在中序序列中找到对应的根节点,那么根节点左边的数就全为左子树的结点,根节点右边的数就全为右子树的结点。根据这个想法,再递归的进行构造,见代码。

后序和中序序列构造一棵二叉树

  思路:我们知道后序序列的最后一个值其实就是根节点的值,这样我们就可以在中序序列中找到对应的根节点,那么根节点左边的数就全为左子树的结点,根节点右边的数就全为右子树的结点。根据这个想法,再递归的进行构造,见代码。

Last updated

Was this helpful?