层次遍历二叉树

层次遍历二叉树

♥ 做法

image-20221210161332715

▪ 逐层进行访问

▪ 对某一层的节点访问完后,再按照其访问次序对各个节点的左、右孩子顺序访问。

♥算法构思

既然我们了解了层次遍历的次序, 那接下来就是层次遍历的设计,我们是逐层遍历,在同一层次上面的节点,先遍历的节点,其孩子在下一层也有优先权,所以我们在遍历到一个节点时,其孩子也要进入排队的序列。我们根据优先权,先进来要求先出,所以我们可以采用队列的形式,逐层的去存储要出队遍历的节点。

唯一需要注意的就是,当遍历一个节点的时候,我们要把其孩子入队,以方便下一层节点的有序遍历。

当然,由于节点的个数不确定,我们可以采用环形队列的方式进行数据结构存储。

♥ 数据结构设计

▪ 先访问的节点,其左、右孩子也要先访问

▪ 先进先出

▪ 用队列实现

▪ 用环形队列实现

♥ 层次遍历过程

▪ 先将根节点进队

▪ 节点出队并访问,再将左右孩子入队

▪ 循环,直到队空

♥ 算法实现

//传入要层次遍历的树
void LevelOrder(BTNode *b)
{
    //定义遍历节点的指针
    BTNode *p;
    //定义存储遍历节点次序的数组队
    BTNode *qu[MaxSize];
    //定义队的队头和队尾
    int front,rear;
    //初始化队列
    front = rear = -1;
    //我们先将根节点入队
    rear++;
    qu[rear]=b;
    //接下来就是遍历节点,然后将其孩子加入队列,按层次遍历的过程了
    while(front!=rear)
    {
        //从队列中出列一个节点*p,访问它;
        front = (front+1)%MaxSize;
        p = qu[front];
        printf("%c",p->data);
        //若它有左孩子节点,将其左孩子节点进队
        if(p->lchild!=NULL)
        {
            rear = (rear+1)%MaxSize;
            qu[rear] = p->lchild; 
        }            
        //若它有右孩子节点,将右孩子节点进队
        if(p->rchild!=NULL)
        {
            rear = (rear+1)%MaxSize;
            qu[rear] = p->rchild; 
        }            
    }        
}    

应用:用层次遍历求路径之逆

♥ 问题

二叉树采用二叉链存储结构,设计算法输出从根节点到每个叶子节点的路径之逆

♥ 解题思路:

image-20221210164427683

既然要求路径之逆,那么就需要让节点知道其双亲是谁, 我们可以通过遍历给每个节点编号,定义每个节点的双亲信息。既然要定义存储其双亲信息,那我们我们就需要遍历二叉树,那就非层次遍历莫属了,因为层次遍历没有递归遍历的冗余信息,没有先序遍历、中序遍历、后续遍历来回操作的烦恼,只需要按部就班的进行进队和出队节点即可,方便我们进行遍历每个节点。并且我们在处理一个节点的时候,会把其孩子入队,此时我们就可以把节点的信息,告诉其孩子,并存储到数组里面,方便后续我们进行求路径之逆。

♥ 算法框架:

结合层次遍历的特点,给出解题框架

▪ 采用非环形顺序队列qu

▪ 层次遍历二叉树

▪ 将所有已访问过的节点指针进队,并在队列中保存双亲节点的位置

▪ 当找到一个叶子结点时,在队列中通过双亲节点的位置输出根节点到该叶子节点的路径之逆。

image-20221210165335289
void AllPath2(BTNode*b)
{
    定义队列;
    根节点入队;
    while(队列不空)
    {
        if(检查是否是叶子节点)
        {
            如果是,就根据标记输出叶子节点到跟节点的路径
        }            
    }        
    //继续遍历二叉树,把每一个节点赋值到数组里面,并将双亲信息给孩子
    左孩子先入队;
    右孩子入队;
}    
__________________________________________________________________________________
    我们不用担心,已经填入的数组的节点不够用,不足以找到其双亲,因为我们是按照层次遍历的二叉树,
如果遍历到一个节点是叶子节点,那其双亲一定在数组里面,我们也一定可以找到,因为我们就是根据其
双亲才将节点入队访问的,都是按照层次进行访问的,其上层一定在数组里面,边访问,边输出即可。

