先序中序后序二叉树遍历
二叉树的遍历是二叉树结构中非常基础但是非常重要的题目,需要认真掌握
使用递归方法实现遍历,会发现代码非常的简单,这也可以看作是每种遍历方法的遍历整体的过程,其实完成的就是递归的操作,只是输出的时间不同。
public static class Node{
public int value;
public Node left;
public Node right;
public Node(int data){
this.value = data;
}
}
public static void preOrderRecur(Node head){
if(head == null){
return;
}
//打印放在最开始的地方就是先序遍历,打印放在中间位置,则是中序遍历,打印放在最后则是后序遍历。
System.out.print(head.value+" ");
preOrderRecur(head.left);
preOderRecur(head.right);
}
//中序遍历
public static void inOrderRecur(Node head){
if(head == null){
return;
}
inOrderRecur(head.left);
//打印放在最开始的地方就是先序遍历,打印放在中间位置,则是中序遍历,打印放在最后则是后序遍历。
System.out.print(head.value+" ");
inOderRecur(head.right);
}
//后序遍历
public static void posOrderRecur(Node head){
if(head == null){
return;
}
posOrderRecur(head.left);
posOderRecur(head.right);
//打印放在最开始的地方就是先序遍历,打印放在中间位置,则是中序遍历,打印放在最后则是后序遍历。
System.out.print(head.value+" ");
}
除了递归的方法解决题目,当然还有非递归的方法,只是相对而言代码稍微复杂一点,新建立一个堆栈,在堆栈中,先放入右边部分,后放入左边部分,这样在弹出的时候就可以先出左,再出右。
二叉树和栈有天然的匹配
二叉树总体结构从上到下,所以返回的结构是从下到上,如果采用队列的话,队列的结构也是从上到下,无法返回。
public static void preOrderUnrecur(Node head){
System.out.print("pre-order:");
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);
}
}
}
System.out.println();
}
//中序遍历
public static void inOrderUnRecur(Node head){
System.out.print("in-order:");
if(head != null){
Stack<Node> stack = new Stack<Node>();
while(!stack.isEmpty()||head!= null){
if(head != null){
stack.push(head);
head = head.left;
}else{
head = stack.pop();
System.out.print(head.value + " ");
head = head.right;
}
}
}
System.out.println();
}
//后序遍历,后序遍历中,建立两个栈,第一个栈按照中右左的方式进行保存,此时跟先序的思路近乎一样,之后再将第一个栈中的数据全部保存到第二个栈中,此时数据的保存格式为左右中的格式,然后再输出,则实现了后序遍历。
public static void posOrderUnRecur1(Node head){
System.out.print("pos-order:");
if(head != null){
Stack<Node> s1 = new Stack<Node>();
Stack<Node> s2 = new Stack<Node>();
s1.push(head);
while(!s1.isEmpty()){
head = s1.pop();
s2.push(head);
if(head.left != null){
s1.push(head.left);
}
if(head.right != null){
s1.push(head.right);
}
}
while(!s2.isEmpty()){
System.out.print(s2.pop().value+ " ");
}
}
System.out.println();
}
题目二:直观打印二叉树
略
题目三:在二叉树中寻找节点的后继节点
寻找后继节点和寻找前节点是基本相同的操作,可以自己写一写
public static Node getSuccessorNode(Node node){
if(node == null){
return node;
}
if(node.right != null){
return getleftMost(node.right);
}else{
Node parent = node.parent;
while(parent != null && parent.left != node){
node = parent;
parent = node.parent;
}
return parent;
}
}
public static Node getLeftMost(Node node){
if(node == null){
return node;
}
while(node.left != null){
node = node.left;
}
return node;
}
题目四:二叉树的序列化和反序列化
序列化:持久化,将结构用文件的形式记录下来就是序列化
反序列化:将文件形式记录的结构重新构造出来
二叉树的序列化:采用先序遍历的方法,在页节点的时候将所有的左右子节点的遍历为null的用特殊的标记进行表示,从而可以明确:当出现连续两个特殊标记的时候,意味着之前的节点为叶节点,从而可以明确每个二叉树节点在二叉树中的位置。
反序列化:
//序列化过程
public static String serialByPre(Node head){
if(head == null){
return "#!";
}
String res = head.value + "!";
res += serialByPre(head.left);
res += serialByPre(head.right);
return res;
}
//反序列化,中间新建一个队列,方便于数据的读取
public static Node reconByPreString(String preStr){
string[] values = preStr.split("!");
Queue<String> queue = new LinkedList<String>();
for(int i = 0;i != values.length; i++){
queue.offer(values[i]);
}
return reconPreOrder(queue);
}
//进行一个递归调用,实现复原
public static Node reconPreOrder(Queue<String> queue){
String value = queue.poll();
if(value.equals("#")){
return null;
}
Node head = new Node(Integer.valueOf(value));
head.left = reconPreOrder(queue);
head.right = reconPreOrder(queue);
return head;
}
判断一颗二叉树是否为平衡二叉树
平衡二叉树:左子树和右子树的长度差值小于等于1.
递归函数处理二叉树很好玩用
大的思路:每颗节点为头的子树全部都是平衡二叉树,同时左树高和右树高差值小于等于1,则整个二叉树为平衡二叉树。
套路:
- 列出可能性
- 整理出返回值的类型
- 整个递归过程按照同样的结构得到子树的信息,利用子树的信息,加工出我的信息,往上返回
public static boolean isBalance(Node head){
boolean[] res = new boolean[1];
res[0] = true;
getHight(head,1,res);
return res[0];
}
public static int getHight(Node head,int level,boolean[] res){
if(head == null){
return level;
}
int lH = getHight(head.left,level+1,res);
if(!res[0]){
return level;
}
int rH = getHeight(head.right,level+1,res);
if(!res[0]){
return level;
}
if(Math.abs(lH-rH)>1){
res[0] = false;
}
return Math.max(lH,rH);
}
判断一棵树是否为搜索二叉树,完全二叉树
搜索二叉树:对于任何节点而言,左子树都比他小,右子树都比他大。
搜索二叉树在中序遍历(左中右)中是按照从小到大的顺序。
public static boolean isBST(Node head){
if(head == null){
return true;
}
boolean res = true;
Node pre = null;
Node cur1 = head;
Node cur2 = null;
while(cur1 != null){
cur2 = cur1.left;
if(cur2 != null){
while(cur2.right != null && cur2.right != cur1){
cur2 = cur2.right;
}
if(cur2.right == null){
cur2.right = cur1;
cur1 = cur1.left;
continue;
}else{
cur2.right = null;
}
}
if(pre != null && pre.value > cur1.value){
res = false;
}
pre = cur1;
cur1 = cur1.right;
}
return res;
}
完全二叉树:
- 如果一个节点有右孩子没有左孩子则不可能是完全二叉树。
- 如果一个节点不是左右两个孩子都全,(有左没右,或者本节点为叶节点)后面遇到的所有节点都必须是叶节点。否则一定不是完全二叉树。
public static boolean isCBT(Node head){
if(head == null){
return true;
}
Queue<Node> queue = new LinkedList<Node>();
//判断叶节点阶段何时开启
boolean leaf = false;
Node l = null;
Node r = null;
queue.offer(head);
while(!queue.isEmpty()){
head = queue.poll();
l = head.left;
r = head.right;
//左边为空右边不为空或者开启了叶节点的阶段,则左右两个节点仍有子节点,则为false
if((leaf &&(l != null || r != null)) || (l == null && r!= null)){
return false;
}
if(l != null){
queue.offer(l);
}
if(r != null){
queue.offer(r);
}else{
leaf = true;
}
}
return true;
}
已知一颗完全二叉树,求其节点的个数
思路:完全二叉树只有当一层满了之后才会进入下一层,所以可以先从左边遍历长度,计算出完全二叉树的高度,然后再从右边遍历长度,判断跟左边长度是否相等,如果不相等,再递归判断右子树的最左边界和左右两边的长度哪边相等,如果跟左边长度相等则证明左子树为完全二叉树,如果跟右边长度相等,则证明右子树为完全二叉树。
public static int nodeNum(Node head){
if(head == null){
return 0;
}
//最开始计算出最大的高度
return bs(head,1,mostLeftLevel(head,1));
}
public static int bs(Node node,int l,int h){
if(l == h){
return 1;
}
//右子树的左最大高度如果跟h相同,则证明左子树为满二叉树,否则则证明右子树为满二叉树,可以计算出数目,下面(1<<(h-1))仅为优化后的写法,左移为放大,意味着2^(h-1)。
if(mostLeftLevel(node.right,l+1) == h){
return (1<<(h-l))+bs(node.right,l+1,h);
}else{
return(1<<(h-l-1))+bs(node.left,l+1,h);
}
}
//将最左边的的高度计算出来
public static int mostLeftLevel(Node node,int level){
while(node != null){
level++;
node = node.left;
}
return level-1;
}