二叉树(2)

二叉树按层遍历
1.针对二叉树的宽度优先遍历。
第一步:需要借助队列,首先将根节点pRoot入队;
第二步:当队列不空时,获得队首元素并出队,赋给pRoot,执行第三步;
第三步:如果pRoot左节点存在,则入队;如果pRoot右节点存在,则入队;执行第二步。

#include<iostream>
#include<string>
#include<stack>
#include<queue>
using namespace std;


class BinaryTreeNode  
{
public:
    char data;  
    BinaryTreeNode *Left;  
    BinaryTreeNode *Right;  
}; 

//创建二叉树,顺序依次为中间节点->左子树->右子树

void createBiTree(BinaryTreeNode* &T)   //这里加上&意思是传递的参数为指针的引用,括号里面等价于 BiTreeNode* &T
 {                                 //这样的意义在于在函数执行过后,传递进来的指针会发生改变(引用的作用),不可以去掉&
     char c;
     cin >> c;
     if('#' == c)               //当遇到#时,令树的根节点为NULL,从而结束该分支的递归
         T = NULL;
     else
     {
         T = new BinaryTreeNode;
         T->data=c;
         createBiTree(T->Left);
         createBiTree(T->Right);
     }
 }
void levelorder(BinaryTreeNode* &T){
    queue<BinaryTreeNode*> q1;
    q1.push(T);
    while(!q1.empty()){
        BinaryTreeNode* cur=q1.front();
        q1.pop();
        cout<<cur->data;
        if(cur->Left!=NULL){
            q1.push(cur->Left);
        }
        if(cur->Right!=NULL){
            q1.push(cur->Right);
        }
    }
}

int main(){
     BinaryTreeNode* T;               //声明一个指向二叉树根节点的指针               
     createBiTree(T);               //abd###ce##fg###
     cout<<"二叉树创建完成!"<<endl; 
     cout<<"层次遍历二叉树:"<<endl;
     levelorder(T);
     cout<<endl;

     return 0;
}

2.宽度优先遍历常使用队列结构。
3.面试中,该类题目常对换行有所要求。

这里写图片描述

给定一颗二叉树的头节点head,请按照现在大家看的的这种格式打印。
要求打印成:
1
2 3
4 5 6
7 8

last:表示正在打印的当前行的最右节点
nlast:表示下一行的最后节点

#include<iostream>
#include<string>
#include<stack>
#include<queue>
using namespace std;

class BinaryTreeNode  
{
public:
    char data;  
    BinaryTreeNode *Left;  
    BinaryTreeNode *Right;  
}; 

//创建二叉树,顺序依次为中间节点->左子树->右子树

void createBiTree(BinaryTreeNode* &T)   //这里加上&意思是传递的参数为指针的引用,括号里面等价于 BiTreeNode* &T
 {                                 //这样的意义在于在函数执行过后,传递进来的指针会发生改变(引用的作用),不可以去掉&
     char c;
     cin >> c;
     if('#' == c)               //当遇到#时,令树的根节点为NULL,从而结束该分支的递归
         T = NULL;
     else
     {
         T = new BinaryTreeNode;
         T->data=c;
         createBiTree(T->Left);
         createBiTree(T->Right);
     }
 }

void levelorder1(BinaryTreeNode* &T){
    queue<BinaryTreeNode*> q1;
    q1.push(T);
    BinaryTreeNode* last=T;
    BinaryTreeNode* nlast=NULL;
    while(!q1.empty()){
        BinaryTreeNode* cur=q1.front();
        q1.pop();
        cout<<cur->data;
        if(cur->Left!=NULL){
            q1.push(cur->Left);
            nlast=cur->Left;
        }
        if(cur->Right!=NULL){
            q1.push(cur->Right);
            nlast=cur->Right;
        }
        if(cur==last){
           last=nlast;
           cout<<endl;      
        }
    }
}

