二叉树的递归和非递归遍历
来源:互联网 发布:桌面美化软件 编辑:程序博客网 时间:2024/06/05 16:59
前段时间瞄了一眼《剑指offer》上面有说要熟悉二叉树的6种遍历方式,说来你或许不信,我自己实现非递归遍历的时候硬是没有实现出来,看来自己的基本功还是有待加强的。话不多说,上代码加分析。
二叉树的实现:
这个基本上是轻车熟路了,平常写书的算法的时候都要求实现一遍,当然这里不是这篇文章的重点。
树的节点的定义和树的定义。
struct TreeNode { TreeNode *lChild; //左孩子 TreeNode *rChild; //右孩子 EleType value; //节点中的值};struct Tree { TreeNode *root; //树可以直接用一个节点的指针来表示};树的实现。
TreeNode *CreateTreeNode (EleType k) { //这个函数的意义是分配一个树的节点并且初始化 TreeNode *temp = (TreeNode *) malloc (sizeof (TreeNode)); temp->lChild = nullptr; temp->rChild = nullptr; temp->value = k; return temp;}void CreateTree (TreeNode **root) { int t; cin >> t; if (t != 0) { //为零的话代表其是叶节点 *root = CreateTreeNode (t); CreateTree (&((*root)->lChild));//利用递归实现树 CreateTree (&((*root)->rChild)); }}二叉树的前序遍历:
二叉树的前序遍历的递归实现。
void PreTravelTree (TreeNode *node) { if (node != nullptr) { cout << node->value << " "; PreTravelTree (node->lChild); PreTravelTree (node->rChild); }}二叉树的前序遍历的非递归实现。
void PreTravelTreeNonRecur (TreeNode *node) { stack<TreeNode *> nodeStack; TreeNode *cur = node; while (cur != nullptr || !nodeStack.empty ()) { while (cur != nullptr) { cout << cur->value << " "; nodeStack.push (cur); cur = cur->lChild; } if (!nodeStack.empty ()) { cur = nodeStack.top (); nodeStack.pop (); cur = cur->rChild; } }二叉树的中序遍历:
二叉树的中序遍历的递归实现。
void MidTravelTree (TreeNode *node) { if (node != nullptr) { MidTravelTree (node->lChild); cout << node->value << " "; MidTravelTree (node->rChild); }}二叉树的中序遍历的非递归实现。
void MidTravelTreeNonRecur (TreeNode *node) { stack<TreeNode *> nodeStack; TreeNode *cur = node; while (cur != nullptr || !nodeStack.empty ()) { while (cur != nullptr) { nodeStack.push (cur); cur = cur->lChild; } if (!nodeStack.empty ()) { cur = nodeStack.top (); cout << cur->value << " "; nodeStack.pop (); cur = cur->rChild; } }}二叉树的后序遍历:
二叉树的后序遍历的递归实现。
void PosTravelTree (TreeNode *node) { if (node != nullptr) { PosTravelTree (node->lChild); PosTravelTree (node->rChild); cout << node->value << " "; }}二叉树的后序遍历的非递归实现。
这个是这篇文章的重点了,由于二叉树的后序遍历不同于前序遍历和中序遍历,必须要使用某种方式标记出左右字节点是否已经访问过了,那么在这里其实有两种方式,一种方式是改变底层的数的节点的数据结构,加上访问标记。第二种就是使用不同的进栈方式,在父节点进栈的时候同时将两个子节点进栈。下面先介绍第一种方式,改变底层的数据结构。
(底层数据结构只是加上了visited的字段,并没有其他的不同,不再赘述)
void PosTravelTreeNonRecurSec (TreeNodePlus *node) { stack<TreeNodePlus *> nodeStack; TreeNodePlus *cur = node; while (cur != nullptr || !nodeStack.empty ()) { while (cur != nullptr) { //在这个while循环当中,只将不是nullptr同时没有访问过的节点加入nodeStack cur->visited++; nodeStack.push (cur); if (cur->lChild == nullptr) { break; }else if (cur->lChild->visited > 0) { break; }else { cur = cur->lChild; } } if (!nodeStack.empty ()) { //进入这里就说明其子节点的一个孩子或者两个孩子已经访问过了(这里有一个特殊情况 cur = nodeStack.top ();//就是子节点为nullptr也可以进入这里,但是子节点为nullptr也代表访问过了) cur->visited++; if (cur->visited == 3) { //说明这个节点的左右子节点已经访问过了,那么就可以将这个节点打印出来 cout << cur->value << " "; nodeStack.pop (); cur = nullptr; //将其设置为nullptr那么下个循环就可以跳过上面那么while循环,处理这个节点的父节点。 }else { cur = cur->rChild;//说明这个节点的右节点还没有访问,那么把当前节点的值设置为右节点。 } } }}第二种方式就是使用不同的进栈方式。
void PosTravelTreeNonRecur (TreeNode *node) { stack<pair<TreeNode * , bool>> nodeStack; //这个栈的节点是一个pair TreeNode *cur = node; nodeStack.push (make_pair (cur , false)); bool visited; while (!nodeStack.empty ()) { cur = nodeStack.top().first; visited = nodeStack.top().second; nodeStack.pop (); if (cur == nullptr) continue; if (visited) cout << cur->value << " "; else { //使用精心设计的进栈方式,根节点放在最下面,然后再是右节点,再是坐节点,这样就保证取出来的时候 nodeStack.push (make_pair(cur , true)); //左节点可以最先取出来。同时,其他两种的遍历方式的非递归实现 nodeStack.push (make_pair(cur->rChild , false)); //也可以采用这种进栈方式,但是缺点是效率稍微低了一些,进栈 nodeStack.push (make_pair(cur->lChild , false)); //次数多了。 } }}
0 0
- 二叉树的递归遍历和非递归遍历
- 二叉树的递归遍历和非递归遍历
- 二叉搜索树的递归遍历和非递归遍历
- java 二叉树的递归遍历和非递归遍历
- 递归 和 非递归 遍历二叉树
- 递归和非递归遍历二叉树
- 递归和非递归遍历二叉树
- 二叉树递归和非递归遍历
- 二叉树递归和非递归遍历
- 递归和非递归遍历二叉树
- 二叉树的递归和非递归的遍历算法
- 二叉树的前序中序后序的递归和非递归遍历
- 二叉树的递归,非递归遍历
- 二叉树的递归+非递归遍历
- 二叉树的递归非递归遍历
- 二叉树的遍历--递归+非递归
- 二叉树的递归、非递归遍历
- 二叉树的递归非递归遍历
- 树链剖分
- Xcode常用快捷键
- 小程序WXML之数据绑定
- 多线程之Runnable
- uboot之start_armboot分析1
- 二叉树的递归和非递归遍历
- popupwindow的封装
- Realm 入门 简单实用方法
- JS垫脚石-字符串篇
- php获取用户(客户端)真实IP地址的三种方法
- 微信小程序 Button按钮与Icon图标
- Java泛型与C++模板
- oracle创建数据库步骤
- DPDK关键技术点