目录

一、二叉树

二、二叉树的先序、中序、后序遍历

(一)、递归遍历

(二)、非递归遍历

(1)先序:头左右

(2)中序:左头右

(3)后序:左右头

三、实现二叉树的按层遍历

(一)、遍历-队列

(二)、求最大层的宽度

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

(一)、递归

(二)、按层


一、二叉树

图示:

结构:

public class BtreeNode {public int value;public BtreeNode left;public BtreeNode right;public BtreeNode(int value){this.value = value;}
}

二、二叉树的先序、中序、后序遍历

先序:任何子树处理顺序是,头-左-右;

中序:任何子树处理顺序是,左-头-右;

后序:任何子树处理顺序是,左-右-头;

先序:

头:1

--左:2

----左:4

------左:8

--------左:16

--------右:17

------右:9

--------左:18

----右:5

------左:10

------右:11

--右:3

----左:6

------左:12

------右:13

----右:7

------左:14

------右:15

(一)、递归遍历

//先序:头左右public void pre(BtreeNode head){if(head == null){return;}System.out.println(head.value);pre(head.left);pre(head.right);}//中序:左头右public void mid(BtreeNode head){if(head == null){return;}mid(head.left);System.out.println(head.value);mid(head.right);}//后序:左右头public void beh(BtreeNode head){if(head == null){return;}beh(head.left);beh(head.right);System.out.println(head.value);}

递归序:先序后序中序不是递归遍历的本质,递归遍历的本质是递归序:

例如先序,先到1,再到2,再到4,4往左走没有了,回到4,再到4的右,4的右也没有了,再回到4,回到2,再到5,5左没有,回到5,5右没有,回到5...

所以整个顺序及到达的节点是:1 2 4 4 4 2 5 5 5 2 1 3 6 6 6 3 7 7 7 3 1

先序(头左右):打印每个第一次到达的节点,就是先序

中序(左头右):第二次到达这个节点的时候打印

后续(左右头):第三次到达这个节点的时候打印

任何一个节点都可以从左边转一圈,收集一些信息,任何节点都可以从右边转一圈,收集一些信息,还可以第三次回到它,把左右信息整合,这是在树上做动态规划的基础。、

(二)、非递归遍历

任何递归方法都可以用非递归实现,遍历二叉树我们可以用压栈方式实现

(1)先序:头左右

左右压栈顺序是先右后左,然后弹出打印,弹出的节点作为头,再压它的右,之后压左。即:1)弹出即打印;2)有右压右;3)有左压左

//先序public void pre(BtreeNode head){if(head == null){return;}BtreeNode node = head;Stack<BtreeNode> stack = new Stack();stack.add(node);while(!stack.isEmpty()){node = stack.pop();System.out.println(node.value);if(node.right != null){stack.add(node.right);}if(node.left != null){stack.add(node.left);}}}

(2)中序:左头右

把子树下面所有的左节点压栈,再弹出打印节点,再把弹出节点的右节点的所有子树的左节点压栈。即1)有左就压左;2)弹出即打印,右节点继续1)

//中序:左头右public void mid(BtreeNode head){if(head == null){return;}BtreeNode node = head;Stack<BtreeNode> stack = new Stack<>();while (node != null || !stack.isEmpty()){if(node!= null){stack.add(node);node = node.left;}else{node = stack.pop();System.out.println(node.value);node = node.right;}}}

(3)后序:左右头

方法一:

先序是头左右,先压右后压左。

后序是左右头,那么头右左反过来,而头右左怎么得到呢,无非是先压左后压右。可以用两个栈实现后序

//后序public void pos1(BtreeNode head){if(head == null){return;}BtreeNode node = head;Stack<BtreeNode> stack1 = new Stack<>();Stack<BtreeNode> stack2 = new Stack<>();stack1.add(node);while (!stack1.isEmpty()){node = stack1.pop();stack2.add(node);if(node.left != null){stack1.add(node.left);}if(node.right != null){stack1.add(node.right);}}while (!stack2.isEmpty()){System.out.println(stack2.pop().value);}}

方法二:如果不用两个栈,可以利用指针实现

