二叉树节点结构
class Node<V>{
V value;
Node left;
Node right;
}
用递归和非递归两种方式实现二叉树的先序、中序、后序遍历
二叉树宽度
递归序列
递归的顺序,先遍历左侧走到头碰到null,就往回左右遍历。
先序打印节点(头左右):1,2,4,5,3,6,7
中序(左头右):4,2,5,1,6,3,7
后序(左右头):4,5,2,6,7,3,1
class Node<V>{
V value;
Node left;
Node right;
}
public void f(Node head){//递归
if (head==null){
return;
}
f(head.left);
f(head.right);
}
public void pre(Node head){//前序遍历
if(head==null){
return;
}
System.out.print(head.value);
pre(head.left);
pre(head.right);
}
public void mid(Node head){//中序遍历
if(head==null){
return;
}
mid(head.left);
System.out.print(head.value);//只在他来到第二个节点打印值
mid(head.right);
}
public static void main(String[] args) {
}
非递归
前序思想:
- 进入头节点,弹出
- 进入左右子节点,弹出
中序思想:
方法1:
3. 构建两个栈,收集栈存放弹出的节点
4. 先做后右
5. 最后弹出收集栈的节点即为中序遍历
方法2:
6. 将左子树都进栈,然后弹出节点
7. 判断弹出节点是否有右子节点,有就进栈,
8. 然后判断是否有左子节点,全部进栈,然后弹出
9. 方法2原理:整棵树都可以看成左倾,一直在做“左头”,右子树也在做“左头”操作,就忽略“右概念”了。
![](https://i-blog.csdnimg.cn/blog_migrate/95b3ef87b4ea48dbf709545ef3db0233.png)
![](https://i-blog.csdnimg.cn/blog_migrate/4598526162d44dbc489e56b2775fd3fc.png)
public void pre1(Node head){//先序遍历
if (head!=null){
Stack<Node> stack=new Stack<Node>();//准备一个栈
stack.add(head);//先把头结点压入到占中
while(!stack.isEmpty()){
head=stack.pop();//弹出节点
System.out.print(head.value);
if(head.right!=null){
stack.push(head.right);//先压右
}if(head.left!=null){
stack.push(head.left);//先压右
}
}
}
}
public void mid1(Node head){//中序法1
if (head!=null){
Stack<Node> stack=new Stack<Node>();//准备一个栈
Stack<Node> stack1=new Stack<Node>();//准备一个栈
stack.add(head);//先把头结点压入到占中
while(!stack.isEmpty()){
head=stack.pop();//弹出节点
stack1.push(head);
if(head.left!=null){
stack.push(head.left);//先压左
}
if(head.right!=null){
stack.push(head.right);//先压右
}
}
while(!stack1.isEmpty()){
System.out.print(stack1.pop());
}
}
public void mid2(Node head){//法2:
if (head!=null){
Stack<Node> stack=new Stack<Node>();//准备一个栈
//如何将所有左子树进栈?不会。
while(!stack.isEmpty()||head!=null){
if(head!=null){//老师思路:周而复始使左子树进栈,移动head.left,最终会到达一个null,就结束循环
stack.push(head);
head=head.left;
}else{
head=stack.pop();
System.out.print(head.value);
head=head.right;//结束后进栈,跳到条件一判断是否有左节点
}
}
}
}
宽度遍历
思想:额外空间:队列
- 先进左后进右
- 弹出节点,判断该节点是否有子节点,进队列
public void w(Node head){//宽度遍历
if(head==null){
return;
}
Queue<Node> queue=new LinkedList<>();//双向链表可以当做队列用
queue.add(head);
while(!queue.isEmpty()){
Node cur=queue.poll();
System.out.print(cur.value);
if(cur.left!=null){//先放左
queue.add(cur.left);
}if (cur.right!=null){//后放右
queue.add(cur.right);
}
}
}
题目:判断二叉树中哪一层节点最多?
问题:需要找出第几层,有几个节点
提示:准备一张哈希表(key为节点,value为节点个数)
思想:
- 准备一张哈希表(key为节点,value为节点个数)
- 初始化话当前层、当前层节点数
- 首先根据宽度遍历思想,队列操作
- 弹出节点时(对应层数map中的value)判断该节点是否属于当前层,属于就节点+1,不属于就比较节点数,初始化当前节点数,层数+1
public void w(Node head){
if(head==null){
return;
}
Queue<Node> queue=new LinkedList<>();//双向链表可以当做队列用
queue.add(head);
HashMap<Node,Integer> levelmap=new HashMap<>();
levelmap.put(head, 1);//头节点在第一层
int curlevel=1;//当前层
int curlevelNodes=0;//当前层有几个节点
int max=Integer.MIN_VALUE;//最大的一层
while(!queue.isEmpty()){
Node cur=queue.poll();
int curNodelevel=levelmap.get(cur);//弹出一个节点得到节点层数map中的value
if(curNodelevel==curlevel){
curlevelNodes++;//弹出的节点层与当前统计层一样,就+1一个节点
}else{//当前层结束
max=Math.max(max,curlevelNodes);
curlevel++;//当前层要加一层
curlevelNodes=0;//清空
}
if(cur.left!=null){
levelmap.put(cur.left, curNodelevel+1);//上一个节点的下一层
queue.add(cur.left);
}if (cur.right!=null){
levelmap.put(cur.right,curNodelevel+1);//记录节点所在层数
queue.add(cur.right);
}
//
System.out.print(cur.value);
if(cur.left!=null){//先放左
queue.add(cur.left);
}if (cur.right!=null){//后放右
queue.add(cur.right);
}
}
}