二叉树基本操作学习记录
二叉树的递归:先中后序
//前序法
public static void preamble(Node node) {
if(node==null) {
return;
}
System.out.print(node.value+" ");
Node.preamble(node.left);
Node.preamble(node.right);
}
//中序法
public static void inorder(Node node) {
if(node==null) {
return;
}
Node.preamble(node.left);
System.out.print(node.value+" ");
Node.preamble(node.right);
}
//后序法
public static void postorder(Node node) {
if(node==null) {
return;
}
Node.preamble(node.left);
Node.preamble(node.right);
System.out.print(node.value+" ");
}
二叉树非递归:先中后序
先序:先将头节点放入栈中,再将头结点弹出,对弹出的节点处理,在压入右节点,再压入左节点。
中序:将左边界存入栈中,当无左边界节点存入是在执行弹栈,对弹出的节点处理,并且将它的右节点视为左边界存入栈中。
后序:先将头节点存入栈1中,在弹出节点,将弹出节点存入栈2中,最后将栈2弹栈,对弹出的节点处理。
//非递归前序法
public static void preamble_stack(Node node) {
if(node==null) {
System.out.println("空树");
return;
}
Stack stack=new Stack();
//先将第一个节点放入栈中
stack.push(node);
//根据栈是否为空作为条件
while(!stack.isEmpty()) {
//弹栈,并且收弹出的元素
Node popnode=(Node) stack.pop();
//对弹出的元素操作
System.out.print(popnode.value+" ");
//判断弹出的元素的右子树
if(popnode.right!=null) {
stack.push(popnode.right);
}
//判断弹出的元素的左子树
if(popnode.left!=null) {
stack.push(popnode.left);
}
}
}
//非递归后序法
public static void postorder_stack(Node node) {
if(node==null) {
System.out.println("空树");
return;
}
//作为弹栈
Stack stackpop=new Stack();
//存储栈
Stack stacksave=new Stack();
stackpop.push(node);
while(!stackpop.isEmpty()) {
Node popnode=(Node) stackpop.pop();
//对弹出的节点,存入stacksave中
stacksave.push(popnode);
if(popnode.left!=null) {
stackpop.push(popnode.left);
}
if(popnode.right!=null) {
stackpop.push(popnode.right);
}
}
while(!stacksave.isEmpty()) {
Node popnode=(Node) stacksave.pop();
System.out.print(popnode.value+" ");
}
}
//非递归中序法
public static void inorder_stack(Node node) {
if(node==null) {
System.out.println("空树");
return;
}
//先将左边所有的节点放入栈中
Stack stack=new Stack();
Node cur=node;
stack.push(cur);
while(!stack.isEmpty()) {
//判断当前左节点是否为空
if(cur.left!=null) {
cur=cur.left;
stack.push(cur);
}else {
//开始弹栈
Node popnode=(Node) stack.pop();
System.out.print(popnode.value+" ");
//对弹出节点右节点判断如果不为空,入栈,并且将cur设置为右节点,将它视为开始时的左边界。
if(popnode.right!=null) {
stack.push(popnode.right);
cur=popnode.right;
}
}
}
}
二叉树宽度优先遍历:常见题目求二叉树的宽度
第一个面临的问题:如何判断节点是第几层?取得出队列节点的层数,出队列节点的左右子树层数为出队列节点层数加1。左右子树必是第二层。
第二个面临的问题:如何计算每层的节点数?设置一个当前层,这个当前层是1,然后拿到出队列的节点层数,比较当前层与节点层是否相同,如果相同表示当前层的节点数+1,如果不相同表示出队列的节点层会大于当前层,并且当前层的节点数已计算完,这时可以比较最大值,将当前层+1。
public static int maxwidth(Node node) {
if(node==null) {
return 0;
}
int max=Integer.MIN_VALUE;//最大宽度
int curLevel=1;//当前层
HashMap<Node,Integer> map=new HashMap();//存放每个节点的层数
map.put(node,1);
int curLevelNodes=0;//当前层的节点个数
Queue<Node> queue=new LinkedList();
queue.add(node);
while(!queue.isEmpty()) {
Node curNode=queue.poll();
int curNodeLevel=map.get(curNode);//取得当前节点的层数
//取得当前层的节点数,
if(curNodeLevel==curLevel) {
curLevelNodes++;
}else {
max=Math.max(max, curLevelNodes);
curLevel++;
curLevelNodes=1;
}
//将左右子树入队列,并且设置层数
if(curNode.left!=null) {
queue.add(curNode.left);
map.put(curNode.left, curNodeLevel+1);
}
if(curNode.right!=null) {
queue.add(curNode.right);
map.put(curNode.right, curNodeLevel+1);
}
}
//1~n-1层中最大的数与第n层比较
max=Math.max(max, curLevelNodes);
return max;
}
总结:关注点在当前层与节点层的关系,当前层只可能等于或小于节点层。等于说明当前层有这个节点,小于说明当前已经没有其他节点了。队列出队与入队是二叉数的宽度优先遍历。