int main(){
     BinaryTreeNode* T;               //声明一个指向二叉树根节点的指针               
     createBiTree(T);               //abd###ce##fg###
     cout<<"二叉树创建完成!"<<endl; 
     cout<<"层次遍历二叉树:"<<endl;
     levelorder1(T);
     cout<<endl;

     return 0;
}

思路:
解决方法是使用2个指针last和nlast,用nlast表示当前正在访问的结点,用last记录下一行的最后一个结点。
①从根结点开始,初始时nlast=null,即可以想象成为在根结点的上面,还没有访问任何一个结点,认为此时的所在行是0行(root的上面一行),令last=root,即表示下一行(第1行)的最后一个结点是root,即nlast=null,last=root(这是规定的,只要初始值规定好,之后就会出现需要的规律);
②将root放入队列后,循环开始,先从队列中取出一个结点cur,并先后将cur.left和cur.right放入队列中;每访问一个结点,就在将该结点放入队列之后将nlast指针移动到当前结点,表示正在访问的结点;
③每次放完之后要进行一个判断,看当前弹出的结点是否等于last。(弹出的结点就是当前正在遍历的结点,千万注意,我们要判断的是从队列中弹出的结点是否到达每层的最后一个结点,即判断正在遍历的结点是否是每一层的最后一个结点,而不是放入队列中的结点是否是是每一层的最后一个结点—因为按层遍历时结点是按照层的顺序从左到右从队列中弹出来的,因此判断的是弹出的结点是否是每一层的最后一个结点)一开始弹出的结点是root,显然成立,当将root.left和root.right放入到队列中之后,nlast指向了结点③,于是令last=nlast,即以结点③作为下一层(第2层)的最后一个结点……之后弹出cur=②,压入④⑤,判断cur!=last,继续弹出cur=③,压入⑥⑦,nlast=⑦,判断cur==last,于是换行,令last=nlast=⑦,……
即总是先弹出一个结点curà压入2个子节点left和right同时更新nlastà判断弹出的结点cur是否等于lastà如果不是,不作处理,继续循环弹出结点;如果是,进行换行操作,同时更新last为nlast。

二叉树的序列化和反序列化
1.二叉树→字符串(序列化)
2.字符串→二叉树(反序列化)
序列化的方式:
1.根据先序遍历序列化
2.根据中序遍历序列化
3.根据后序遍历序列化
4.按层序列化

二叉树被记录成文件的过程叫作二叉树的序列化,通过文件内容重建原来二叉树的过程叫作二叉树的反序列化。给定一颗二叉树的头节点head,并已知二叉树节点的类型为32位整型。请设计一种二叉树序列化和反序列化的方案,并用代码实现。

先序遍历二叉树进行序列化
1.假设序列化结果为str,初始时str为空字符串。
2.先序遍历二叉树时如果需要空节点,在str末尾加上“#!”。(#表示该节点为空,!表示一个值的结束,这些特殊字符可以自己设置)
3.如果遇到不为空的节点,假设节点值为3,就在str的末尾加上“3!”。
这里写图片描述

用一个特殊字符表示一个二叉树节点值的结束的意义。

如果不用特殊符号表示值的结束,则以下两棵树的序列化结果为:123###,说明不用特殊字符表示节点值结束的话,会产生歧义。
这里写图片描述

先序遍历反序列化
一个二叉树通过先序遍历得到的结果,如何进行反序列化。
把字符串str先变成字符串数组values。
str=“12!3!#!#!#!”
转为
values=[“12”、”3”、”#”、”#”、”#”]
这里写图片描述

1.选择用什么样的遍历方式序列化,就选择用什么样的方式反序列化。
2.一颗树序列化的结果是唯一的,唯一的结果生成的二叉树也是唯一的。

按层遍历的方式对二叉树进行序列化
1.用队列来进行二叉树的按层遍历,即宽度优先遍历。
2.除了访问节点的顺序是按层遍历之外,对结果字符串的处理,与之前介绍的处理方式一样。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值