数据结构复习总结:遍历二叉树及其应用(必考)

遍历二叉树及其应用

(非递归算法不考!!!)

二叉树的遍历是指从根结点出发,按照某种次序依次访问二叉树中的所有结点,使得每个结点被访问一次且仅被访问一次。

二叉树的遍历算法:

1. 前序遍历

若二叉树为空树,则空操作;否则,

(1)访问根结点;

(2)先序遍历左子树;

(3)先序遍历右子树。

在这里插入图片描述

遍历的顺序为:ABDGHCEIF

递归实现:
void PreOrderTraverse(BiTree T)
{ 
	if(T==NULL)
		return;
	printf("%c",T->data);		
	PreOrderTraverse(T->lchild); //再先序遍历左子树
	PreOrderTraverse(T->rchild); //最后先序遍历右子树
}
非递归实现:
  1. 建立栈,并初始化。

  2. 若遍历结点存在或者栈不为空

    (1) 若结点存在:访问结点,结点入栈,指向其左孩子。

    (2)否则:出栈,指向其右孩子。

    1. 否则,遍历结束。
void PreOrderTraverse(BiTree root)
{
	SqStack S;
	InitStack(S);
	BiTree *p;
	p = root;
	while(p||!StatckEmpty(S)){
		if(p)
		{
			printf("%c",p->data); //访问根结点
			Push(S,p); //保存根结点
			p=p->lchild; //遍历左子树
		}
		else
		{
			Pop(S,p); //弹出根结点
			p=p->rchild; //遍历右子树
		}
	}
}

2. 中序遍历

若二叉树为空树,则空操作;否则,

(1)中序遍历左子树;

(2)访问根结点;

(3)中序遍历右子树。

在这里插入图片描述

遍历顺序为:GDHBAEICF

递归实现:
void InOrderTraverse(BiTree T)
{ 
	if(T==NULL)
		return;
	InOrderTraverse(T->lchild); 
	printf("%c",T->data);		
	InOrderTraverse(T->rchild); 
}
非递归实现:
  1. 建立栈,并初始化。

  2. 若遍历结点存在或者栈不为空

    (1) 若结点存在:结点入栈,指向其左孩子。

    (2)否则:出栈,访问结点,指向其右孩子。

    1. 否则,遍历结束。
void InOrderTraverse(BiTree root)
{
	SqStack S;
	InitStack(S);
	BiTree *p;
	p = root;
	while(p||!StatckEmpty(S)){
		if(p)
		{
			Push(S,p); //保存根结点
			p=p->lchild; //遍历左子树
		}
		else
		{
			Pop(S,p); //弹出根结点
			printf("%c",p->data); //访问根结点
			p=p->rchild; //遍历右子树
		}
	}
}

3. 后序遍历

若二叉树为空树,则空操作;否则,

(1)后序遍历左子树;

(2)后序遍历右子树;

(3)访问根结点。

在这里插入图片描述

遍历顺序为:GHDBIEFCA

递归实现:
void PostOrderTraverse(BiTree T)
{
	if(T==NULL)
		return;
	PostOrderTraverse(T->lchild); 	
	PostOrderTraverse(T->rchild); 	
	printf("%c",T->data);			
}
非递归实现:

弹出条件

	1. 判断刚访问过的结点q是不是当前栈顶结点p的右孩子。
	2. p的右孩子为空。
void PostOrderTraverse(BiTree root)
{ 
	InitStack(S);
	BiTree *p=T,*q; // r标记最近访问过的结点
	p = root;
	q = NULL;
	while(p||!StatckEmpty(S)){
		if(p){
			Push(S,p);  // 一直向左走,左孩子入栈
			p=p->lchild;
		}
		else{
			GetTop(S,p);
			if(p->rchild && p->rchild!=q){ // 若右孩子存在且未被访问
				p=p->rchild;  // 就让右孩子
				push(S,p)  // 入栈
				p=p->lchild;  // 让右孩子向左
				//上面三句意思就是让右孩子的左孩子一直入栈,一直向左走
			}
			else{
				pop(s,p);  // 右孩子为空或未被访问过,就出栈
				visit(p->data);
				q=p;  // q标记最近访问结点
				p=NULL;
			}
		}
	}
}

4. 层序遍历

若二叉树为空树,则空操作;否则,从树的第一层,也就是根结点开始访问,从上而下逐层遍历,在同一层中,按从左到右的顺序对节点逐个访问。

在这里插入图片描述

遍历顺序为:ABCDEFGHI

队列实现:

先根结点入队,然后:

	1. 从队列中取出一个元素;
	2. 访问该元素所指结点;
	3. 若该元素所指结点的左右孩子结点非空,则将其左右孩子顺序入队。
void LevelorderTraverse ( BiTree root) {      
    Queue Q;      
    BiTree T;     
    if (!root) 
        return;  /* 若是空树则直接返回 */          
    InitQueue(Q); /* 创建空队列Q */  
    EnQueue(Q,root);     
    while (!IsEmpty(Q)) 
    {         
        DeQueue(Q,T);         
        printf("%d ", T->Data); /* 访问取出队列的结点 */         
        if ( T->lchild )   
            EnQueue(Q, T->lchild);      
        if ( T->rchild )  
            EnQueue(Q, T->rchild);  
        }
    } 
}

