typedef struct TreeNode{
int value;
struct TreeNode *lchild, *rchild;
}TreeNode;
//二叉树的先序遍历非递归
void PreOrderTraverse(TreeNode *root){
if(root == NULL)
return;
TreeNode *pNode;
stack<TreeNode*> s;
s.push(root);
while(!s.empty()){
pNode = s.top();
cout<<pNode->value<<endl;
//当前节点访问完后出栈
s.pop();
//先让右子树进栈,后访问右子树
if(pNode->rchild != NULL)
s.push(pNode->rchild);
//右子树在栈顶,保证下次访问先访问左子树
if(pNode->lchild != NULL)
s.push(pNode->lchild);
}
}
//二叉树的中序遍历非递归
void InOrderTraverse(TreeNode *root){
if(root == NULL)
return;
TreeNode *pNode = root;
stack<TreeNode*> s;
//思路就是每次遍历到最左边的孩子,然后依次出栈访问
//然后对每个出栈的节点对其右孩子为根节点最上面同样的操作(遍历到最左边,再依次退栈)
while(pNode!=NULL||!s.empty())
{
while(pNode!=NULL)
{
s.push(pNode);
pNode=pNode->lchild;
}
if(!s.empty())
{
//栈里的所有元素可以视为左孩子
pNode=s.top();
cout<<pNode->value<<endl;
//最重要的就是这个出栈,出栈可以视为这样
//该栈顶节点左孩子访问出栈,该节点访问后出栈,然后对该节点的右孩子做中序遍历,直至右子树中序访问完毕
//访问该栈顶节点的祖先节点(也就是栈顶的后一个元素),再重复上述操作(对该祖先节点的右孩子做中序遍历,直至该祖先节点的右子树访问完毕)
s.pop();
pNode=pNode->rchild;
}
}
}
//二叉树的后序遍历非递归
void PostOrderTraverse(TreeNode *root){
if(root == NULL)
return;
stack<TreeNode*> s;
TreeNode *pNode = root, *pre;
//思路就是每个节点都按照右中左的顺序入栈
//然后出栈有两种情况:
// 1.第一个出栈的肯定为叶子,无论是左右叶子
// 2.如果栈顶不是叶子节点,则往下深度搜索
//第二种情况会出现一种问题,如果这个节点的左右子树已经被访问了
//如果不加以区分,这个节点的左右子树还会入栈,造成重复访问
// 这个节点的祖先节点也不能正确的被访问(因为后序遍历是从下往上的)
//设置pre为上一个被访问的节点,
s.push(pNode);
while (!s.empty()) {
pNode = s.top();
if (pNode->lchild == NULL && pNode->rchild == NULL) { //当pNode为叶子时
cout<<pNode->value<<endl;
s.pop();
pre = pNode;
} else if (pNode->lchild == pre || pNode->rchild == pre) { //当pNode的左孩子或右孩子被访问后
cout<<pNode->value<<endl;
s.pop();
pre = pNode;
} else{
if (pNode->rchild != NULL) {
s.push(pNode->rchild);
}
if (pNode->lchild != NULL) {
s.push(pNode->lchild);
}
}
}
}
//二叉树的层次遍历非递归
void LevelOrderTraverse(TreeNode *root){
if(root == NULL)
return;
TreeNode *p;
queue<TreeNode*> q;
q.push(root);
while (!q.empty()) {
p = q.front();
q.pop();
cout<<p->value<<endl;
if (p->lchild)
q.push(p->lchild);
if (p->rchild)
q.push(p->rchild);
}
}
二叉树的非递归遍历
最新推荐文章于 2024-06-03 17:15:00 发布