♥ 算法实现

//传入二叉树
void AllPath2(BTNode *b)
{
    //定义访问的节点的指针
    BTNode *q;
	//定义存储双亲信息的数组节点
    struct snode
    {
        //存储节点的值
        BTNode *node;
        //存储节点双亲在数组里的位置
        int parent;
    }qu[MaxSize];        
    //因为我们是按照层次进行遍历的,所有节点都是按顺序填入数组的,我们可以将此存储双亲信息的数组当成队列去使用
	//我们此次没有出队节点的需要,所以不会破坏队列的数据
    //初始化队列
    int front,rear,p;
    front = rear = -1;
    //入队根节点
    rear++;
    qu[rear].node = b;
    qu[rear].parent = -1;	//根节点无双亲,所以记作-1
    //下面开始遍历访问节点,并填入数组,如果遇到叶子节点,根据双亲信息输出即可
	//队列不空
    while(front!=rear)
    {
        //访问队头节点
        front++;
        q = qu[front].node;
        //判断叶子节点,输出路径之逆
        if(q->lchild==NULL && q->rchild==NULL)
        {
            //通过上面的验证,说明队首节点就是叶子节点
            p = front;
            while(qu[p].parent!= -1)
            {
                printf("%c->",qu[p].node->data);
                //遍历赋值叶子节点路径上的双亲数组序号
                p = qu[p].parent;
            }                
            printf("%c\n",qu[p].node->data);
        }            
        //左孩子入队
        if(q->lchild!=NULL)
        {
            rear++;
            //入队的节点
            qu[rear].node = q->lchild;
            //入队节点的双亲是队首节点
            qu[rear].parent = front;
        }            
        //右孩子入队
        if(q->rchild!=NULL)
        {
            rear++;
			//入队的节点
            qu[rear].node = q->rchild;
            //入队节点的双亲是队首节点
            qu[rear].parent = front;
        }            
    }        
}    
    

层次遍历二叉树是一种广度优先搜索的算法,它按照从上到下、从左到右的顺序逐层遍历二叉树的节点。下面是一个用C语言实现层次遍历二叉树的示例代码: ```c #include <stdio.h> #include <stdlib.h> // 定义二叉树节点结构 struct TreeNode { int val; struct TreeNode* left; struct TreeNode* right; }; // 创建新节点 struct TreeNode* createNode(int val) { struct TreeNode* newNode = (struct TreeNode*)malloc(sizeof(struct TreeNode)); newNode->val = val; newNode->left = NULL; newNode->right = NULL; return newNode; } // 层次遍历二叉树 void levelOrder(struct TreeNode* root) { if (root == NULL) { return; } // 创建一个队列用于存储待遍历的节点 struct TreeNode** queue = (struct TreeNode**)malloc(sizeof(struct TreeNode*) * 1000); int front = 0; // 队列头指针 int rear = 0; // 队列尾指针 // 将根节点入队 queue[rear++] = root; while (front < rear) { // 出队当前节点并访问 struct TreeNode* node = queue[front++]; printf("%d ", node->val); // 将当前节点的左右子节点入队 if (node->left != NULL) { queue[rear++] = node->left; } if (node->right != NULL) { queue[rear++] = node->right; } } // 释放队列内存 free(queue); } int main() { // 创建二叉树 struct TreeNode* root = createNode(1); root->left = createNode(2); root->right = createNode(3); root->left->left = createNode(4); root->left->right = createNode(5); // 层次遍历二叉树 printf("层次遍历结果:"); levelOrder(root); return 0; } ``` 这段代码中,我们首先定义了一个二叉树节点的结构体`TreeNode`,包含一个整数值`val`和左右子节点的指针。然后,我们实现了一个`createNode`函数用于创建新的节点。接下来,我们定义了一个`levelOrder`函数用于层次遍历二叉树。在该函数中,我们使用一个队列来存储待遍历的节点,初始时将根节点入队,然后循环执行以下操作:出队当前节点并访问,将当前节点的左右子节点入队。最后,我们在`main`函数中创建了一个二叉树,并调用`levelOrder`函数进行层次遍历
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值