比如

1先入栈,

1如果有左节点,左节点入栈:2入栈

2如果有左节点,左节点入栈:4入栈

4如果有左节点,左节点入栈:没有节点入栈

4如果有右节点,右节点入栈:没有节点入栈

4弹出

栈顶是2,需要一个指针记录刚刚弹出的节点是4,2的左节点已经弹出,处理2的右节点

2如果有右节点,右节点入栈:5入栈

5如果有左节点,左节点入栈:没有节点入栈

5如果有右节点,右节点入栈:没有节点入栈

5弹出

栈顶是2,指针记录刚刚弹出的节点是5,2的右节点弹出了,说明左右都处理完了,

2弹出

栈顶是1,指针记录刚弹出的是2,1的左节点已经弹出,处理1的右节点

....

//后序 方法二public void pos2(BtreeNode head){if(head == null){return;}BtreeNode c = head;BtreeNode h = head;//记录上一个弹出的节点Stack<BtreeNode> stack = new Stack<>();stack.push(head);while(!stack.isEmpty()){c = stack.peek();if(c.left != null && h != c.left && h != c.right){//left right都没弹出stack.push(c.left);}else if (c.right != null && h!=c.right){//右没弹出stack.push(c.right);}else{h = stack.pop();System.out.println(h.value);}}}

三、实现二叉树的按层遍历

(一)、遍历-队列

弹出-判断有无左节点,有则左入队列-判断有无右节点,有右入队列...循环

public void layerQueue(BtreeNode head){if(head == null){return;}BtreeNode node = head;Queue<BtreeNode> queue = new LinkedList<>();queue.add(head);while(!queue.isEmpty()){node = queue.poll();System.out.println(node.value);if(node.left != null){queue.add(node.left);}if(node.right != null){queue.add(node.right);}}}

(二)、求最大层的宽度

每层有几个节点即宽度为多少

方法一:使用map记录每一个节点在哪层,使用指针记录每一个出队列的节点的层数,一旦某个节点和它上一个节点的层数不一样了,说明到下一层了,进行结算

