赞
踩
在学习二叉树的过程中,二叉树的遍历是最基础的,但大多数人只学会了递归的写法,甚至不理解其根本,本篇文章带来二叉树遍历的非递归写法,无非就是借助栈或队列,标记域来完成非递归写法。
typedef char ElemType;
typedef struct BtNode
{
ElemType data;
struct BtNode* leftchild;
struct BtNode* rightchild;
}BtNode, * BinaryTree;
中序遍历,访问方式为 左子树——根节点——右子树。
非递归写法:借用栈来实现
初始状态
一直入左子树结点,直到为NULL
2结点有右子树,所以将右子树继续入栈。
再重复规则,直到循环退出。
// 非递归中序遍历 void NiceInOrder(BtNode* ptr) { if (ptr == NULL) return; std::stack<BtNode*> st; while (ptr != NULL || !st.empty()) { while (ptr != NULL) { st.push(ptr); ptr = ptr->leftchild; } ptr = st.top(); st.pop(); cout << ptr->data << " "; ptr = ptr->rightchild; } cout << endl; }
和中序遍历一样借用一个栈。
先序遍历顺序为:根节点——左子树——右子树。所以先打印数据,再入栈左子树。其他与中序遍历相同。
// 非递归先序遍历 void NicePreOrder(BtNode* ptr) { if (ptr == NULL) return; std::stack<BtNode*> st; while (ptr != NULL || !st.empty()) { while (ptr != NULL) { cout << ptr->data << " "; st.push(ptr); ptr = ptr->leftchild; } ptr = st.top(); st.pop(); ptr = ptr->rightchild; } cout << endl; }
后序遍历稍微复杂,若也是借用栈来实现,由于遍历方式是左子树——右子树——根节点。 所以在对某个结点出栈后,我们并不知道是否对该结点的右子树访问了没有。
初始状态
一直对左子树入栈直至左子树为NULL
打印该结点值,将标记位指向当前节点,并将ptr置为NULL
继续出栈后
发现标记位不在当前结点的右子树,那么继续将该结点入栈
重复上述规则
// 非递归后序遍历 void NicePastOrder(BtNode* ptr) { if (ptr == NULL) return; std::stack<BtNode*> st; // 跟踪标记位 BtNode* tag = NULL; while (ptr != NULL || !st.empty()) { // 先入栈左子树 while (ptr != NULL) { st.push(ptr); ptr = ptr->leftchild; } ptr = st.top(); st.pop(); // 如果当前结点右子树不为NULL或标记位在右子树 // 就可以打印该结点,并将标记位指向该结点 if (ptr->rightchild == NULL || ptr->rightchild == tag) { cout << ptr->data << " "; tag = ptr; ptr = NULL; } else // 否则就继续入栈,并访问它的右子树 { st.push(ptr); ptr = ptr->rightchild; } } cout << endl; }
在后序遍历过程中可以发现,每个结点都出栈了三次。
如图,1,2,3代表出栈次数
设计一个类型,表示要存到栈里的类型,有二叉树类型的指针成员和计数成员pos,这个计数值代表出栈次数。
// 计数加栈 struct StkNode { BtNode* pnode; int pos; public: StkNode(BtNode* node = nullptr, int n = 0) : pnode(node), pos(n) { } }; void StkPastOrder(BtNode* root) { if (root == nullptr) return; std::stack<StkNode> st; st.push(StkNode(root)); while (!st.empty()) { StkNode node = st.top(); st.pop(); if (++node.pos == 3) { cout << node.pnode->data << " "; } else { st.push(node); if (node.pos == 1 && node.pnode->leftchild != nullptr) { st.push(node.pnode->leftchild); } else if (node.pos == 2 && node.pnode->rightchild != nullptr) { st.push(node.pnode->rightchild); } } } cout << endl; }
参考自leetcode:二叉树的遍历
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。