数据结构12————二叉树的遍历和建立
来源:互联网 发布:网络借贷管理办法 编辑:程序博客网 时间:2024/06/11 10:19
数据结构12————二叉树的遍历和建立
一.内容
1.二叉树遍历的概念
2.二叉树的遍历 使用递归实现
3.二叉树的遍历 使用栈实现
4.二叉树的建立
5.二叉树遍历的应用
所以代码只是核心函数,完整代码见末尾链接
注意本篇博客都是基于二叉链表的实现
二.二叉树遍历的概念
如果我们要求次序的不重复的,遍历一颗树,并且限制从左到右习惯方式,一共有4种不同遍历方法。
1.层次遍历
按照二叉树的层,一层一层的访问。
例:对于二叉树T而言,它的层次遍历序列为ABCDEFG
2.前序遍历
对于一颗二叉树
- 先访问根节点
- 前序遍历左子树(按照前序遍历规则访问左子树,即先访问左子树的根,然后继续遍历它的左右子树,下同)
- 前序遍历右子树
例:对于二叉树T而言,它的前序遍历序列为ABDGCEF
3.中序遍历
对于一颗二叉树- 中序遍历它的左子树
- 访问它的根节点
- 中序遍历它的右子树
例:对于二叉树T而言,它的中序遍历序列为DGBAECF
4.后序遍历
对于一颗二叉树- 后序遍历它的左子树
- 后序遍历它的右子树
- 访问根节点
例:对于二叉树T而言,它的后序遍历序列为GDBEFCA
三.二叉树的遍历 递归实现
其实根据上面的前中后序遍历规则,基本来说就可以确定递归的写法了,不过要增加一个递归出口。当前指针为NULL时,结束。1.前序遍历
void PreOrder(BiTree root){ int static count; if(root==NULL) return; printf("%c",root->data); PreOrder(root->lChild); PreOrder(root->rChild);}
2.中序遍历
void InOrder(BiTree root){ if(root==NULL) return; InOrder(root->lChild); printf("%c",root->data); InOrder(root->rChild);}
3.后序遍历
void PostOrder(BiTree root){ if(root==NULL) return; PostOrder(root->lChild); PostOrder(root->rChild); printf("%c",root->data);}
4.层次遍历
对于层次遍历而言,不能使用递归来进行遍历。要使用队来进行。(类似于图的广度优先遍历)以树T为例
先将A入队 队内元素A 遍历序列为空
将队首A出队,访问,入队A的左右子树,队内元素BC,遍历序列A
将队首B出队,访问,入队B的左右子树,队内元素CD,遍历序列AB
将队首C出队,访问,入队C的左右子树,队内元素DEF,遍历序列ABC
将队首D出队,访问,入队D的左右子树, 队内元素EFG,遍历序列ABCD
将队首E出队,访问,入队E的左右子树, 队内元素FG,遍历序列ABCDE
将队首F出队,访问,入队F的左右子树, 队内元素G,遍历序列ABCDE
将队首G出队,访问,入队G的左右子树, 队内元素空,遍历序列ABCDEFG
队空,结束
void levelOrder(BiTree root){ BiTree p=root; CSeQeue *S; S=InitSeQueue();//创建队 InSeQueue(S,p);//入队 while(!EmptySeQueue(S)){ QutSeQueue(S,&p);//出队 printf("%c",p->data); if(p->lChild!=NULL) InSeQueue(S,p->lChild);//入队 if(p->rChild!=NULL) InSeQueue(S,p->rChild);//入队 }}
三.二叉树的遍历 栈实现
1.前序遍历
对于前序遍历而言,使用栈来实现,和递归很像 规则,- 先访问根节点,然后将根节点入栈
- 遍历左子树。遍历完之后,
- 出栈,获得右子树指针,遍历它的右子树
以树T为例:(可以自己根据代码走一遍)
访问A节点,入栈,栈内元素A,遍历序列A
访问A节点的左子树B,B入栈,栈内元素AB,遍历序列AB
访问B节点的左子树D,D入栈,栈内元素ABD,遍历序列ABD
访问D节点的左子树,左子树为空,左子树的访问完毕,出栈栈顶D,栈内元素AB,遍历序列为ABD
访问D节点的右子树G,G入栈,栈内元素ABG,遍历序列ABDG
访问G节点的左子树,左子树为空,出栈栈顶G,栈内元素AB,遍历序列ABDG
访问G节点的右子树,右子树为空,出栈栈顶B,栈顶元素A,遍历序列为ABDG
访问B节点的右子树,右子树为空,出栈栈顶A,栈内元素空,遍历序列ABDG
访问A节点的右子树C,C入栈,栈内元素C,遍历序列ABDGC
……
最后当需要出栈是,栈为空,则表示遍历完成
void PreOrder(BiTree root){ BiTree p; SeqStack *S; S = InitStack(); p = root; while(p!=NULL||StackEmpty(S)==0){ while(p!=NULL){ printf("%c",p->data); Push(S,p); //入栈 p=p->lChild; //遍历左子树 } if(StackEmpty(S)==0){ Pop(S,&p);//出栈 p=p->rChild; //遍历右子树 } } }
2.中序遍历
和前序遍历类似。- 先入栈,遍历它的左子树 左子树遍历完之后
- 出栈,访问根节点,
- 遍历右子树
void InOrder(BiTree root){ BiTree p; SeqStack *S; S = InitStack(); p = root; while(p!=NULL||StackEmpty(S)==0){ while(p!=NULL){ Push(S,p); //入栈 p=p->lChild; //遍历左子树 } if(StackEmpty(S)==0){ Pop(S,&p);//出栈 printf("%c",p->data); p=p->rChild; //遍历右子树 } } }
3.后序遍历
和前序中序遍历不同,后序遍历稍微麻烦些,因为涉及到两次访问栈顶
- 先入栈,,遍历左子树,左子树遍历完之后
- 访问栈顶(不出栈) 得到右子树指针,遍历右子树,右子树遍历完之后
- 出栈栈顶元素,访问根节点
void PostOrder(BiTree root){ BiTree p,q; SeqStack *S; S = InitStack(); q = NULL; p = root; while(p!=NULL||StackEmpty(S)==0){ while(p!=NULL){ //出循环时p左子树为空 Push(S,p); //入栈 p=p->lChild; //遍历左子树 } if(StackEmpty(S)==0){ GetTop(S,&p); if(p->rChild==NULL||p->rChild==q){ //如果栈顶元素p右子树为空,或者上一步输出的是他的右子树 Pop(S,&p); printf("%c",p->data); q=p; p=NULL; }else{ //如果上一步访问是栈顶元素的左子树 p=p->rChild; } } }}
四.二叉树的建立
单独一个遍历序列是无法唯一确定一颗二叉树的,想要根据遍历序列确定一颗二叉树,只有两种方法,一种是根据扩展的遍历序列,一种是根据中序遍历序号和前序(中序)遍历序列。所以我们二叉树的创建就是根据这两种思路来进行的。 我们以扩展的先序遍历序列和先序+中序遍历序列为例创建二叉树
1.根据扩展的先序序列创建二叉树.
a. 扩展的先序序列
扩展的先序序列,就是将二叉树节点的左右空子树也用特殊符号表示出来。
比如树T的扩展序列为ABD^G^^^CE^^F^^
b. 代码
BiTree CreatBiTree(BiTree root){ //二叉树的建立(由扩展的先序序列建立的二叉树) static int count; char ch=str[count]; count++; if(ch=='#') return NULL; root = (BiTNode *)malloc(sizeof(BiTNode)); root->data = ch; root->lChild = CreatBiTree(root->lChild);//以当前节点的左指针为下一级二叉树的跟 root->rChild = CreatBiTree(root->rChild);//以当前节点的右指针为下一级二叉树的跟 return root;}
2.根据先序和中序序列创建二叉树
思路,根据先序序列确定根,根据中序序列确定根节点的左右子树。然后根据先序序列确定左右子树的根节点,根据中序序列确定左右子树的左右子树….
BiTree CreatBiTree(char *frontArray,char *centreArray,int n){ BiTree root; char lfArray[N],rfArray[N]; char lcArray[N],rcArray[N]; int ln,rn,i,j; char ch; if(n==0) return NULL; ch = frontArray[0]; root = (BiTNode *)malloc(sizeof(BiTNode)); root->data = ch; for(i=0;centreArray[i]!=ch;i++){ //左子树的后序 lcArray[i] = centreArray[i]; } ln=i; i++; for(rn=0;i<n;rn++,i++){ //右子树的后序 rcArray[rn] = centreArray[i]; } for(i=0;i<ln;i++){ //左子树的先序 lfArray[i] = frontArray[i+1]; } for(j=0;j<rn;j++,i++){ //右子树的先序 rfArray[j]=frontArray[i+1]; } root->lChild = CreatBiTree(lfArray,lcArray,ln);//以当前节点的左指针为下一级二叉树的跟 root->rChild = CreatBiTree(rfArray,rcArray,rn);//以当前节点的右指针为下一级二叉树的跟 return root;}
五.二叉树的遍历的应用
1. 节点及所在层次
void PreOrder(BiTree root){ //先序遍历输出加层次 int static count; if(root==NULL) return; count++; printf("(%c,%d)",root->data,count); PreOrder(root->lChild); PreOrder(root->rChild); count--;}
2. 某层叶子节点个数
int f1(BiTree root,int k){ int static countlevel; int static countleaf; if(root==NULL) return; countlevel++; if(countlevel == k&&root->lChild==NULL&&root->rChild==NULL) countleaf++; f1(root->lChild,k); f1(root->rChild,k); countlevel--; return countleaf;}
3. 交换左右子树
void exchange(BiTree root){ //交换各节点的左右子树 BiTree t; if(root==NULL) return; t=root->lChild; root->lChild=root->rChild; root->rChild=t; exchange(root->lChild); exchange(root->rChild);}
4. 根节点到叶子节点的路径
void PreOrder(BiTree root){ int static count; int i; if(root==NULL) return; count++; if(root->lChild==NULL&&root->rChild==NULL){ printf("%c:",root->data); for(i=1;i<count;i++){ printf("%c",array[i]); } printf("\n"); }else{ array[count]=root->data; } PreOrder(root->lChild); PreOrder(root->rChild); count--;}
5. 两个节点的共同祖先
int count; int flag; //标记是否找到 void PreOrder(BiTree root,char ch,char *array){ if(root==NULL) return ; count++; if(root->data==ch){ flag = 1; array[count]=0; return ; }else if(flag ==0&&root!=NULL){ array[count]=root->data; } if(flag==0){ PreOrder(root->lChild,ch,array); PreOrder(root->rChild,ch,array); } count--; return;}
在text12中
- 数据结构12————二叉树的遍历和建立
- 数据结构——二叉树的建立和遍历(递归建树&层序遍历建树)
- 数据结构(十一)——二叉树的遍历和建立
- 数据结构(十一)——二叉树的遍历和建立
- 数据结构——二叉树的创建和遍历
- 基本数据结构——二叉树的建立,遍历,求叶子节点,深度计算
- 数据结构——二叉树的遍历
- 数据结构——二叉树的遍历
- 数据结构——二叉树的遍历
- 数据结构——二叉树的遍历
- 数据结构——二叉树的遍历
- 数据结构——二叉树的遍历
- 数据结构二叉树——建立二叉树、中序递归遍历、非递归遍历、层次遍历
- 数据结构:二叉树的建立和遍历(C#实现)
- 数据结构之二叉树的递归建立和遍历
- 数据结构之二叉树的递归建立和遍历(续)
- 【数据结构基础】二叉树的建立和递归遍历
- 常用数据结构-二叉树的链式存储、建立和遍历
- 关于android中的两大布局LinearLayout、RelativeLayout
- Tensorflow 读取Txt和Csv格式数据
- 130. Surrounded Regions
- 238. Product of Array Except Self
- Windows物理磁盘扇区读写示例总结
- 数据结构12————二叉树的遍历和建立
- 序列有关BIF
- Hdoj 5702 Solving Order
- 为什么C++11引入了std::ref?
- Java知识点复习系列(5)
- 区块链技术的应用场景与常见疑问
- 740. Delete and Earn
- python 中TCP协议
- 剑指offer 矩阵中的路径