public int nodeCountMaxUseMap(BtreeNode head) throws Exception {if(head == null){throw new Exception("头为空");}Map<BtreeNode,Integer> map = new HashMap<>();Queue<BtreeNode> queue = new LinkedList<>();BtreeNode node = null;queue.add(head);map.put(head,1);int nodeLevel = 1;//当前在哪一层int nodeCount = 0;//当前那一层的个数int max = 0;//最大的宽度while(!queue.isEmpty()){node = queue.poll();int h = map.get(node);if(node.left != null){queue.add(node.left);map.put(node.left,h+1);}if(node.right != null){queue.add(node.right);map.put(node.right,h+1);}if(h == nodeLevel){ //仍然在这一层nodeCount++;}else{ //到了下一层max = Math.max(max,nodeCount);nodeCount = 1;nodeLevel ++;}}max = Math.max(max,nodeCount);//最后一层结算return max;}

方法二:

可以只用一个队列,然后记录下一层的最右节点,这样每一层的最右节点就被记录下来。当弹出的节点等于这一层的最右节点时,说明新层要开始了,我们进入结算,当不等于时,说明我们还是在这一层,那就节点数+1

public int nodeCountMaxNoMap(BtreeNode head) throws Exception {if(head == null){throw new Exception("头为空");}BtreeNode node = null;Queue<BtreeNode> queue = new LinkedList<>();queue.add(head);BtreeNode nextEnd = null;//下一层的最右节点int nodeCount = 0;//当前层的个数BtreeNode curNode = head;//当前层的最右节点int max = 0;while(!queue.isEmpty()){node = queue.poll();if(node.left != null){queue.add(node.left);nextEnd = node.left;}if(node.right != null){queue.add(node.right);nextEnd = node.right;}nodeCount++;if(node == curNode){//这个弹出的节点是当前层的最右节点,说明下一层要开始了max = Math.max(max,nodeCount);nodeCount = 0;curNode = nextEnd;}}return max;}

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

如何把一个内存里的树变成一个序列化的结构,这个树是在内存中串好的,如果某个时刻要停机,则需要把内存的东西做成文件的形式保存下来,这样服务重新启动的时候,又可以恢复成原来的内存结构

(一)、递归

序列化:

可以按照先序、中序、后序顺序,递归把树放入一个队列进行序列化,但是要注意,不能忽略空节点,遇到空节点也要放,不是空节点则继续按照头左右(左右头...)递归

例如,这里先序(头左右)序列化出来的队列就应该是[1,2,4,null,null,3,5,null,null]

public Queue<BtreeNode> pre(BtreeNode head){Queue<BtreeNode> queue = new LinkedList<>();preRecursion(queue,head);return queue;}private void preRecursion(Queue<BtreeNode> queue,BtreeNode node){if(node ==  null){queue.add(node);}else{//不是null,就继续递归queue.add(node);preRecursion(queue,node.left);preRecursion(queue,node.right);}}

反序列化:

递归弹出队列的数据,如果是空则返回,继续弹,如果不是空,则给二叉树赋值,左节点继续递归要队列的值,右节点继续递归要队列的值

private void preRecursion(Queue<BtreeNode> queue,BtreeNode node){if(node ==  null){queue.add(node);}else{//不是null,就继续递归queue.add(node);preRecursion(queue,node.left);preRecursion(queue,node.right);}}//先序反序列化public BtreeNode antipre(Queue<BtreeNode> queue){if(queue.isEmpty() || queue.size()==0){return null;}return antiPreRecursion(queue);}private BtreeNode antiPreRecursion(Queue<BtreeNode> queue){BtreeNode node = queue.poll();if(node == null){return null;}BtreeNode head = node;head.left = antiPreRecursion(queue);head.right = antiPreRecursion(queue);return head;}

(二)、按层

序列化:

序列化之后,入队列,为[1,2,3,4,null,5,null,null,null,null,null]

提起按层,我们就应该利用队列,先把树的节点按层加入一个队列,然后这个队列弹出,再来一个队列接收,如果前一个队列的左节点为空,新队列加空,不为空,加左节点本身,右节点同理

//按层序列化public Queue<BtreeNode> cengSer(BtreeNode head){Queue<BtreeNode> q1 = new LinkedList();Queue<BtreeNode> q2 = new LinkedList<>();if(head == null){q2.add(head);}else{BtreeNode node = null;q1.add(head);while(!q1.isEmpty()){node = q1.poll();q2.add(node);if(node.left != null){q1.add(node.left);}q2.add(node.left);if(node.right != null){q1.add(node.right);}q2.add(node.right);}}return q2;}

反序列化:

//反序列化public BtreeNode cengAntiSer(Queue<BtreeNode> queue){if(queue == null || queue.isEmpty() || queue.size()==0){return null;}BtreeNode head = queue.peek();BtreeNode node = null;while (!queue.isEmpty()){node = queue.poll();if(node == null){continue;}if(queue.peek() != null){node.left = queue.poll();}if(queue.peek() != null){node.right = queue.poll();}}return head;}

算法 - 二叉树的基本算法相关推荐

  1. Python实现: 常用排序算法 二叉树的遍历算法

    转载自:http://www.cnblogs.com/alex3714/articles/5474411.html点击打开链接,感谢原作者,如有侵权,联系删除 本节内容 算法定义 时间复杂度 空间复杂 ...

  2. 【swjtu】数据结构实验6_二叉树的遍历算法

    实验内容及要求: 编写程序,用先序递归遍历法建立二叉树的二叉链表存储结构,然后输出其先序.中序.后序以及层次遍历结点访问次序.其中层次遍历的实现需使用循环队列.二叉树结点数据类型建议选用字符类型. 实 ...

  3. 重拾算法(3)——用458329个测试用例全面测试二叉树和线索二叉树的遍历算法

    重拾算法(3)--用458329个测试用例全面测试二叉树和线索二叉树的遍历算法 在"上一篇"和"上上一篇"中,我给出了二叉树和线索二叉树的遍历算法.给出算法容易 ...

  4. 二叉树的遍历(算法导论第三版12.1-4)(包含先序遍历,后序遍历和中序遍历)

    二叉树的遍历(算法导论第三版12.1-4) 1⃣️先序遍历 template<typename T> void preorder_tree_wald(BinaryTreeNode<T ...

  5. 数据结构与算法--二叉树第k个大的节点

    二叉树第k个大的节点 二叉树文章列表: 数据结构与算法–面试必问AVL树原理及实现 数据结构与算法–二叉树的深度问题 数据结构与算法–二叉堆(最大堆,最小堆)实现及原理 数据结构与算法–二叉查找树转顺 ...

  6. 数据结构与算法-- 二叉树中和为某一值的路径

    二叉树中和为某一值的路径 题目:输入一颗二叉树和一个整数,打印出二叉树中节点值的和为给定值的所有路径.从树的根节点开始往下一只到叶子节点所经过的节点形成一条路径. 我们用二叉树节点的定义沿用之前文章中 ...

  7. 数据结构与算法-- 二叉树后续遍历序列校验

    二叉树后续遍历序列校验 题目:输入一个整数数组,判断改数组是否是某个二叉搜索树的后续遍历结果,如果是返回true否则false,假设输入数组的任意两个数字不相同. 例如输入{5,7,6,9,11,10 ...

  8. javascript数据结构与算法--二叉树遍历(中序)

    javascript数据结构与算法--二叉树遍历(中序) 中序遍历按照节点上的键值,以升序访问BST上的所有节点 代码如下: /**二叉树中,相对较小的值保存在左节点上,较大的值保存在右节点中*** ...

  9. 数据结构算法-二叉树

    目录 二叉树 二叉树的链式存储结构 二叉树先序遍历(递归) 二叉树先序遍历(非递归) 二叉树中序遍历(递归) 二叉树中序遍历(非递归) 二叉树后序遍历(递归) 二叉树后序遍历(非递归) 二叉树判定问题 ...

最新文章

  1. ln -s命令 linux,linux ln命令详解
  2. 5 zabbix 添加host_Zabbix 快速上手——添加 Agent 主机
  3. Linux使用ftp传输10g的文件,Ubuntu 16.04 安装ftp服务器传输文件
  4. windows, 放方向键设置为vim格式,autohotkey-windows
  5. boolean类型_10、typescript的高级类型
  6. linux16.04下安装Clion2019.2记录以及C++代码运行
  7. Realsense无法启动彩色摄像头
  8. websocket 压测工具 有哪些_性能测试总结(概念amp;流程amp;工具)
  9. Autojs对接图灵机器人
  10. sena utility Android apk,Sena 30K Utility
  11. gromacs 安装_安装gromacs的一些心得
  12. 【Java】在Eclipse中,很多代码的背景变成黄色、绿色或红色(已解决)
  13. 软件工程(四)——结构化设计之总体设计
  14. 战地1修改服务器,战地1服务器设置教程
  15. 王道计算机考研j机试指南,王道论坛计算机考研机试指南 三 Hash的应用
  16. 遇到问题-----ftp---windows----打开FTP文件夹出错--windows无法访问此文件夹。请确保输入的文件名是否正确,并且您有权访问此文件
  17. 文件下载名称出现乱码问题
  18. Excel一个表内多个sheet分列操作
  19. 2021年十大医疗手术机器人公司(翻译)
  20. 计算机游戏五子连珠怎么出来,五子连珠游戏程序流程图

热门文章

  1. 百度超级链与重庆市联合打造的电子处方流转平台,并荣获可信区块链高价值案例
  2. 80211 BA/BAR
  3. 典型CCN网络——efficientNet(2019-Google-已开源)
  4. 巧用小词在GRE写作中拿高分
  5. TensorFlow学习笔记——车牌标志识别分类
  6. 计算机专业考研书目(中科大)
  7. Python办公自动化之释放双手自动写文章
  8. 去哪查阅RFC文档?
  9. 佛学常见辞汇(十五画)
  10. 3D劲舞游戏 Dance Mixer 简体中文汉化版+常见问题(更新1.1补丁 汉化) 1