二叉树是每个节点最多有两个子树的树结构,遍历方法有深度优先(包括:先序、中序、后序遍历)和宽度优先(层序遍历),层序遍历通过队列可以实现。
这里主要介绍深度优先遍历的方法以及其中栈的应用,帮助理解二叉树的结构、递归和非递归中栈的应用。
中序遍历:左子树---> 根结点 ---> 右子树(先访问左子树,再访问根节点,后访问右子树,而对于每个子树来说,又按照同样的访问顺序进行遍历)
先序遍历:根结点 ---> 左子树 ---> 右子树
后序遍历:左子树 ---> 右子树 ---> 根结点
根据三种遍历的特性,递归的算法很容易就能写出来
//先序 void PreOrder(node *root) { if (root==NULL) return; else { printf("%d", root->data); PreOrder(root->lch); PreOrder(root->rch); } } //中序 void InOrder(node *root) { if (root==NULL) return; else { InOrder(root->lch); printf("%d", root->data); InOrder(root->rch); } } //后序 void PostOrder(node *root) { if (root==NULL) return; else { PostOrder(root->lch); PostOrder(root->rch); printf("%d", root->data); } }
二叉树遍历的核心问题:二维结构的线性化
>从结点访问其左,右儿子节点
>访问左儿子后,右儿子节点怎么办?
#需要一个存储结构保存暂时不访问的结点
#存储结构:堆栈,队列
递归的根本的实现方法就是堆栈,我们想有没有可能直接用堆栈实现非递归算法?
树中各节点的访问路径
以中序遍历为例,一开始碰到A的时候,由于是中序不能直接打印A,必须遍历完左边的子树后,才能打印A,那遍历完后又怎么知道回到这边来呢?这时候采用的方法实际上就是堆栈
对于栈中的某一元素而言,需要判定其是否满足出栈条件:当回溯至栈中某一点时,要判断是否还需要其的记忆作用
void Traversal(BiTree BT)
{ Stack S = CreateStack(MaxSize);//创建栈,用于存储节点 BTNode *T = BT; while(T||!isEmpty(S)){ while(T){ //在此访问节点为先序遍历 Push(S, T); T = T->lchild; } if(!isEmpty(S)){ T = pop(S); //在此访问节点为中序遍历 T = T->rchild; } } }
以上是先序遍历和中序遍历的模板,如果在压栈的时候访问节点,这时是第一次遇到该节点,则为先序遍历。如果在弹栈的时候访问节点,此时之前已经将节点入栈,所以这是第二次遇到该节点,则是中序遍历。
老师在课上讲的关于访问树的路径是每个节点都要被访问三次,第一次、第二次、第三次遇到节点的时候访问则为先序、中序、后序遍历。
第一次、第二次、第三次遇到该节点分别是:
第一次:该节点被作为其父节点的某子树的根节点访问。
第二次:从该节点的左子树返回该节点
第三次:从该节点的右子树返回该节点
如果是后序遍历,则需要在第三次遇到该节点的时候访问该节点。那么就是需要在从该节点的右子树返回时访问该节点。所以实现后序遍历最重要的就是识别当节点从栈中弹出时,刚刚是访问了其左孩子节点,还是访问了右孩子节点。
如果每次访问节点的时候,都用一个节点指向这个节点,那么下一次要访问节点的时候,就可以知道上一次访问的是它的左孩子节点还是右孩子节点。
所以当要访问一个节点的时候,我们首先判断上一次访问的是不是它的右孩子节点,如果不是并且该节点有右孩子节点的话,那么就先访问它的右子树。如果是的话,那么表示该节点的左子树和右子树都已经访问完毕。
void postOrderTraversal(BiTree BT) { BiTree T = BT, pre = NULL; Stack S = CreateStack(MaxSize); while(T||!isEmpty(S)) { while(T) { Push(S, T); T = T->lchild; } if(!isEmpty(S)){ T = getTop(S); //右子树还没有被访问 if(T->rchild && T->rchild!=pre) T = T->rchild; //无右子树或右子树已被访问 else{ T = pop(S);//节点出栈并访问 visit(T); pre = T; T = NULL;//将T设为空,以访问其父节点。 } } } }
参考自:
https://www.icourse163.org/learn/ZJU-93001?tid=1003997005#/learn/content?type=detail&id=1007588486&cid=1009151983(main)
https://blog.csdn.net/sky_kkk/article/details/78543358?utm_source=blogxgwz7
https://blog.csdn.net/sdulibh/article/details/50573036
https://blog.csdn.net/zhangxiangdavaid/article/details/37115355