目录
遍历二叉树:
定义:
遍历方法:
重点研究前三种,因为前三种和后三种是对称的,所以只要会了前三种,后三种也就会了。
DLR——先(根)序遍历
LDR——中(根)序遍历
LRD——后(根)序遍历
遍历算法描述:
由二叉树得到遍历序列:
先序遍历二叉树的操作:
中序遍历二叉树的操作:
后序遍历二叉树的操作:
例题:
1.
2.用二叉树表示算术表达式:
由遍历序列确定二叉树:
已知先序序列和中序序列求二叉树:
先序序列的第一个一定是根。
步骤:
已知后序序列和中序序列求二叉树:
后序序列的最后一个一定是根。
遍历的算法实现(递归与非递归):
先序遍历算法(递归算法):
中序遍历算法(递归算法):
中序遍历算法(非递归算法):
步骤:
A、B先依次进栈
访问到 B 的左子树为空,则访问 B,B 出栈,B 的右子树也为空,则 D 进栈
访问 D 的左子树,为空,则访问 D ,D 出栈,访问D 的右子树,为空,返回到 A
访问 A , A 出栈,接着C进栈
访问 C 的左子树,为空,C出栈,访问 C 的右子树为空,最后返回,此时栈为空
后序遍历算法(递归算法):
遍历算法的分析:
可以看到,如果去掉输出语句,从递归的角度看,三种算法是完全相同的,或者说这三种算法的访问路径是相同的,只是访问结点的时机不同。
如图所示:
时间复杂度都为O(n)。(都要沿着虚线走一遍,每个结点都访问并且只访问一次)
空间复杂度为O(n)。(最坏情况下,即单支情况下;栈占用的最大辅助空间)
二叉树的层次遍历:
如图:
算法思路(队列):
层次遍历算法实现:
步骤:
首先先让根结点a入队
将根结点a出队,同时让它的左右孩子b和f入队
将对头元素b出队,同时让它的左右孩子c和d入队
将对头元素f出队,同时让它的左孩子g入队(因其没有右孩子)
将对头元素c出队,因其没有左右孩子。所以不进行入队操作
将对头元素d出队,同时让它的左孩子e入队(因其没有右孩子)
将对头元素g出队,同时让它的右孩子h入队(因其没有左孩子)
将对头元素e出队,因其没有左右孩子。所以不进行入队操作
将对头元素h出队,因其没有左右孩子。所以不进行入队操作
此时队列为空,不能再进行出队操作,所以当前的层次遍历结束。
实现:
层次遍历也可以用栈来实现,但是比这个要麻烦。
二叉树遍历算法的应用:
应用1:
.按先序遍历序列建立二叉树的二叉链表
我们可以看到如果我们直接输入ABCDEFG的话,它的树型结构是不唯一的。
解决方法:补充空结点
如:
代码实现:
#include<iostream>
#include<string>
using namespace std;
#define OK 1
#define OVERFLOW -2
#define MAXSIZE 100
typedef char Status;
//定义
typedef struct BiNode
{
char data;
struct BiNode *lchild,*rchild;//左右孩子指针
}BiNode,*BiTree;
Status Create(BiTree &T);//建立二叉树
Status PreOrder(BiTree T);//按先序遍历输出
Status InOrder(BiTree T);//按中序遍历输出
Status PostOrder(BiTree T);//按后序遍历输出
int main()
{
BiTree T;
cout<<"二叉树创建成功"<<Create(T)<<endl;
//函数调用
cout<<"按先序遍历输出:";
PreOrder(T);
cout<<endl;
cout<<"按中序遍历输出:";
InOrder(T);
cout<<endl;
cout<<"按后序遍历输出:";
PostOrder(T);
cout<<endl;
return 0;
}
//建立二叉树
Status Create(BiTree &T)
{
char ch;
cin>>ch;
if(ch=='#')
T=NULL;
else
{
if(!(T=new BiNode))
exit(OVERFLOW);
T->data=ch;
Create(T->lchild);//递归构造左子树
Create(T->rchild);//递归构造右子树
}
return OK;
}
//按先序遍历输出
Status PreOrder(BiTree T)
{
if(T==NULL) return OK;
else
{
cout<<T->data;
PreOrder(T->lchild);//递归遍历左子树
PreOrder(T->rchild);//递归遍历右子树
}
}
//按中序遍历输出
Status InOrder(BiTree T)
{
if(T==NULL) return OK;
else
{
InOrder(T->lchild);//递归遍历左子树
cout<<T->data;
InOrder(T->rchild);//递归遍历右子树
}
}
//按后序遍历输出
Status PostOrder(BiTree T)
{
if(T==NULL) return OK;
else
{
PostOrder(T->lchild);//递归遍历左子树
PostOrder(T->rchild);//递归遍历右子树
cout<<T->data;
}
}
运行结果:
应用2:
《1》复制二叉树
代码实现(以上图中的树为例):
#include<iostream>
#include<string>
using namespace std;
#define OK 1
#define OVERFLOW -2
#define MAXSIZE 100
typedef char Status;
//定义
typedef struct BiNode
{
char data;
struct BiNode *lchild,*rchild;//左右孩子指针
}BiNode,*BiTree;
Status Create(BiTree &T);//建立二叉树
Status Copy(BiTree T,BiTree &NewT);//复制二叉树
Status PreOrder(BiTree T);//按先序遍历输出
int main()
{
BiTree T,NewT;
cout<<"二叉树创建成功"<<Create(T)<<endl;
//函数调用
Copy(T,NewT);
cout<<"按先序遍历输出新二叉树:";
PreOrder(NewT);
cout<<endl;
return 0;
}
//建立二叉树
Status Create(BiTree &T)
{
char ch;
cin>>ch;
if(ch=='#')
T=NULL;
else
{
if(!(T=new BiNode))
exit(OVERFLOW);
T->data=ch;
Create(T->lchild);//递归构造左子树
Create(T->rchild);//递归构造右子树
}
return OK;
}
//复制二叉树
Status Copy(BiTree T,BiTree &NewT)
{
if(T==NULL)
{
NewT=NULL;
return 0;
}
else
{
NewT=new BiNode;
NewT->data=T->data;
Copy(T->lchild,NewT->lchild);//复制左子树
Copy(T->rchild,NewT->rchild);//复制右子树
}
}
//按先序遍历输出
Status PreOrder(BiTree NewT)
{
if(NewT==NULL) return OK;
else
{
cout<<NewT->data;
PreOrder(NewT->lchild);//递归遍历左子树
PreOrder(NewT->rchild);//递归遍历右子树
}
}
运行结果:
《2》计算二叉树深度
代码实现(以《1》中的树为例):
#include<iostream>
#include<string>
using namespace std;
#define OK 1
#define OVERFLOW -2
#define MAXSIZE 100
typedef char Status;
//定义
typedef struct BiNode
{
char data;
struct BiNode *lchild,*rchild;//左右孩子指针
}BiNode,*BiTree;
Status Create(BiTree &T);//建立二叉树
int Depth(BiTree T);//计算树的深度
int main()
{
BiTree T,NewT;
cout<<"二叉树创建成功"<<Create(T)<<endl;
//函数调用
cout<<"树的深度:"<<Depth(T);
return 0;
}
//建立二叉树
Status Create(BiTree &T)
{
char ch;
cin>>ch;
if(ch=='#')
T=NULL;
else
{
if(!(T=new BiNode))
exit(OVERFLOW);
T->data=ch;
Create(T->lchild);//递归构造左子树
Create(T->rchild);//递归构造右子树
}
return OK;
}
//计算树的深度
int Depth(BiTree T)
{
int m,n;
if(T==NULL)//如果为空树返回0
return 0;
else
{
m=Depth(T->lchild);
n=Depth(T->rchild);
if(m>n)
return (m+1);
else
return (n+1);
}
}
运行结果:
《3》计算二叉树的结点总数
代码实现(以上图中的树为例):
#include<iostream>
#include<string>
using namespace std;
#define OK 1
#define OVERFLOW -2
#define MAXSIZE 100
typedef char Status;
//定义
typedef struct BiNode
{
char data;
struct BiNode *lchild,*rchild;//左右孩子指针
}BiNode,*BiTree;
Status Create(BiTree &T);//建立二叉树
int NodeCount(BiTree T);//计算二叉树的结点总数
int main()
{
BiTree T,NewT;
cout<<"二叉树创建成功"<<Create(T)<<endl;
//函数调用
cout<<"该树的结点总数为:"<<NodeCount(T)<<endl;
return 0;
}
//建立二叉树
Status Create(BiTree &T)
{
char ch;
cin>>ch;
if(ch=='#')
T=NULL;
else
{
if(!(T=new BiNode))
exit(OVERFLOW);
T->data=ch;
Create(T->lchild);//递归构造左子树
Create(T->rchild);//递归构造右子树
}
return OK;
}
//计算二叉树的结点总数
int NodeCount(BiTree T)
{
if(T==NULL)
return 0;
else
{
return NodeCount(T->lchild)+NodeCount(T->rchild)+1;
}
}
运行结果:
《4》计算二叉树叶子结点数
代码实现(以《3》中的树为例):
#include<iostream>
#include<string>
using namespace std;
#define OK 1
#define OVERFLOW -2
#define MAXSIZE 100
typedef char Status;
//定义
typedef struct BiNode
{
char data;
struct BiNode *lchild,*rchild;//左右孩子指针
}BiNode,*BiTree;
Status Create(BiTree &T);//建立二叉树
int LeadCount(BiTree T);//计算二叉树的叶子结点数
int main()
{
BiTree T,NewT;
cout<<"二叉树创建成功"<<Create(T)<<endl;
//函数调用
cout<<"该树的叶子结点数为:"<<LeadCount(T)<<endl;
return 0;
}
//建立二叉树
Status Create(BiTree &T)
{
char ch;
cin>>ch;
if(ch=='#')
T=NULL;
else
{
if(!(T=new BiNode))
exit(OVERFLOW);
T->data=ch;
Create(T->lchild);//递归构造左子树
Create(T->rchild);//递归构造右子树
}
return OK;
}
//计算二叉树的叶子结点数
int LeadCount(BiTree T)
{
if(T==NULL)//如果是空树返回0
return 0;
else if(T->lchild==NULL&&T->rchild==NULL)
return 1;//如果是叶子结点返回1
else
{
return LeadCount(T->lchild)+LeadCount(T->rchild);
}
}
运行结果:
线索二叉树:
引入:
定义:
利用二叉链表中的空指针域:
举例:
优化:
线索二叉树的分类:
进一步优化: