二叉树的基本算法

二叉树的先序遍历
就是每棵子树,都是先出现头结点、再左子树、再右子树。

1、递归实现先序中序后序遍历
!!! 一定会到达这个Node节点三次,也表明了有三个位置进行Node数据的处理,前中后

每个节点都是这样。

先序就是第一次到达某个节点就打印

中序就是第二次到达某个节点就打印

后序就是第三次到达某个节点再打印。

二叉树可以先去左边树上转一圈,再回到中间节点,再去右边树上转一圈,可以进行信息的整合。

f(Node)
{
    if(Node==NULL)
        return;
    // 1
    f(Node->left);
    // 2
    f(Node->left);
    //3
}

2、非递归实现先序中序后序遍历

压栈的方式实现非递归

  

1、先序遍历

设计栈   头-左-右

  1. 栈弹出元素就打印
  2. 如有右,就压入右
  3. 如有左,就压入左

因为栈先进后出,所以先压右,再压左,那么弹出的时候就先弹出左,弹出即打印,就是先序了。

2、后序遍历 

头-右-左   那么把弹出来的元素倒个序就是左-右-头,也就是倒序遍历了

  1. 栈弹出元素就打印
  2. 如有左,就压入左
  3. 如有右,就压入右

所以处理元素的时候,另设一个新栈放处理元素,等放节点的栈处理完了 ,把新栈里的元素弹出,那么就是后序遍历的结果了。

 

 后序遍历通过一个栈实现

在没有打印的时候,h的含义没有动过。h始终指向上次打印的位置。c指向当前栈顶。

c.left=h就说明 c节点的左子树处理完了,c.right=h就说明 c节点的右子树处理完了,当然左树也处理完了。

if...else if...else 分别对应节点的左树、右树都没有处理完;左树处理完了;右树处理完,左右树同时处理完了。

3、中序遍历 

1)head不为零,整条左边界依次入栈

2)条件1)无法满足,就弹出,右树继续执行条件1)

理解:整棵树会被左边界(头左)分解,弹出的时候就是左头。且每次处理都是先左树的左头,再右树的左头,把整棵树分解,也就遍历完了树上的每个节点。

 3、层序遍历

刷爆LeetCode很难?你错了!左神(左程云)算法大牛,熬夜1个月,肝出数据结构与算法基础-中级-高级全家桶教程,直击BATJ算法面试题真题,一线大厂一网打尽_哔哩哔哩_bilibili

4、二叉树的序列化和反序列化 

二叉树结该是一个二维平面内的结构,而序列化出来的字符串是一个线性的一维结构。所谓的序列化不过就是把结构化的数据「打平」,其实就是在考察二叉树的遍历方式

保存节点,包括空节点,那么可以通过打印出来的东西进行二叉树的复原。

序列化和二叉树的结构一一对应。

不能忽略空。

层序遍历反序列化

序列化是在前、中、后序遍历的基础上,把二维平面内的二叉树结构元素拿出来变成线性的一维结构。

下面的是参考labuladong算法小抄的内容

二叉树的题,就那几个框架,枯燥至极🤔 (qq.com)https://mp.weixin.qq.com/s?__biz=MzAxODQxMDM0Mw==&mid=2247485871&idx=1&sn=bcb24ea8927995b585629a8b9caeed01&chksm=9bd7f7a7aca07eb1b4c330382a4e0b916ef5a82ca48db28908ab16563e28a376b5ca6805bec2&scene=21#wechat_redirect

该链接中同时包含前中后序遍历二叉树的序列化和反序列化,同时有层级遍历的序列化和反序列化。

 4.1基于前序遍历的框架实现序列化和反序列化

序列化:在前序遍历的框架上,遍历元素并且保存元素

String SEP = ",";
String NULL = "#";

/* 主函数,将二叉树序列化为字符串 */
String serialize(TreeNode root) {
    StringBuilder sb = new StringBuilder();
    serialize(root, sb);
    return sb.toString();
}

/* 辅助函数,将二叉树存入 StringBuilder */
void serialize(TreeNode root, StringBuilder sb) {
    if (root == null) {
        sb.append(NULL).append(SEP);
        return;
    }

    /****** 前序遍历位置 ******/
    sb.append(root.val).append(SEP);
    /***********************/

    serialize(root.left, sb);
    serialize(root.right, sb);
}


反序列:如何通过二叉树的前序遍历结果还原一棵二叉树?

    if (nodes.isEmpty()) return null;

    /****** 前序遍历位置 ******/
    // 列表最左侧就是根节点
    String first = nodes.removeFirst();
    if (first.equals(NULL)) return null;
    TreeNode root = new TreeNode(Integer.parseInt(first));
    /***********************/

    root.left = deserialize(nodes);
    root.right = deserialize(nodes);

理解:借助二叉树的递归就是先处理中间的节点,再处理左子树,最后处理右子树。
注意这里的返回值用一维结构元素数组中取出来的元素构造节点,分别先赋值给根节点,再赋值给根节点的左、右树节点。
根据树的递归性质,nodes 列表的第一个元素就是一棵树的根节点,所以只要将列表的第一个元素取出作为根节点,剩下的交给递归函数去解决即可。

!!!注意:这里的两次返回null,一次是数组元素为空,说明所有的节点都处理完了;一次是遇到数组中有null,在先序遍历中说明某节点的某颗子树处理完了。

 4.2基于中序遍历的框架无法实现反序列化 

序列化:

/* 辅助函数,将二叉树存入 StringBuilder */
void serialize(TreeNode root, StringBuilder sb) {
    if (root == null) {
        sb.append(NULL).append(SEP);
        return;
    }

    serialize(root.left, sb);
    serialize(root.right, sb);

    /****** 后序遍历位置 ******/
    sb.append(root.val).append(SEP);
    /***********************/
}

反序列化: 

 

/* 主函数,将字符串反序列化为二叉树结构 */
TreeNode deserialize(String data) {
    LinkedList<String> nodes = new LinkedList<>();
    for (String s : data.split(SEP)) {
        nodes.addLast(s);
    }
    return deserialize(nodes);
}

/* 辅助函数,通过 nodes 列表构造二叉树 */
TreeNode deserialize(LinkedList<String> nodes) {
    if (nodes.isEmpty()) return null;
    // 从后往前取出元素
    String last = nodes.removeLast();
    if (last.equals(NULL)) return null;
    TreeNode root = new TreeNode(Integer.parseInt(last));
    // 限构造右子树,后构造左子树
    root.right = deserialize(nodes);
    root.left = deserialize(nodes);

    return root;
}

 4.3基于中序遍历的框架无法实现反序列化

可以实现序列化

/* 辅助函数,将二叉树存入 StringBuilder */
void serialize(TreeNode root, StringBuilder sb) {
    if (root == null) {
        sb.append(NULL).append(SEP);
        return;
    }

    serialize(root.left, sb);
    /****** 中序遍历位置 ******/
    sb.append(root.val).append(SEP);
    /***********************/
    serialize(root.right, sb);
}

但是,我们刚才说了,要想实现反序列方法,首先要构造 root 节点。前序遍历得到的 nodes 列表中,第一个元素是 root 节点的值;后序遍历得到的 nodes 列表中,最后一个元素是 root 节点的值。

你看上面这段中序遍历的代码,root 的值被夹在两棵子树的中间,也就是在 nodes 列表的中间,我们不知道确切的索引位置,所以无法找到 root 节点,也就无法进行反序列化。

4.4基于层序遍历的框架实现反序列化 

 

 可以看到,每一个非空节点都会对应两个子节点。 

 我的困惑就是怎么在一、二层完成以后,怎么将第三层和上两层的联系起来?是通过把元素构成的节点放到队列中,如果遍历到的元素不为空就压入队列中,意味着通过它构造出来的节点不为空,就会对应两个子节点。

/* 将字符串反序列化为二叉树结构 */
TreeNode deserialize(String data) {
    if (data.isEmpty()) return null;
    String[] nodes = data.split(SEP);
    // 第一个元素就是 root 的值
    TreeNode root = new TreeNode(Integer.parseInt(nodes[0]));

    // 队列 q 记录父节点,将 root 加入队列
    Queue<TreeNode> q = new LinkedList<>();
    q.offer(root);

    for (int i = 1; i < nodes.length; ) {
        // 队列中存的都是父节点
        TreeNode parent = q.poll();
        // 父节点对应的左侧子节点的值
        String left = nodes[i++];
        if (!left.equals(NULL)) {
            parent.left = new TreeNode(Integer.parseInt(left));
            q.offer(parent.left);
        } else {
            parent.left = null;
        }
        // 父节点对应的右侧子节点的值
        String right = nodes[i++];
        if (!right.equals(NULL)) {
            parent.right = new TreeNode(Integer.parseInt(right));
            q.offer(parent.right);
        } else {
            parent.right = null;
        }
    }
    return root;
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
平衡二叉树是一种特殊的二叉搜索树,它具有以下特点: 1. 左子树和右子树的高度差不超过 1; 2. 左子树和右子树都是平衡二叉树。 常见的平衡二叉树有 AVL 树、红黑树等。 平衡二叉树基本算法验证包括以下部分: 1. 插入节点:在插入节点时,需要保证插入后树仍然是平衡的。具体操作是:首先按照二叉搜索树的插入方法将节点插入到树中,然后从插入节点开始向上逐层检查,如果检查到某个节点不平衡,就进行旋转操作,使得该节点重新平衡。旋转操作包括左旋、右旋、左右旋和右左旋四种,具体实现可参考 AVL 树、红黑树等平衡二叉树的旋转操作; 2. 删除节点:在删除节点时,同样需要保证删除后树仍然是平衡的。具体操作是:先按照二叉搜索树的删除方法将节点删除,然后从删除节点的父节点开始向上逐层检查,如果检查到某个节点不平衡,就进行旋转操作,使得该节点重新平衡; 3. 查找节点:在平衡二叉树中查找节点的方法与二叉搜索树相同,具体操作是从根节点开始,比较待查找节点与当前节点的大小关系,然后根据比较结果向左子树或右子树遍历,直到找到目标节点或遍历到叶子节点为止。 以上就是平衡二叉树基本算法验证的内容。需要注意的是,不同的平衡二叉树可能存在一些细微的差异,具体实现时需要结合具体的平衡二叉树来进行调整。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值