二叉树——二叉树的遍历
2016-02-21 12:29
197 查看
二叉树遍历(Binary Tree Traversal)
二叉树的遍历是指按照一定次序访问树中所有结点,并且每个结点仅被访问一次的过程。它是最基本的运算,是二叉树中所有其他运算的基础。重用的4种遍历方法如下:
1.前序遍历
前序遍历的二叉树的过程如下:
(1)访问根结点
(2)前序遍历左子树
(3)前序遍历右子树
前序遍历二叉树的递归算法如下:
//前序遍历(递归) void PreOrder(TreeNode *root) { if(root) { cout<<root->val<<" "; PreOrder(root->left); PreOrder(root->right); } }
由前序遍历的过程可知,先访问根结点,再访问左子树,最后访问右子树。因此,先将根结点进栈,在栈不为空时循环:出栈p,访问*p结点,若它有右孩子,将其右孩子结点进栈,若它有左孩子,再将其左孩子进栈。对应的非递归算法如下:
//前序遍历(非递归) void PreOrder2(TreeNode *root) { stack<TreeNode *> st; TreeNode *p =root; while(p || !st.empty()) { if(p) { st.push(p); cout<<p->val<<" "; p=p->left; } else { p = st.top(); st.pop(); p = p->right; } } }
2.中序遍历
中序遍历的二叉树的过程如下:
(1)中序遍历左子树
(2)访问根结点
(3)中序遍历右子树
中序遍历二叉树的递归算法如下:
//中序遍历(递归) void InOrder(TreeNode *root) { if(root) { InOrder(root->left); cout<<root->val<<" "; InOrder(root->right); } }
由中序遍历过程可知,采用一个栈保存需要返回的结点指针,先扫描(并非访问)根结点的所有左下结点并将它们一一进栈。然后出栈一个结点,显然该结点没有左孩子结点或者左孩子结点已被访问过(进一步说明该结点的左子树均已被访问过),则访问它。然后扫描该结点的右孩子结点,将其进栈,再扫描该右孩子结点的所有左结点并一一进栈,如此这样,直到栈为空为止。对应的非递归算法如下:
//中序遍历(非递归) void InOrder2(TreeNode *root) { stack<TreeNode *> st; TreeNode *p = root; while(p || !st.empty()) { if(p) { st.push(p); p = p->left; } else { p = st.top(); cout<<p->val<<" "; st.pop(); p=p->right; } } }
3.后序遍历
后序遍历的二叉树的过程如下:
(1)后序遍历左子树
(2)后序遍历右子树
(3)访问根结点
后序遍历二叉树的递归算法如下:
//后序遍历(递归) void PostOrder(TreeNode *root) { if(root) { PostOrder(root->left); PostOrder(root->right); cout<<root->val<<" "; } }
由后续遍历可知,采用一个栈保存需要返回的结点指针,先扫描根结点的所有左结点并一一进栈,出栈一个结点*b即当前结点,然后扫描该节点的右孩子结点并进栈,再扫描该右孩子结点的所有左结点并建站。当一个结点的左右孩子结点均被访问后再访问该结点,如此这样,直到栈为空为止。
其中的难点是如何判断一个结点*b的右孩子结点已被反问过,为此用p保存刚刚访问过的结点(初始值为NULL),若b->rchild==p成立(在后续遍历中,*b的右孩子结点一定刚好在*b之前被访问),说明*b的左右子树均已被访问,现在应访问*b。
从上述过程可知,栈中保存的是当前结点*b的所有祖先结点(均未被访问过)。对应的递归算法如下:
//后序遍历(非递归) void PostOrder2(TreeNode *root) { stack<BTNode *> st; TreeNode *p=root; BTNode *temp; while(p || !st.empty()) { while(p) { BTNode *btn = new BTNode(); btn->btnode = p; btn->ifFirst = true; st.push(btn); p=p->left; } if(!st.empty()) { temp = st.top(); st.pop(); if(temp->ifFirst) { temp->ifFirst=false; st.push(temp); p = temp->btnode->right; } else { cout<<temp->btnode->val<<" "; p=NULL; } } } }
4.层次遍历
层次遍历二叉树的过程如下:
(1)访问根结点(第1层)。
(2)从左到右访问第2层的所有结点。
(3)从左到右访问第3层的所有结点,······,第h层的所有结点。
层次遍历二叉树的算法如下:
//层次遍历 void LevelOrder(TreeNode *root) { TreeNode *p = root; queue<TreeNode *> qu; qu.push(p); while(!qu.empty()) { p = qu.front(); cout<<p->val<<" "; qu.pop(); if(p->left) { qu.push(p->left); } if(p->right) { qu.push(p->right); } } }
相关文章推荐
- AVL树-自平衡二叉查找树(Java实现)
- 文件遍历排序函数
- Lua 学习笔记之C API 遍历 Table实现代码
- C#遍历文件夹后上传文件夹中所有文件错误案例分析
- C#中遍历Hashtable的4种方法
- Erlang中遍历取出某个位置的最大值代码
- C++实现图的邻接矩阵存储和广度、深度优先遍历实例分析
- C++实现图的邻接表存储和广度优先遍历实例分析
- C语言二叉树的非递归遍历实例分析
- 使用C语言构建基本的二叉树数据结构
- 一波二叉树遍历问题的C++解答实例分享
- C++非递归队列实现二叉树的广度优先遍历
- php遍历目录方法小结
- 一个目录遍历函数
- php遍历删除整个目录及文件的方法
- PHP遍历文件夹与文件类及处理类用法实例
- PHP遍历XML文档所有节点的方法
- php中使用key,value,current,next和prev函数遍历数组的方法
- C#使用前序遍历、中序遍历和后序遍历打印二叉树的方法
- 平衡二叉树