二叉树的建立以及六种递归非递归遍历
2014-05-06 18:14
288 查看
最近在看数据结构,在看到二叉树的这一章,发现书上详细写出了三种遍历方法,但是对于非递归的实现却介绍的不是很详细,但是在笔试或者面试的时候经常被问到二叉树的非递归实现遍历,仔细的思考了一下,实现了二叉树的三种递归遍历以及三种非递归遍历。
在建立如上图的二叉树的时候,一定要注意输入NULL节点,这一点对于初学者很容易造成疑惑,因为只有八个节点,为什么我输入八个节点之后,显示出来的二叉树不是我想要的二叉树,原因就是NULL节点的输入以及输入的顺序,如本例的图所示,在此假设当输入的数是-1的时候代表的是NULL节点,那么应该输入的顺序就应该是:1,2,4,-1,-1,5,-1,-1,3,6,-1,-1,7,-1,8,-1,-1;具体的代码如下所示:
只要注意这里传输的是地址,但是对于地址的操作有这两种方法,个人推荐用值传递,方便简单。
1,左孩子比右孩子先访问
2,三种遍历方式所说的是访问父母节点的顺序,比如说前序遍历就是首先访问父母节点,中序遍历就是第二个访问父母节点,后序遍历就是最后访问父母节点
记住这两点,基本上就不会将三种遍历再记混淆,关于前序遍历的递归方式首先访问父母节点,然后访问左孩子,访问右孩子,以此递归就可以,很好理解。前序遍历的非递归实现方法是靠栈的方法实现的,首先如果节点不为空,打印节点的信息,同时将此节点入栈,将节点的左孩子的值赋给节点,一直寻找左孩子,直到左孩子为空,若左孩子为空,取栈顶的节点,并进行出栈操作,并将栈顶节点的右孩子赋值给当前节点,一直到栈为空,遍历结束,具体的实现代码如下所示:
1,若节点不为空,将左孩子节点赋给当前节点值
2,若左孩子不为空,重复1操作,若左孩子为空,取栈顶元素,访问栈顶元素,出栈,并将取出的栈顶元素的右孩子的值赋给当前节点,重复1操作
3,若栈为空结束。
代码如下所示:
情况1:当前节点的左孩子以及右孩子同时为空的时候,才会将当前节点值输出
情况2::当前一个访问的是当前节点的左孩子或者右孩子的时候,那么此时也会将当前节点的值输出
具体的思路就是上述所表述的,具体的步骤如下:
(1)初始化,将根节点入栈,将前一个访问的置为NULL;
(2)如果栈不为空,取栈顶元素作为当前节点的值,判断当前节点是否满足两种输出情况,如果满足输出,出栈,将当前节点的值赋给pre,即前一个访问节点,进行下次循环;如果不满足进行步骤3
(3)如果当前节点的左孩子以及右孩子都不为空,现将右孩子入栈,再入栈左孩子;如果一个为空,那么入栈不为空的
(4)循环(2)到(3),直至栈为空的时候截止。
在这里面值的注意的是步骤三的入栈情况,是先右孩子入栈,然后才是左孩子入栈,因为栈是LIFO的结构,具体的实现代码如下所示:
头文件 tree.h
实现代码 tree.cpp
主函数main代码如下:
截图如下所示:
参考内容:(1)/article/4719934.html
(2)数据结构(c语言版) 严蔚敏
一、二叉树的建立
二叉树的一些很详细的知识在此不做介绍,二叉树的每一个节点最多有两个子孩子,在建立二叉树的时候需要注意的是对于每一个子孩子为空的二叉树,在用键盘输入的时候分别要给输入相应的空符号,例如现在要建立一个二叉树,如下图所示:在建立如上图的二叉树的时候,一定要注意输入NULL节点,这一点对于初学者很容易造成疑惑,因为只有八个节点,为什么我输入八个节点之后,显示出来的二叉树不是我想要的二叉树,原因就是NULL节点的输入以及输入的顺序,如本例的图所示,在此假设当输入的数是-1的时候代表的是NULL节点,那么应该输入的顺序就应该是:1,2,4,-1,-1,5,-1,-1,3,6,-1,-1,7,-1,8,-1,-1;具体的代码如下所示:
typedef struct treenode { int data; struct treenode *left,*right; }treenode,*mytree; void creattree(mytree &a) { int temp; cin>>temp; if(temp==-1) a=NULL; else { a=(mytree)malloc(sizeof(treenode)); a->data=temp; creattree(a->left); creattree(a->right); } }因为很简单,所以在此不做详细的解释,唯一的一点说明的是,因为是指针操作,所以对于一些读者来说可能会有点问题,在这里所采用的传参方式是引用传参,可能相对于指针来说会简单点,因为如果是指针传地址的话就应该如下所示:
void creattree1(mytree *a) { int temp; cin>>temp; if(temp==-1) *a=NULL; else { (*a)=(mytree)malloc(sizeof(treenode)); (*a)->data=temp; creattree1(&(*a)->left); creattree1(&(*a)->right); } }
只要注意这里传输的是地址,但是对于地址的操作有这两种方法,个人推荐用值传递,方便简单。
二、二叉树的三种遍历方式
(1)前序遍历
二叉树的前序遍历是先访问根节点,接着访问左孩子,最后访问右孩子,二叉树的三种遍历方式可能有时候会比较容易弄混淆,但是只要记住两点:1,左孩子比右孩子先访问
2,三种遍历方式所说的是访问父母节点的顺序,比如说前序遍历就是首先访问父母节点,中序遍历就是第二个访问父母节点,后序遍历就是最后访问父母节点
记住这两点,基本上就不会将三种遍历再记混淆,关于前序遍历的递归方式首先访问父母节点,然后访问左孩子,访问右孩子,以此递归就可以,很好理解。前序遍历的非递归实现方法是靠栈的方法实现的,首先如果节点不为空,打印节点的信息,同时将此节点入栈,将节点的左孩子的值赋给节点,一直寻找左孩子,直到左孩子为空,若左孩子为空,取栈顶的节点,并进行出栈操作,并将栈顶节点的右孩子赋值给当前节点,一直到栈为空,遍历结束,具体的实现代码如下所示:
void pretravel_feidiedai(const mytree a) { stack<mytree> s; mytree temp=a; while(temp!=NULL||!s.empty()) { while(temp!=NULL) { cout<<temp->data<<" "; s.push(temp); temp=temp->left; } if(!s.empty()) { temp=s.top(); s.pop(); temp=temp->right; } } }
(2)中序遍历
中序遍历的非递归方法和前序遍历的类似具体的步骤如下所示:1,若节点不为空,将左孩子节点赋给当前节点值
2,若左孩子不为空,重复1操作,若左孩子为空,取栈顶元素,访问栈顶元素,出栈,并将取出的栈顶元素的右孩子的值赋给当前节点,重复1操作
3,若栈为空结束。
代码如下所示:
void midtravel_feidiedai(const mytree a) { stack<mytree> s; mytree temp=a; while(temp!=NULL||!s.empty()) { while(temp!=NULL) { s.push(temp); temp=temp->left; } if(!s.empty()) { temp=s.top(); cout<<temp->data<<" "; s.pop(); temp=temp->right; } } }
(3)后序遍历
后续遍历相比与前序遍历以及中序遍历有点不同,后续遍历需要先访问左孩子,然后访问右孩子,然后访问父母节点,当情况1:当前节点的左孩子以及右孩子同时为空的时候,才会将当前节点值输出
情况2::当前一个访问的是当前节点的左孩子或者右孩子的时候,那么此时也会将当前节点的值输出
具体的思路就是上述所表述的,具体的步骤如下:
(1)初始化,将根节点入栈,将前一个访问的置为NULL;
(2)如果栈不为空,取栈顶元素作为当前节点的值,判断当前节点是否满足两种输出情况,如果满足输出,出栈,将当前节点的值赋给pre,即前一个访问节点,进行下次循环;如果不满足进行步骤3
(3)如果当前节点的左孩子以及右孩子都不为空,现将右孩子入栈,再入栈左孩子;如果一个为空,那么入栈不为空的
(4)循环(2)到(3),直至栈为空的时候截止。
在这里面值的注意的是步骤三的入栈情况,是先右孩子入栈,然后才是左孩子入栈,因为栈是LIFO的结构,具体的实现代码如下所示:
void posttravel_feidiedai(const mytree a) { stack<mytree> s; mytree cur=a,pre=NULL; s.push(a); while(!s.empty()) { cur=s.top(); if((cur->right==NULL&&cur->left==NULL)||((pre!=NULL)&&(pre==cur->left||pre==cur->right))) { cout<<cur->data<<" "; s.pop(); pre=cur; } else { if(cur->right!=NULL) s.push(cur->right); if(cur->left!=NULL) s.push(cur->left); } }
三、递归与非递归的完整代码
上述已经将非递归的情况说明清楚,递归的情况基本上每本书都会涉及,下面将所有的代码贴上去:头文件 tree.h
#ifndef _TREE_H #define _TREE_H #include<iostream> #include<stack> #include<windows.h> using namespace std; typedef struct treenode { int data; struct treenode *left,*right; }treenode,*mytree; void creattree(mytree &a); void pretravel_diedai(const mytree a); void midtravel_diedai(const mytree a); void posttravel_diedai(const mytree a); void pretravel_feidiedai(const mytree a); void midtravel_feidiedai(const mytree a); void posttravel_feidiedai(const mytree a); #endif
实现代码 tree.cpp
#include"tree.h"
void creattree(mytree &a)
{
int temp;
cin>>temp;
if(temp==-1)
a=NULL;
else
{
a=(mytree)malloc(sizeof(treenode));
a->data=temp;
creattree(a->left);
creattree(a->right);
}
}
void creattree1(mytree *a) { int temp; cin>>temp; if(temp==-1) *a=NULL; else { (*a)=(mytree)malloc(sizeof(treenode)); (*a)->data=temp; creattree1(&(*a)->left); creattree1(&(*a)->right); } }
void pretravel_diedai(const mytree a)
{
if(a!=NULL)
{
cout<<a->data<<" ";
pretravel_diedai(a->left);
pretravel_diedai(a->right);
}
}
void midtravel_diedai(const mytree a)
{
if(a!=NULL)
{
midtravel_diedai(a->left);
cout<<a->data<<" ";
midtravel_diedai(a->right);
}
}
void posttravel_diedai(const mytree a)
{
if(a!=NULL)
{
posttravel_diedai(a->left);
posttravel_diedai(a->right);
cout<<a->data<<" ";
}
}
void pretravel_feidiedai(const mytree a) { stack<mytree> s; mytree temp=a; while(temp!=NULL||!s.empty()) { while(temp!=NULL) { cout<<temp->data<<" "; s.push(temp); temp=temp->left; } if(!s.empty()) { temp=s.top(); s.pop(); temp=temp->right; } } }
void midtravel_feidiedai(const mytree a) { stack<mytree> s; mytree temp=a; while(temp!=NULL||!s.empty()) { while(temp!=NULL) { s.push(temp); temp=temp->left; } if(!s.empty()) { temp=s.top(); cout<<temp->data<<" "; s.pop(); temp=temp->right; } } }
void posttravel_feidiedai(const mytree a) { stack<mytree> s; mytree cur=a,pre=NULL; s.push(a); while(!s.empty()) { cur=s.top(); if((cur->right==NULL&&cur->left==NULL)||((pre!=NULL)&&(pre==cur->left||pre==cur->right))) { cout<<cur->data<<" "; s.pop(); pre=cur; } else { if(cur->right!=NULL) s.push(cur->right); if(cur->left!=NULL) s.push(cur->left); } }
}
主函数main代码如下:
#include"tree.h" void tree_6_travel(); int main() { tree_6_travel(); return 0; } void tree_6_travel() { mytree tree1; creattree(tree1); cout<<"迭代前序:"<<endl; pretravel_diedai(tree1); cout<<endl<<"迭代中序:"<<endl; midtravel_diedai(tree1); cout<<endl<<"迭代后序:"<<endl; posttravel_diedai(tree1); cout<<endl<<"非迭代前序:"<<endl; pretravel_feidiedai(tree1); cout<<endl<<"非迭代中序:"<<endl; midtravel_feidiedai(tree1); cout<<endl<<"非迭代后序:"<<endl; posttravel_feidiedai(tree1); system("pause"); }
截图如下所示:
参考内容:(1)/article/4719934.html
(2)数据结构(c语言版) 严蔚敏
相关文章推荐
- 二叉树的建立以及三种遍历方式的递归、非递归的实现
- 二叉树的递归创建,以及二叉查找树查找的建立 和遍历查找的比较
- 二叉树的建立以及先序中序后序递归遍历
- 二叉树建立以及递归、非递归遍历
- python实现二叉树的建立以及遍历(递归前序、中序、后序遍历,队栈前序、中序、后序、层次遍历)
- 二叉树的建立,以及递归前中后序遍历二叉树
- 二叉树先序后序递归建立,前中后序层次非递归遍历,以及统计叶子结点个数以及树的深度
- 二叉树的建树,按层遍历,结点总数,页结点,深度以及三序非递归遍历二叉树,建立中序线索二叉树
- 二叉树的先序以及后序递归建立,先中后序递归遍历。
- 二叉树的建立以及前序、中序、后序遍历的递归和非递归实现
- 二叉树的建立、遍历,以及给定二叉树前序遍历和中序遍历重建二叉树问题。
- 二叉树的建立及递归遍历
- 数据结构_二叉树的先序建立与先序,中序,后序(递归)遍历方式_C语言源代码
- 【非递归】二叉树的建立及遍历
- 二叉树的递归遍历以及非递归遍历
- 二叉树的存储方式以及递归和非递归的三种遍历方式
- 二叉树递归建立--深搜+宽搜遍历
- 二叉树各种遍历算法(递归以及非递归)6
- C++实现二叉树的建立和三种递归遍历
- c++ 二叉树 的递归建立和递归遍历