二叉树的恢复:(必考)

1. 由先序和中序序列恢复二叉树

二叉树的先序序列:根—>左子树—>右子树

二叉树的中序序列:左子树—>根—>右子树

(1)由先序序列的第一个结点确定根结点D。

(2)通过根结点D分割中序序列:D之前是左子树的中序序列,D之后是右子树的中序序列,同时获得左右子树的结点个数。

(3)根据左子树的结点个数,分割先序序列:第一结点根D,之后是左子树的先序序列,最后是右子树的先序序列。

在这里插入图片描述

2. 由中序和后序序列恢复二叉树

二叉树的中序序列:左子树—>根—>右子树

二叉树的后序序列:左子树—>右子树—>根

同理:

在这里插入图片描述

二叉树遍历的应用:

1. 统计叶子结点的数目:

解法1:

在这里插入图片描述

int LeafCount = 0;
void LeafNum(BiTree root){
	if(root!=NULL){
		if(root->lchild==NULL&&root->rchild==NULL){
			LeafCount++;
		}
        LeafNum(root->lchild);
        LeafNum(root->rchild);
	}
}
解法2:

在这里插入图片描述

int Leaf(BiTree root){
	int LeafCount;
	if(root==NULL)
		LeafCount=0;
	else if(root->lchild==NULL&&root->rchild==NULL){
		LeafCount=1;
	}
	else
		LeafCount=leaf(root->lchild)+leaf(root->rchild);
	return 1;
}
拓展:
统计二叉树中度为1的结点个数:
(root->lchild==NULL&&root->rchild!=NULL)||(root->lchild!=NULL&&root->rchild==NULL)
统计二叉树中度为2的结点个数:
root->lchild!=NULL&&root->rchild!=NULL
统计二叉树中结点值为x的结点个数:
root->data == x

2. 计算二叉树的高度:

二叉树的高度:二叉树中所有结点层次的最大值

解法1:

在这里插入图片描述

int depth = 0; 
void PreTreeDepth(BiTree root,int h){
	if(root!=NULL){
		if(h>depth)
			depth = h;
		PreTreeDepth(root->lchild,h+1);
		PreTreeDepth(root->rchild,h+1);
	}
}
解法2:

在这里插入图片描述

int PostTreeDepth(BiTree root){
	int hl,hr,max;
	if(root!=NULL){
		hl=PostTreeDepth(root->lchild);
		hr=PostTreeDepth(root->lchild);
		max=hl>hr?hl:hr;
			return max+1;
	}
	else
		return 0;
}

2. 计算二叉树的最大宽度:(利用层序遍历法)

int WidthCount ( BiTree root) {      
    Queue Q;      
    BiTree T;     
    if (!root) 
        return;  /* 若是空树则直接返回 */          
    InitQueue(Q); /* 创建空队列Q */  
    int width = 0;
    int num = 1;
    int max = 0;
    EnQueue(Q,root);     
    while (!IsEmpty(Q)) 
    {         
        DeQueue(Q,T);         
        printf("%d ", T->Data); /* 访问取出队列的结点 */         
        if ( T->lchild )   
            EnQueue(Q, T->lchild); width++;        
        if ( T->rchild )  
            EnQueue(Q, T->rchild); width++;  
        if(--num == 0){
            num = witdh;
            if(max < width){
                max = width;
            }
            width = 0;
        }
    } 
    return max;
}

二叉树的繁茂度:

int Lushdeg(BiTree root){
	return PostTreeDepth(root)*WidthCount(root) ; //繁茂度=高度*最大宽度
}

3. 交换左右子树

void reChange(BiTree root){
	if(root == NULL) return;
	if(root){
		Bitree temp = root->lchild;
		root->lchild = root->rchild;
		root->rchild = temp;
		reChange(root->lchild);
		reChange(root->rchild);
	}
}

4. 判断二叉树是否为平衡二叉树

bool isAVL (BiTree root){
    if(root){
        int l = PreTreeDepth(root->lchild);
        int r = PreTreeDepth(root->rchild);
        if(abs(l-r)!=1)	return false;
    }
    return true;
}

5. 根结点到叶子结点的路径

void RouteToRoot(BiTree root) {
    if (root) {
        SqStack stack;
		InitStack(stack)
        push(stack, root->data); //只要root不为空,就将root的值入栈
        
        if (!root->left_child&&!root->right_child)
            printStack(stack);
        else { 
            RouteToRoot(root->lchild, stack); 
            RouteToRoot(root->rchild, stack);
        }
        pop(stack);
    }
}

6. 判断二叉树是否为严格二叉树

bool isStrict (BiTree root){
	if(!root)
		return true;
	if(root){
		if((!root->lchild&&root->rchild)||(root->lchild&&!root->rchild))
			return false;
	}
	return isStrict (root->lchild) && isStrict (root->rchild);
}

在这里插入图片描述


在这里插入图片描述

  • 7
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序猿小张的日常笔记

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值