二叉树的先/中/后序遍历
遍历:按照某种次序把所有结点都访问一遍
- 先序遍历:根左右(NLR)
- 中序遍历:左根右(LNR)
- 后序遍历:左右根(LRN)
eg:
代码实现
typedef struct BiTNode{
ElemType data;
struct BiTNode *lchild, *rchild;
}BiTNode, *BiTree;
//遍历条件:
//1)若二叉树为空,则什么都不做
//2)若二叉树非空,则按对应的遍历规则进行遍历
//先序遍历:空间复杂度:O(h)
void PreOrder(BiTree T){
if(T != NULL){// 如果二叉树非空
visit(T);//访问根结点(可以做一些打印这个结点的值等等的操作)
PreOrder(T->lchild); //递归遍历左子树
PreOrder(T->rchild); //递归遍历右子树
}
}
//中序遍历
void InOrder(BiTree T){
if(T != NULL){// 如果二叉树非空
InOrder(T->lchild); //递归遍历左子树
visit(T);//访问根结点
InOrder(T->rchild); //递归遍历右子树
}
}
//后序遍历
void PostOrder(BiTree T){
if(T != NULL){// 如果二叉树非空
PostOrder(T->lchild); //递归遍历左子树
PostOrder(T->rchild); //递归遍历右子树
visit(T);//访问根结点
}
}
//求树的深度(应用)
int treeDepth(BiTree T){
if(T == NULL) return 0;
else{
int l = treeDepth(T->lchild);
int r = treeDepth(T->rchild);
//树的深度=MAX(l r)+1
return l>r ? l+1 :r+1;
}
}
二叉树的层序遍历
也就是一层一层的遍历一个二叉树
算法思想:
- 初始化一个辅助队列
- 根结点入队
- 若队列非空,则队头结点出队,访问该结点,并将其左、右孩子插入队尾(如果有的话)
代码实现:
//---------结构定义
typedef struct BiTNode{
char data;
struct BiTNode *lchild, *rchild;
}BiTNode, *BiTree;
typedef struct LinkNode{
BiTNode * data;
struct LinkNode *next;
}LinkNode;
typedef struct{
LinkNode *front, *rear; //队头队尾指针
}LinkQueue;
//层序遍历
void LevelOrder(BiTree T){
LinkQueue Q; //链队列
InitQueue(Q); //初始化辅助队列
BiTree p;
EnQueue(Q,T); //将根结点入队
while(!IsEmpty(Q)){//队列非空则循环
DeQueue(Q, p); //队头结点出队
visit(p); //访问出队结点
if(p->lchild != NULL)
EnQueue(Q, p->lchild); //左孩子入队
if(p->rchild != NULL)
EnQueue(Q, p->rchild); //右孩子入队
}
}
由遍历序列构造二叉树
若只给出一棵二叉树的前/中/后层序遍历层序中的一种,不能唯一确定一棵二叉树。
线索二叉树
//-----线索二叉树的存储结构
typedef struct ThreadNode{ // 线索链表
ElemType data;
struct ThreadNode *lchild, *rchild;
int ltag, rtag; //左,右线索标志
// tag == 0 : 表示指针指向孩子
// tag == 1 : 表示指针是"线索"
}ThreadNode, *ThreadTree;
二叉树线索化
typedef struct ThreadNode{
ElemType data;
struct ThreadNode *lchild, *rchild;
int ltag, rtag; //左右线索标记
}ThreadNode, *ThreadTree;
//全局变量pre,指向当前访问结点的前驱
ThreadNode *pre = NULL;
//中序线索化二叉树T
void CreateInThread(ThreadTree T){
pre = NULL; //初始为NULL
if(T != NULL){ //非空二叉树才能线索化
InThread(T); //中序线索化二叉树
if(pre->rchild == NULL)
pre->rtag = 1; //处理遍历的最后一个结点
}
}
//中序遍历二叉树,一边遍历一边线索化
void InThread(ThreadTree T){
if(T != NULL){
InThread(T->lchild);
visit(T);
InThread(T->rchild);
}
}
void visit(ThreadNode *q){
if(q->lchild == NULL){ //左子树为空,建立前驱线索
q->lchild = pre;
q->ltag = 1;
}
if(pre != NULL && pre->rchild == NULL){
pre->rchild = q; //建立前驱结点的后续线索
pre->rtag = 1;
}
pre = q;
}
线索二叉树找前驱/后继
- 中序线索二叉树
//中序线索二叉树找中序后继
//找到以p为根的子树中,第一个被中序遍历的结点
ThreadNode *Firstnode(ThreadNode *p){
//循环找到最左下结点(不一定是叶子结点)
while(p->ltag == 0) p = p->lchild;
return p;
}
//在中序线索二叉树中找到结点p的后继结点
ThreadNode *Nextnode(ThreadNode *p){
//右子树中最左下结点
if(p->rtag == 0) return Firstnode(p->rchild);
else return p->rchild; //rtag==1直接返回后继结点
}
//对中序线索二叉树进行中序遍历(利用线索实现的非递归算法)
//空间复杂度O(1)
void Inorder(ThreadNode *T){
for(ThreadNode *p=Firstnode(T);p!=NULL;p=Nextnode(p))
visit(p);
}
//中序线索二叉树找中序前驱
//找到以p为根的子树中,最后一个被中序遍历的结点
ThreadNode *Lastnode(ThreadNode *p){
//循环找到最右下结点(不一定是叶结点)
while(p->rtag == 0) p = p->rchild;
return p;
}
//在中序线索二叉树中找到结点p的前驱结点
ThreadNode *Prenode(ThreadNode *p){
//左子树中最右下结点
if(p->ltag == 0) return Lastnode(p->lchild);
else return p->lchild;
}
//对中序线索二叉树进行逆向中序遍历
void RevInorder(ThreadNode *T){
for(ThreadNode *p=Lastnode(T);p!=NULL;p=Prenode(p))
visit(p);
}