二叉树的构建及其遍历算法
来源:互联网 发布:罗技m558 mac驱动下载 编辑:程序博客网 时间:2024/05/29 07:38
本篇博客参照了兰亭风雨的博客:http://blog.csdn.net/ns_code/article/details/12977901/
概要
二叉树是一种非常重要的数据结构,很多其他数据机构都是基于二叉树的基础演变过来的。二叉树有先、中、后,层次四种遍历方式,因为树的本身就是用递归定义的,因此采用递归的方法实现三种遍历,不仅代码简洁且容易理解,但其开销也比较大,而若采用非递归方法实现先中后3种遍历,则要用栈来模拟实现(递归也是用栈实现的)。下面先简要介绍先中后三种遍历方式的递归实现,再详细介绍先中后三种遍历方式的非递归实现与层次遍历。
递归先序遍历
先序遍历按照“根节点->左子树->右子树”的顺序进行遍历。代码如下:
void PreorderTraversal(BinaryTree* T){ if(T == NULL){ return; } cout<<T->data<<" "; //访问根节点并输出 T->PreorderTraversal(T->lchild); //递归前序遍历左子树 T->PreorderTraversal(T->rchild); //递归前序遍历右子树 }
递归中序遍历
中序遍历按照“左子树->根节点->右子树”的顺序进行遍历。代码如下:
void InorderTraversal(BinaryTree* T){ if(T == NULL){ return; } T->InorderTraversal(T->lchild); //递归中序遍历左子树 cout<<T->data<<" "; //访问根节点并输出 T->InorderTraversal(T->rchild); //递归中序遍历左子树 }
递归后序遍历
后序遍历按照“左子树->右子树->根结点”的顺序进行遍历。代码如下:
void PostorderTraversal(BinaryTree* T){ if(T == NULL){ return; } T->PostorderTraversal(T->lchild); //递归后序遍历左子树 T->PostorderTraversal(T->rchild); //递归后序遍历右子树 cout<<T->data<<" "; //访问并打印根节点 }
非递归先序遍历
非递归的实现思路如下:
对于任一节点P,
1)输出节点P,然后将其入栈,再看P的左孩子是否为空;
2)若P的左孩子不为空,则置P的左孩子为当前节点,重复1)的操作;
3)若P的左孩子为空,则将栈顶节点出栈,但不输出,并将出栈节点的右孩子置为当前节点,看其是否为空;
4)若不为空,则循环至1)操作;
5)如果为空,则继续出栈,但不输出,同时将出栈节点的右孩子置为当前节点,看其是否为空,重复4)和5)操作;
6)直到当前节点P为NULL并且栈空,遍历结束。
代码如下:
void PreorderTraversal2(BinaryTree* T){ stack<BinaryTree*> stack; //初始化栈 BinaryTree* binary_tree_curr = T; //保存当前结点 //当前结点为空跳出循环 while(binary_tree_curr || !stack.empty()){ cout<<binary_tree_curr->data<<" "; //打印当前结点 stack.push(binary_tree_curr); //当前结点入栈 binary_tree_curr = binary_tree_curr->lchild; //访问左子树 //当前结点为空为空,当前结点出栈 //并把右孩子作为当前结点 while(!binary_tree_curr && !stack.empty()){ binary_tree_curr = stack.top(); stack.pop(); binary_tree_curr = binary_tree_curr->rchild; } } }
非递归中序遍历
非递归的实现思路如下:
对于任一节点P,
1)若P的左孩子不为空,则将P入栈并将P的左孩子置为当前节点,然后再对当前节点进行相同的处理;
2)若P的左孩子为空,则输出P节点,而后将P的右孩子置为当前节点,看其是否为空;
3)若不为空,则重复1)和2)的操作;
4)若为空,则执行出栈操作,输出栈顶节点,并将出栈的节点的右孩子置为当前节点,看起是否为空,重复3)和4)的操作;
5)直到当前节点P为NULL并且栈为空,则遍历结束。
代码如下:
void InorderTraversal2(BinaryTree* T){ stack<BinaryTree*> stack; //初始化栈 BinaryTree* binary_tree_curr = T; //保存当前结点 while(binary_tree_curr || !stack.empty()){ if(binary_tree_curr->lchild){ //左孩子非空 stack.push(binary_tree_curr); //当前结点入栈 binary_tree_curr = binary_tree_curr->lchild; //遍历左子树 }else{ //左孩子为空,则打印当前结点遍历右子树 cout<<binary_tree_curr->data<<" "; binary_tree_curr = binary_tree_curr->rchild; //如果为空,且栈不空,则将栈顶节点出栈,并输出该节点, //同时将它的右孩子设为当前节点,继续判断,直到当前节点不为空 while(!binary_tree_curr && !stack.empty()){ binary_tree_curr = stack.top(); cout<<binary_tree_curr->data<<" "; stack.pop(); binary_tree_curr = binary_tree_curr->rchild; } } } }
非递归后序遍历
思路如下:
对于任一节点P,
1)先将节点P入栈;
2)若P不存在左孩子和右孩子,或者P存在左孩子或右孩子,但左右孩子已经被输出,则可以直接输出节点P,并将其出栈,将出栈节点P标记为上一个输出的节点,再将此时的栈顶结点设为当前节点;
3)若不满足2)中的条件,则将P的右孩子和左孩子依次入栈,当前节点重新置为栈顶结点,之后重复操作2);
4)直到栈空,遍历结束。
代码如下:
//非递归后序遍历 void PostorderTraversal2(BinaryTree* T){ stack<BinaryTree*> stack; BinaryTree* binary_tree_curr = T; //当前结点 BinaryTree* binary_tree_pre = NULL; // 上一个结点 //先将树的根节点入栈 stack.push(binary_tree_curr); //直到栈空时,结束循环 while(!stack.empty()){ binary_tree_curr = stack.top(); //当前节点置为栈顶节点 //如果当前节点没有左右孩子,或者有左孩子或有孩子,但已经被访问输出, //则直接输出该节点,将其出栈,将其设为上一个访问的节点 if((binary_tree_curr->lchild == NULL && binary_tree_curr->rchild == NULL) || (binary_tree_curr != NULL && binary_tree_curr->lchild == binary_tree_pre || binary_tree_curr->rchild == binary_tree_pre)){ cout<<binary_tree_curr->data<<" "; stack.pop(); binary_tree_pre = binary_tree_curr; }else{ //如果不满足上面两种情况,则将其右孩子左孩子依次入栈 if(binary_tree_curr->rchild != NULL){ stack.push(binary_tree_curr->rchild); } if(binary_tree_curr->lchild != NULL){ stack.push(binary_tree_curr->lchild); } } } }
层次遍历
层次遍历是指按照从从上到下,从左到右的顺序对二叉树的每一层进行遍历。思路如下:
对于任何结点P
1)首先将其入队,判断左右结点是否为空,如不是依次入队(先做孩子后右孩子)
2)把队列头元素出队,打印结点
3)重复1),2)两个步骤直至队列为空
代码如下:
//层次遍历 void LevelOrderTraversal(BinaryTree* T){ queue<BinaryTree*> queue; BinaryTree* cur = T; //头结点入队 queue.push(cur); //队列为空时循环结束 while(!queue.empty()){ //队列头元素出队 cur = queue.front(); queue.pop(); cout<<cur->data<<" "; //左孩子不为空入队 if(cur->lchild != NULL){ queue.push(cur->lchild); } //右孩子不为空时入队 if(cur->rchild != NULL){ queue.push(cur->rchild); } } }
整体代码:
#include <iostream>#include <stack> #include <queue>using namespace std;class BinaryTree{ private: char data; BinaryTree* lchild; BinaryTree* rchild; public: //二叉树的初始化函数 BinaryTree* Create_BinaryTree(){ BinaryTree* T = new BinaryTree; char ch; cin>>ch; if(ch == '#'){ //“#”是结束标志 T = NULL; }else{ T->data = ch; //对当前结点初始化 T->lchild = Create_BinaryTree(); //递归构造左子树 T->rchild = Create_BinaryTree(); //递归构造右子树 } return T; } //递归前序遍历 void PreorderTraversal(BinaryTree* T){ if(T == NULL){ return; } cout<<T->data<<" "; //访问根节点并输出 T->PreorderTraversal(T->lchild); //递归前序遍历左子树 T->PreorderTraversal(T->rchild); //递归前序遍历右子树 } //非递归前序遍历 void PreorderTraversal2(BinaryTree* T){ stack<BinaryTree*> stack; //初始化栈 BinaryTree* binary_tree_curr = T; //保存当前结点 //当前结点为空跳出循环 while(binary_tree_curr || !stack.empty()){ cout<<binary_tree_curr->data<<" "; //打印当前结点 stack.push(binary_tree_curr); //当前结点入栈 binary_tree_curr = binary_tree_curr->lchild; //访问左子树 //当前结点为空为空,当前结点出栈 //并把右孩子作为当前结点 while(!binary_tree_curr && !stack.empty()){ binary_tree_curr = stack.top(); stack.pop(); binary_tree_curr = binary_tree_curr->rchild; } } } //递归中序遍历 void InorderTraversal(BinaryTree* T){ if(T == NULL){ return; } T->InorderTraversal(T->lchild); //递归中序遍历左子树 cout<<T->data<<" "; //访问根节点并输出 T->InorderTraversal(T->rchild); //递归中序遍历左子树 } //非递归中序遍历 void InorderTraversal2(BinaryTree* T){ stack<BinaryTree*> stack; //初始化栈 BinaryTree* binary_tree_curr = T; //保存当前结点 while(binary_tree_curr || !stack.empty()){ if(binary_tree_curr->lchild){ //左孩子非空 stack.push(binary_tree_curr); //当前结点入栈 binary_tree_curr = binary_tree_curr->lchild; //遍历左子树 }else{ //左孩子为空,则打印当前结点遍历右子树 cout<<binary_tree_curr->data<<" "; binary_tree_curr = binary_tree_curr->rchild; //如果为空,且栈不空,则将栈顶节点出栈,并输出该节点, //同时将它的右孩子设为当前节点,继续判断,直到当前节点不为空 while(!binary_tree_curr && !stack.empty()){ binary_tree_curr = stack.top(); cout<<binary_tree_curr->data<<" "; stack.pop(); binary_tree_curr = binary_tree_curr->rchild; } } } } //递归后序遍历 void PostorderTraversal(BinaryTree* T){ if(T == NULL){ return; } T->PostorderTraversal(T->lchild); //递归后序遍历左子树 T->PostorderTraversal(T->rchild); //递归后序遍历右子树 cout<<T->data<<" "; //访问并打印根节点 } //非递归后序遍历 void PostorderTraversal2(BinaryTree* T){ stack<BinaryTree*> stack; BinaryTree* binary_tree_curr = T; //当前结点 BinaryTree* binary_tree_pre = NULL; // 上一个结点 //先将树的根节点入栈 stack.push(binary_tree_curr); //直到栈空时,结束循环 while(!stack.empty()){ binary_tree_curr = stack.top(); //当前节点置为栈顶节点 //如果当前节点没有左右孩子,或者有左孩子或有孩子,但已经被访问输出, //则直接输出该节点,将其出栈,将其设为上一个访问的节点 if((binary_tree_curr->lchild == NULL && binary_tree_curr->rchild == NULL) || (binary_tree_curr != NULL && binary_tree_curr->lchild == binary_tree_pre || binary_tree_curr->rchild == binary_tree_pre)){ cout<<binary_tree_curr->data<<" "; stack.pop(); binary_tree_pre = binary_tree_curr; }else{ //如果不满足上面两种情况,则将其右孩子左孩子依次入栈 if(binary_tree_curr->rchild != NULL){ stack.push(binary_tree_curr->rchild); } if(binary_tree_curr->lchild != NULL){ stack.push(binary_tree_curr->lchild); } } } } //层次遍历 void LevelOrderTraversal(BinaryTree* T){ queue<BinaryTree*> queue; BinaryTree* cur = T; //头结点入队 queue.push(cur); //队列为空时循环结束 while(!queue.empty()){ //队列头元素出队 cur = queue.front(); queue.pop(); cout<<cur->data<<" "; //左孩子不为空入队 if(cur->lchild != NULL){ queue.push(cur->lchild); } //右孩子不为空时入队 if(cur->rchild != NULL){ queue.push(cur->rchild); } } } //二叉树的高度 int getBinaryTreeHeight(BinaryTree* T){ if(T){ //递归求左子树高度 int lheight = T->getBinaryTreeHeight(T->lchild); //递归求右子树高度 int rheight = T->getBinaryTreeHeight(T->rchild); //树的高度等于左右子树高度的较大者加1 int height = (lheight>rheight)?lheight:rheight; height++; return height; } return 0; }};int main(){ cout<<"请初始化二叉树:"<<endl; BinaryTree* T; T = T->Create_BinaryTree(); cout<<"前序遍历(递归):"<<endl; T->PreorderTraversal(T); cout<<endl; cout<<"前序遍历(非递归):"<<endl; T->PreorderTraversal2(T); cout<<endl; cout<<"中序遍历(递归):"<<endl; T->InorderTraversal(T); cout<<endl; cout<<"中序遍历(非递归):"<<endl; T->InorderTraversal2(T); cout<<endl; cout<<"后序遍历(递归):"<<endl; T->PostorderTraversal(T); cout<<endl; cout<<"后序遍历(非递归):"<<endl; T->PostorderTraversal2(T); cout<<endl; cout<<"层次遍历:"<<endl; T->LevelOrderTraversal(T); cout<<endl; cout<<"二叉树高度为:" <<endl; cout<<T->getBinaryTreeHeight(T)<<endl; return 0; }
下面的程序结果都是基于如下的二叉树进行的:
截图:
- 二叉树的构建及其遍历算法
- 【数据结构】二叉树的构建及其遍历(C++实现)
- 二叉树及其遍历算法
- 二叉树的前序遍历、中序遍历和后序遍历及其算法
- 二叉树的前序遍历、中序遍历和后序遍历及其算法
- 二叉树的前序遍历、中序遍历和后序遍历及其算法
- 二叉树的前序遍历、中序遍历和后序遍历及其算法
- 二叉树的前序遍历、中序遍历和后序遍历及其算法
- 二叉树遍历&构建
- 二叉树及其遍历
- 二叉树及其遍历
- 二叉树及其遍历
- 二叉树及其遍历
- 二叉树的构建与遍历
- 二叉树的构建及各种遍历
- 二叉树的构建及遍历
- 二叉树的构建和遍历
- java二叉树的构建以及遍历
- 01Two Sum
- Java IO流学习总结
- 2表联合查询
- XYNUOJ 1106 1107 求最大公约数 求最小公倍数
- 设置logo和背景以及语言包切换
- 二叉树的构建及其遍历算法
- POJ 1182 食物链(并查集 带权路径)
- Redis错误及解决方案
- android studio 创建aidl
- C#设计模式(4)——观察者模式(Observer Pattern)
- java实现基础数据类型中二进制位操作算法
- 爬虫学习(一):爬取写真网
- TortoiseGit安装和使用的图文教程
- PSAM