数据结构与算法分析笔记与总结(java实现)--二叉树笔记

对于树这类题目,其实并不研究复杂的树,只研究最简单的二叉树,所谓二叉树就是指每个结点最多有2个子节点,可以只有一个子节点或者没有子节点(只要让不存在的结点为null即可),每个结点TreeNode除了有子节点之外还有一个数值,通常数值是int类型的数,即树有树结点构成,每个结点是一个TreeNode对象,结点对象中包含对2个子节点的引用以及一个int类型的值。二叉树问题并不难,通链表一样主要也是对指针的使用,只是二叉树的使用范围更广,场景、变化更多;因此要多理解,多练习,学会举一反三。

注意:二叉树不同于堆(堆是特殊的二叉树—完全二叉树),只有完全二叉树才与数组相对应,才可以使用i、2*i、2*i+1来建立父节点与子节点之间的位置关系。

 

视频讲解:

二叉树是由结点通过引用构成的,二叉树结点的结构是int value用来表示这个结点的值,以及Node left和Node right用来表示这个结点的2个子节点的引用对象。在Node类中通常还有一个构造函数,用来给新创建的结点赋值,注意只是给value属性赋值,left和right不赋值,默认是null。在新创建数的结点时需要Node node=new Node(123);并且通过设置left、right来设置这个结点的左右子节点;通过将某个结点的left或者right赋值为node来将结点node连接到已有的父节点上。注意,在二叉树中,任何一个结点只有一个父节点,即只会被引用一次;任何一个几点最多有2个子节点,即最多可以引用2个子节点。

 

二叉树类型题目是面试常考题型

1.二叉树能够结合队列、栈、链表、字符串等很多数据结构来进行考察

2.二叉树是一种特殊的图,使用二叉树时需要掌握图的基本遍历方式,例如广度优先搜索算法(Breadth First Search--BFS)和深度优先搜索算法(Deepth First Search--DFS)

3.二叉树题目需要掌握递归函数的使用并自己设计出递归过程。二叉树本身就是一种高度重复的结构(每棵树都有子树构成,子树又是一个树又由子树构成,对一棵树的某种操作需要对该树的子树以及子子树进行相同的操作),于是在对树进行操作时经常会用到递归来对子树以及子子树进行相同的操作。要灵活应用递归,掌握边界停止条件和每次的返回值。

4.树在实际工作中有广泛的使用,练好树的题目对于工作也是很有用的。

二叉树是一种特殊的树,相对树和图来讲结构很简单清晰,关键是对二叉树的先序、中序、后序遍历过程要熟练掌握并且明白二叉树在每种遍历顺序下有什么特点(例如先序遍历下第一个数是根结点,后序遍历下最后一个结点是根结点等)。

 

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

一棵树上面有很多结点,在很多时候都要对树上的所有结点进行遍历(例如找出最小的结点,判断是否对称,按层打印所有结点,找出最大子搜索树等),因此必然要求对二叉树进行扫描遍历,遍历有很多种顺序,任意顺序都可以,但是通常最常用的是3中遍历方式,即先序遍历,中序遍历、后序遍历。这3中遍历方式究竟是什么原理呢?它们都是按照从大到小,从整到零的思想来遍历的,我们知道树的结点的基本结构就3部分:结点自身、左子树以及右子树。因此遍历时无非就是要遍历某个结点、该结点的左结点、该结点的右结点。而该结点的子节点又是一棵树的根结点,有其左结点和右结点,那么对于层出不穷的结点究竟如何遍历呢?我们规定了3中遍历顺序,注意是规定了3中遍历顺序,没有什么理由。

所谓先序遍历就是指先访问根结点,再访问左结点,再访问右结点。注意,这里的访问顺序是对树中的任意子树都成立的,即对于任意子树,都要先访问根结点,再访问左结点和右结点。注意理解:遍历时总是从根结点开始逐个访问(访问到某个结点并不代表遍历到了这个结点),不管是先序、中序、后序,总是从根结点开始,如果是先序就先打印①,再去访问②③;如果是中序,虽然是先打印②再打印①,但是访问时还是先访问①,然后按照遍历顺序先去遍历它的左结点②,再遍历结点①。

对于上图中的二叉树,如果是先序遍历,那么先输出结点①,然后遍历左子树②再遍历右子树③,在遍历左子树时,由于结点②本身是子树的根结点,它又有子结点,因此按照定义(对于任意子树,都要先遍历根结点,再遍历其左结点和右结点),如果一个结点有子树,那么要先遍历完这个结点的子树之后才代表遍历完了这个结点,才能够继续遍历右子树,即所谓的先序遍历是指:先遍历根结点,再遍历根结点的左子树,再遍历根结点的右子树。即是遍历左右子树而不是左右结点,于是在遍历某个子树时,也要先遍历它的根结点(注意是结点),再遍历它的左子树(注意是子树)、再遍历它的右子树(注意是子树)。

同理对于中序遍历,对于当前访问到的结点,先遍历左子树(注意是子树),一直向下访问结点的左子树,当结点的左子树为null即没有左子树了时输出这个结点,即当左子树为null时遍历该子树根结点(注意是结点),然后访问该结点的右子树(注意是子树)。注意任何时候当访问的子树为null时表示没有子树了,就return。

同理对于后序遍历,访问总是从根结点开始,先遍历左子树(注意是子树),如果子树根结点又有子树那么就继续向下访问左子树,直到左子树为null,访问对应的右子树,同理还要向下访问左子树、右子树、当左子树右子树都为null时遍历null的根结点,表示该结点对应的子树遍历完成,之后return到上一层,遍历上一层的右子树,以此类推。

对于二叉树的遍历,只需要理解对于每一个子树的遍历顺序(根结点+左子树+右子树;左子树+根结点+右子树;左子树+右子树+根结点),即只需要理解在一个子树中的遍历顺序即可,在一个子树中确定遍历的return条件、递归方法调用顺序即可,然后使用递归来对整棵树进行递归遍历即可,千万不要按照递归展开后的顺序去理解二叉树的遍历,那样会很复杂很痛苦。即弄好一个循环单元,然后以此循环单元进行循环或者递归即可。

 

先序遍历:对于二叉树中的任意子树,都是先遍历子树的根结点,再遍历子树的左子树和右子树,因此当把二叉树按照先序遍历的顺序存放到字符串或者数组中之后,数组的第一个元素必然是根元素,除此之外不能给出更多的信息了。

 

中序遍历:对于二叉树中的任意子树,都是先遍历根结点的左子树,再遍历根结点,再遍历根结点的右子树,因此当把二叉树按照中序遍历的顺序存放到数组或者字符串中之后,如果已知根结点再数组中的位置i,那么在i左边的元素都是其左子树上的结点;在i右边的元素都是其右树上的结点。

 

后序遍历:对于二叉树中的任意子树,都是先遍历根结点的左子树,再遍历根结点的右子树,再遍历根结点,因此当把二叉树按照后序遍历的顺序存放到字符串或者数组中时,数组最后的一个元素必然就是二叉树的根结点,除此之外无法提供更多信息了。

你可能感兴趣的:(数据结构与算法(java实现))