二叉树遍历:递归方法与非递归方法——递归程序修改为非递归的方法
来源:互联网 发布:mac怎么打开多个终端 编辑:程序博客网 时间:2024/04/30 19:11
前天去美团面试,二面基本一路顺风,后来,碰到一个用非递归的方法求解二叉树高度,并要求现场写程序,一下就卡住了,非常不爽。这两天把这个部分恶补了一下,总结了一下思路如下。
1、考虑清楚解题类似于遍历中的前序 or 中序 or 后续;
2、考虑清楚在递归程序中,每次会有哪些内容需要进栈:节点本身、返回地址(用于告诉程序返回后应该从何处执行)、局部变量、返回值。
下面先上代码,并比较得出思路。
首先,我们看一下先序遍历的递归和非递归程序:
void PreTraverse(CNode *subTree, bool (*Visit)(CNode *)){if (subTree){Visit(subTree);PreTraverse(subTree->lchild, Visit);PreTraverse(subTree->rchild, Visit);}}void PreTraverseNonRecursive(CNode *subTree, bool (*Visit)(CNode *)) // 你会把这个函数按照后边的形式简化吗^^这个函数来源于网络,个人认为写的比较繁琐。你可以使用三个case简化。{std::stack<CNode*> s;CNode *t = subTree;s.push(t);while (!s.empty()){while (!s.empty()) // go left until the most left child{t = s.top(); // notice: without pop!!if (!t)break;Visit(t);s.push(t->lchild);}s.pop(); // pop null pointerif (!s.empty()) // right child{t = s.top(); s.pop();s.push(t->rchild);}}}
其次,中序遍历:
void InTraverse(CNode *subTree, bool (*Visit)(CNode *)){if (subTree){InTraverse(subTree->lchild, Visit);Visit(subTree);InTraverse(subTree->rchild, Visit);}}void InTraverseNonRecursiveVer2(CNode *subTree, bool (*Visit)(CNode *)) { class CPostNode { public: CNode* pNode; int flag; CPostNode(CNode *n, int i) { pNode = n; flag = i; }; }; std::stack<CPostNode> s; CPostNode t(subTree, 1); s.push(t); while (!s.empty()) { t= s.top(); s.pop(); switch(t.flag) { case 1: t.flag = 2; s.push(t); if (t.pNode->lchild) { s.push(CPostNode(t.pNode->lchild, 1)); } break; case 2: Visit(t.pNode); if (t.pNode->rchild) { s.push(CPostNode(t.pNode->rchild, 1)); } break; case 3: // unable to run to here for in-traverse. break; } } }
再然后,是后续遍历:
void PostTraverse(CNode *subTree, bool (*Visit)(CNode *)){if (subTree){PostTraverse(subTree->lchild, Visit);PostTraverse(subTree->rchild, Visit);Visit(subTree);}}void PostTraverseNonRecursive(CNode *subTree, bool (*Visit)(CNode *)){class CPostNode{public:CNode* pNode;int flag;CPostNode(CNode *n, int i){pNode = n;flag = i;};};std::stack<CPostNode> s;CPostNode t(subTree, 1);s.push(t);while (!s.empty()){t = s.top(); s.pop(); // notice: pop() here!!switch(t.flag){case 1:t.flag = 2;s.push(t);if (t.pNode->lchild){s.push(CPostNode(t.pNode->lchild, 1));}break;case 2:t.flag = 3;s.push(t);if (t.pNode->rchild){s.push(CPostNode(t.pNode->rchild, 1));}break;case 3:Visit(t.pNode);//s.pop();break;}}}
最后,也就是把我难倒的,非递归法求树的高度:
int GetSubTreeDepth(CNode *subTree){if (!subTree)return 0;return std::max<int>(GetSubTreeDepth(subTree->lchild), GetSubTreeDepth(subTree->rchild)) + 1;}int GetSubTreeDepthVer2(CNode *subTree){class CStackNode{public:CNode* pNode;int flag;int depth;CStackNode(CNode *n, int i, int d){pNode = n;flag = i;depth = d;};};std::stack<CStackNode> s;CStackNode t(subTree, 1, 1);s.push(t);while (!s.empty()){t = s.top(); s.pop();switch (t.flag){case 1:t.flag = 2;s.push(t);if (t.pNode->lchild){s.push(CStackNode(t.pNode->lchild, 1, 1));}break;case 2:t.flag = 3;s.push(t);if (t.pNode->rchild){s.push(CStackNode(t.pNode->rchild, 1, 1));}break;case 3:if (s.empty())return t.depth;CStackNode t3 = s.top(); s.pop();t3.depth = std::max<int>(t3.depth, t.depth + 1);s.push(t3);break;}}return t.depth;}
从上面的例子中,我们能清晰的看到解题的思路:用flag来标记我们访问该节点第几次,不同的次数意味着要做不同的事情,所以在程序中有不同的case执行着不同的代码。
另外,一个需要关注的地方是,在求树的高度时,case 3中需要首先判断s是否为空,若为空则可直接返回高度了~
所有代码为本人花了一天的时间完成,引用请注明出处,谢谢~
xjs.xjtu@gmail.com
2012-10-24
- 二叉树遍历:递归方法与非递归方法——递归程序修改为非递归的方法
- 二叉树递归与非递归遍历的方法
- java二叉树的遍历,递归与非递归方法
- 二叉树三种遍历方法的递归与非递归实现
- 二叉树的非递归遍历方法
- 非递归的方法遍历二叉树
- 非递归遍历二叉树的方法
- 二叉树的非递归遍历方法
- 二叉树的遍历方法(递归,非递归)
- 二叉树的遍历 -- 递归和非递归方法
- 二叉树的递归和非递归遍历方法
- 遍历二叉树的全部方法(递归+非递归)
- 二叉树的递归和非递归遍历方法
- 【算法设计-二叉树遍历】二叉树的递归与非递归遍历方法
- 二叉树的深度 (递归与非递归方法整理)
- 二叉树中序遍历的非递归方法
- 【C++】二叉树的创建方法及其遍历的递归与非递归方法总结
- 二叉树的先序、中序、后序遍历方法(递归与非递归方法)——《数据结构》
- poj 2393 Yogurt factory
- 图像处理(二)直方图均衡化
- 日历时间加减法
- Hibernate分页查询
- MOS管开关电路设计知识
- 二叉树遍历:递归方法与非递归方法——递归程序修改为非递归的方法
- 系统程序设计学习笔记
- UbuntuServer搭建Git服务器之SSH基本用法(一)
- 移动mysql数据文件目录(datadir)以及selinux的一些经验
- Android adb shell command
- Windows7/Windows Server 2008 右键"选择默认程序"出错解决方案
- hdu 2242 考研路茫茫――空调教室(Tarjan+树型DP)
- 最大子序列、最长递增子序列、最长公共子串、最长公共子序列、字符串编辑距离
- 安装MYSQL之转移数据目录的成功经验