二叉树的递归与非递归遍历

来源:互联网 发布:java filter过滤器实例 编辑:程序博客网 时间:2024/06/16 00:24

二叉树遍历是二叉树中最基本的问题,其实现的方法非常多,有简单粗暴但容易爆栈的递归算法,还有稍微高级的使用栈模拟递归的非递归算法,另外还有不用栈而且只需要常数空间和线性时间的神奇Morris遍历算法,本文将对这些算法进行讲解和实现。

递归算法

二叉树节点使用以下数据结构进行表示,包括关键字、左儿子、右儿子属性和一个带默认参数的构造函数。
struct成员的默认属性为public,于是可以直接访问。

struct Node{int val;Node *left, *right;Node(int v = 0, Node *l = NULL, Node *r = NULL) : val(v), left(l), right(r) {}};

二叉树的递归算法非常简单,设置好递归出口之后,根据遍历的顺序,对当前节点的左右子递归调用自身即可。其前序、中序、后序遍历的代码如下。

void preorder1(Node *root) //递归前序遍历{if (root == NULL) return;printf("%d ", root->val);preorder1(root->left);preorder1(root->right);}void inorder1(Node *root) //递归中序遍历{if (root == NULL) return;inorder1(root->left);printf("%d ", root->val);inorder1(root->right);}void postorder1(Node *root) //递归后序遍历{if (root == NULL) return;postorder1(root->left);postorder1(root->right);printf("%d ", root->val);}

栈模拟非递归算法

递归算法的本质是利用函数的调用栈进行,实际上我们可以自行使用栈来进行模拟,这样的算法空间复杂度为O(h),h为二叉树的高度。

前序遍历

首先把根节点入栈,然后在每次循环中执行以下操作:

  • 此时栈顶元素即为当前的根节点,弹出并打印当前的根节点。
  • 把当前根节点的右儿子和左儿子分别入栈(注意是右儿子先入栈左儿子后入栈,这样的话下次出栈的元素才是左儿子,这样才符合前序遍历的顺序要求:根节点->左儿子->右儿子)。

下面是代码实现。

void preorder2(Node *root)//非递归前序遍历{if (root == NULL) return;stack<Node *> stk;stk.push(root);while (!stk.empty()){Node *p = stk.top(); stk.pop();printf("%d ", p->val);if (p->right) stk.push(p->right);if (p->left) stk.push(p->left);}}

后序遍历

因为后序遍历的顺序是:左子树->右子树->根节点,于是我们在前序遍历的代码中,当访问完当前节点后,先把当前节点的左子树入栈,再把右子树入栈,这样最终得到的顺序为:根节点->右子树->左子树,刚好是后序遍历倒过来的版本,于是把这个结果做一次翻转即为真正的后序遍历。而翻转可以通过使用另外一个栈简单完成,这样的代价是需要两个栈,但就复杂度而言,空间复杂度是O(n)。

void postorder2(Node *root)//非递归后序遍历{if (root == NULL) return;stack<Node *> stk, stk2;stk.push(root);while (!stk.empty()){Node *p = stk.top(); stk.pop();stk2.push(p);if (p->left) stk.push(p->left);if (p->right) stk.push(p->right);}while(!stk2.empty()){printf("%d ", stk2.top()->val);stk2.pop();}}

中序遍历

中序遍历稍微复杂,使用一个指针p指向下一个待访问的节点,p初始化为根节点。在每次循环中执行以下操作:

  • 如果p非空,则把p入栈,p变为p的左儿子。
  • 如果p为空,说明已经向左走到尽头了,弹出当前栈顶元素,进行访问,并把p更新为其右儿子。

下面是代码实现。

void inorder2(Node *root)//非递归中序遍历{stack<Node *> stk;Node *p = root;while (p != NULL || !stk.empty()){if (p != NULL)stk.push(p), p = p->left;else{p = stk.top(); stk.pop();printf("%d ", p->val);p = p->right;}}}

0 0
原创粉丝点击