二叉树是一种特殊的树形结构,每个节点最多有两个子节点,两个节点有左右之分,次序不能颠倒。一般使用递归来定义二叉树,因此与二叉树相关的问题都可以通过递归来解决,二叉树节点的定义如下:
1 class Node{
2 public int value=-1;
3 public Node leftNode;
4 public Node rightNode;
5 public Node(int val){
6 value=val;
7 }
8 public Node(){
9 this(null);
10 }
11 }
View Code
接下来介绍根据已知的二叉树结构,构造二叉树的方法。首先给出两个二叉树的结构,如下图所示:
1)根据已有的二叉树结构,生成节点数组,依据节点数组构造二叉树时。约定输入的正数表示其节点编号,负数表示节点不存在。从根节点开始,构造其左子树,如果此树上还有左子树,继续操作,直至没有左子树,然后构造右子树。以A为例说明生成节点数组的过程,设节点数组为nodeArr。首先访问根节点1(nodeArr=[1]),有左子树且根节点为2(nodeArr=[1,2]),以2为根节点继续访问,仍然有左子树且根节点为4(nodeArr=[1,2,4]),继续访问,没有左子树(nodeArr=[1,2,4,-1]),也没有右子树(nodeArr=[1,2,4,-1,-1]),返回到上层,访问2的右子树,且右子树根节点为5(nodeArr=[1,2,4,-1,-1,5]),发现5没有左节点和右节点(nodeArr=[1,2,4,-1,-1,5,-1,-1]),依此类推,最终A的节点数组为nodeArr=[1,2,4,-1,-1,5,-1,-1,3,-1,6,-1,-1]。同理,设B的节点数组为nodeArr2,有nodeArr2=[1,2,4,-1,-1,5,9,-1,-1,-1,3,6,7,-1,8,-1,-1,-1,-1]。
2)根据节点数组,生成二叉树,代码如下:
1 public class traversal {
2 static int step=0;
3 public static void main(String[] args){
4 int[] nodeArray=new int[]{1,2,4,-1,-1,5,-1,-1,3,-1,6,-1,-1};
5 int[] nodeArray2=new int[]{1,2,4,-1,-1,5,9,-1,-1,-1,3,6,7,-1,8,-1,-1,-1,-1};
6 Node root=new Node();
7 root=createBinaryTree(root,nodeArray2);
8 System.out.println("end");
9 }
10 public static Node createBinaryTree(Node root,int[] nodeArray ){
11 int val=-1;
12 try {
13 val = nodeArray[step];
14 step++;
15 }
16 catch (ArrayIndexOutOfBoundsException ex){
17 System.out.println("(ArrayIndexOutOfBounds,check the nodeArray");
18 }
19 if(val<0){
20 System.out.println("leaf node");
21 root=null;
22 return root;
23 }
24 root=new Node(val);///指向新对象
25 //step++;
26 root.leftNode=createBinaryTree(root.leftNode,nodeArray);
27 root.rightNode=createBinaryTree(root.rightNode,nodeArray);
28 return root;
29 }
30 }
31 class Node{
32 public int value=-1;
33 public Node leftNode;
34 public Node rightNode;
35 public Node(int val){
36 value=val;
37 }
38 public Node(){
39 }
40 }
View Code
3)结果如下所示:
动画演示:http://student.zjzk.cn/course_ware/data_structure/web/flashhtml/erchashujianli.htm
4)事实上,上述构造二叉树的过程是使用了二叉树的先序遍历完成的。在二叉树已经构造完成的基础上,分别完成先序遍历、中序遍历、后序遍历和层次遍历。
先序遍历:先访问根节点,再访问左节点,后访问右节点。如果左节点上还有左子树,继续访问其左节点,然后再访问右节点。
中序遍历:左节点、根节点、右节点。
后序遍历:左节点、右节点、根节点。
层次遍历:首先访问第0层,当i层所有节点访问完之后,再从左向右访问i+1层的各个节点。
使用递归的方法完成先序遍历、中序遍历、后序遍历,使用队列的方法完成层次遍历。代码如下:
1 import java.util.LinkedList;
2 import java.util.Queue;
3 public class traversal {
4 static int step=0;
5 public static void main(String[] args){
6 int[] nodeArray=new int[]{1,2,4,-1,-1,5,-1,-1,3,-1,6,-1,-1};
7 int[] nodeArray2=new int[]{1,2,4,-1,-1,5,9,-1,-1,-1,3,6,7,-1,8,-1,-1,-1,-1};
8 Node root=new Node();
9 root=createBinaryTree(root,nodeArray);
10 System.out.println("tree A:");
11 System.out.println("先序遍历:");
12 nlr(root);
13 System.out.println("\n" + "中序遍历:");
14 lnr(root);
15 System.out.println("\n" + "后序遍历:");
16 lrn(root);
17 System.out.println("\n" + "层次遍历:");
18 levelTraversal(root);
19 Node root2=new Node();
20 step=0;
21 root2=createBinaryTree(root2,nodeArray2);
22 System.out.println("\n"+"tree B:");
23 System.out.println("先序遍历:");
24 nlr(root2);
25 System.out.println("\n" + "中序遍历:");
26 lnr(root2);
27 System.out.println("\n" + "后序遍历:");
28 lrn(root2);
29 System.out.println("\n" + "层次遍历:");
30 levelTraversal(root2);
31 }
32 public static Node createBinaryTree(Node root,int[] nodeArray ){
33 int val=-1;
34 try {
35 val = nodeArray[step];
36 step++;
37 }
38 catch (ArrayIndexOutOfBoundsException ex){
39 System.out.println("(ArrayIndexOutOfBounds,check the nodeArray");
40 }
41 if(val<0){
42 //System.out.println("leaf node");
43 root=null;
44 return root;
45 }
46 root=new Node(val);///指向新对象
47 //step++;
48 root.leftNode=createBinaryTree(root.leftNode,nodeArray);
49 root.rightNode=createBinaryTree(root.rightNode,nodeArray);
50 return root;
51 }
52 public static void nlr(Node head){
53 if(head==null){
54 return;
55 }
56 System.out.print(head.value+"\t");
57 nlr(head.leftNode);
58 nlr(head.rightNode);
59 }
60 public static void lnr(Node head){
61 if(head==null){
62 return;
63 }
64 lnr(head.leftNode);
65 System.out.print(head.value + "\t");
66 lnr(head.rightNode);
67 }
68 public static void lrn(Node head){
69 if(head==null){
70 return;
71 }
72 lrn(head.leftNode);
73 lrn(head.rightNode);
74 System.out.print(head.value + "\t");
75 }
76 public static void levelTraversal(Node head){
77 Queue<Node> nodeQueue=new LinkedList<>();
78 nodeQueue.offer(head);
79 while(!nodeQueue.isEmpty()){
80 Node node=nodeQueue.poll();
81 System.out.print(node.value+"\t");
82 if (node.leftNode!=null){
83 nodeQueue.offer(node.leftNode);
84 }
85 if(node.rightNode!=null){
86 nodeQueue.offer(node.rightNode);
87 }
88 }
89 return;
90 }
91 }
92 class Node{
93 public int value=-1;
94 public Node leftNode;
95 public Node rightNode;
96 public Node(int val){
97 value=val;
98 }
99 public Node(){
100 }
101 }
View Code
运行结果图:
三种遍历的非递归实现:
1 //非递归形式的先序遍历
2 public static void nlr2(Node head){
3 if (head!=null){
4 return;
5 }
6 Stack<Node> stack=new Stack<>();
7 stack.push(head);
8 while (!stack.empty()){
9 Node temp=stack.peek();
10 System.out.println(temp.value+"\t");
11 stack.pop();
12 if(temp.rightNode!=null){
13 stack.push(temp.rightNode);
14 }
15 if(temp.leftNode!=null){
16 stack.push(temp.leftNode);
17 }
18 }
19
20 }
21
22 void lnr2(Node *root)//非递归中序遍历
23 {
24 stack<Node *> stk;
25 Node *p = root;
26 while (p != NULL || !stk.empty())
27 {
28 if (p != NULL)
29 stk.push(p), p = p->left;
30 else
31 {
32 p = stk.top(); stk.pop();
33 printf("%d ", p->val);
34 p = p->right;
35 }
36 }
37 }
38 //非递归形式的后序遍历
39 public static void lrn2(Node head){
40 if(head==null){
41 return;
42 }
43 Stack<Node> stack1=new Stack<>();
44 Stack<Node> stack2=new Stack<>();
45 stack1.push(head);
46 while (!stack1.empty()){
47 Node tmp=stack1.peek();
48 stack1.pop();
49 stack2.push(tmp);
50 if(tmp.leftNode!=null){
51 stack1.push(tmp.leftNode);
52 }
53 if(tmp.rightNode!=null){
54 stack1.push(tmp.rightNode);
55 }
56 }
57 while (!stack2.empty()){
58 System.out.print(stack2.pop().value + "\t");
59 }
60 }
View Code
参考:http://noalgo.info/832.html
更多代码:
import java.util.*;
/**
* Created by hfz on 2016/7/5.
*/
public class traversal {
static int step=0;
public static void main(String[] args){
int[] nodeArray=new int[]{1,2,4,-1,-1,5,-1,-1,3,-1,6,-1,-1};
int[] nodeArray2=new int[]{1,2,4,-1,-1,5,9,-1,-1,-1,3,6,7,-1,8,-1,-1,-1,-1};
Node root=new Node();
root=createBinaryTree(root,nodeArray);
System.out.println("tree A:");
System.out.println("先序遍历:");
nlr(root);
System.out.println("\n" + "非递归先序遍历:");
unRecurNLR(root);
nlr2(root);
System.out.println("\n" + "中序遍历:");
lnr(root);
System.out.println("\n" + "非递归中序遍历:");
unRecurLNR2(root);
System.out.println("\n" + "后序遍历:");
lrn(root);
System.out.println("\n" + "层次遍历:");
levelTraversal(root);
System.out.printf("%n二叉树叶子节点数量%n%d", getLeafNodeNum(root));
System.out.println("\n" + "二叉树节点总个数:");
System.out.print(calNodeAmounts(root));
System.out.println("\n" + "二叉树深度:");
int i=0;
System.out.print(calDepth(root, i));
int k=2;
System.out.printf("%n第1层到第%d层节点总个数%n",k);
System.out.print(calKLevalNodeAmounts(root, k, 1));
System.out.print(String.format("%n第%d层节点个数为%n%d", k, calKthLevel(root, k)));
Node root2=new Node();
step=0;
root2=createBinaryTree(root2,nodeArray2);
System.out.println("\n"+"tree B:");
System.out.println("先序遍历:");
nlr(root2);
System.out.println("\n" + "非递归先序遍历:");
unRecurNLR(root2);
System.out.println("\n" + "中序遍历:");
lnr(root2);
System.out.println("\n" + "非递归中序遍历:");
unRecurLNR2(root2);
System.out.println("\n" + "后序遍历:");
lrn(root2);
System.out.println("\n" + "层次遍历:");
levelTraversal(root2);
System.out.printf("%n二叉树叶子节点数量%n%d", getLeafNodeNum(root2));
System.out.println("\n" + "二叉树节点个数:");
System.out.print(calNodeAmounts(root2));
System.out.println("\n" + "二叉树深度:");
System.out.print(calDepth(root2, i));
k=4;
System.out.print(String.format("%n第1层到第%d层节点总个数为:%n%d", k, calKLevalNodeAmounts(root2, k, 1)));
System.out.print(String.format("%n第%d层节点个数为:%n%d", k, calKthLevel(root2, k)));
System.out.printf("%ntree A和tree B 结构是否相同:%n%b",structureCmp(root,root2));
}
// 创建二叉树
public static Node createBinaryTree(Node root,int[] nodeArray ){
int val=-1;
try {
val = nodeArray[step];
step++;
}
catch (ArrayIndexOutOfBoundsException ex){
System.out.println("(ArrayIndexOutOfBounds,check the nodeArray");
}
if(val<0){
//System.out.println("leaf node");
root=null;
return root;
}
root=new Node(val);///指向新对象
//step++;
root.leftNode=createBinaryTree(root.leftNode,nodeArray);
root.rightNode=createBinaryTree(root.rightNode,nodeArray);
return root;
}
//先序遍历
public static void nlr(Node head){
if(head==null){
return;
}
System.out.print(head.value+"\t");
nlr(head.leftNode);
nlr(head.rightNode);
}
//非递归形式的先序遍历
/*
1)申请一个栈来存放节点,首先存入根节点
2)弹出栈顶节点并打印其值,记为cur,将栈顶节点(cur)的右节点(如果有的话)入栈,将栈顶节点(cur)的左节点入栈
3)重复2,直至栈为空
*/
public static void unRecurNLR(Node root){
Stack<Node> stack=new Stack<>();
Node cur=root;
Node rightNode=null;
Node leftNode=null;
if(cur==null){
return;
}
stack.push(cur);
while(!stack.empty()){
cur=stack.pop();
System.out.print(cur.value + "\t");
rightNode=cur.rightNode;
leftNode=cur.leftNode;
if(rightNode!=null){
stack.push(rightNode);
}
if(leftNode!=null){
stack.push(leftNode);
}
}
}
public static void nlr2(Node head){
Stack<Node> stack=new Stack<>();
ArrayList<Integer> list=new ArrayList<>();
stack.push(head);
while (!stack.empty()){
Node temp=stack.peek();
list.add(temp.value);
stack.pop();
if(temp.rightNode!=null){
stack.push(temp.rightNode);
}
if(temp.leftNode!=null){
stack.push(temp.leftNode);
}
}
Integer[] rr=list.toArray(new Integer[]{} );
System.out.println(Arrays.toString(rr));
}
//中序遍历
public static void lnr(Node head){
if(head==null){
return;
}
lnr(head.leftNode);
System.out.print(head.value + "\t");
lnr(head.rightNode);
}
//非递归形式的中序遍历(自己编写)
/*
1)申请栈存放节点,令cur=head
2)将cur指向的节点入栈
3)令cur=cur.leftNode,如果cur!=null,转2,如果栈为空,算法结束,否则弹出cur指向的节点(栈顶节点)node,并打印node
4)弹出栈顶节点后,令cur=node.right,转2
*/
public static void unRecurLNR(Node head){
Node cur=head;
//Node leftNode=null;
//Node rightNode=null;
Stack<Node> stack=new Stack<>();
stack.push(cur);
while (!stack.empty()){
while (cur!=null) {
cur=cur.leftNode;
if(cur!=null)
stack.push(cur);
}
cur=stack.pop();
System.out.print(cur.value+"\t");
cur=cur.rightNode;
if(cur!=null)
stack.push(cur);
}
}
//非递归形式的中序遍历(书上编写),形式更加简洁。
public static void unRecurLNR2(Node head){
if(head!=null){
Node cur=head;
Stack<Node> stack=new Stack<>();
//stack.push(cur);
while (!stack.empty()||cur!=null){
if(cur!=null){
stack.push(cur);
cur=cur.leftNode;
}
else{
cur=stack.pop();
System.out.print(cur.value+"\t");
cur=cur.rightNode;
}
}
}
}
//后序遍历
public static void lrn(Node head){
if(head==null){
return;
}
lrn(head.leftNode);
lrn(head.rightNode);
System.out.print(head.value + "\t");
}
//层次遍历
public static void levelTraversal(Node head){
Queue<Node> nodeQueue=new LinkedList<>();
nodeQueue.offer(head);
while(!nodeQueue.isEmpty()){
Node node=nodeQueue.poll();
System.out.print(node.value+"\t");
if (node.leftNode!=null){
nodeQueue.offer(node.leftNode);
}
if(node.rightNode!=null){
nodeQueue.offer(node.rightNode);
}
}
return;
}
//计算二叉树节点总个数
public static int calNodeAmounts(Node head){
if(head==null){
return 0;
}
return calNodeAmounts(head.leftNode)+calNodeAmounts(head.rightNode)+1;
}
//计算二叉树深度(自己编写)
public static int calDepth(Node head,int counter){
if(head==null){
return counter;
}
else {
counter++;
}
int a=calDepth(head.leftNode,counter);
int b=calDepth(head.rightNode,counter);
return a>b?a:b;
}
//计算二叉树深度(更好实现)
public static int calDept2(Node head){
if(head==null){
return 0;
}
int leftDepth=calDept2(head.leftNode);
int rightDepth=calDept2(head.rightNode);
return leftDepth>rightDepth?leftDepth+1:rightDepth+1;
}
//第1层到第k层节点总数量(自己编写)
public static int calKLevalNodeAmounts(Node head,int KLevel,int currentLevel){
if(head==null){
return 0;
}
if(currentLevel<= KLevel){
return calKLevalNodeAmounts(head.leftNode,KLevel,currentLevel+1)+calKLevalNodeAmounts(head.rightNode,
KLevel,currentLevel+1)+1;
}
return 0;
}
//第k层节点数量
public static int calKthLevel(Node head,int k){
if(head==null||k<1){
return 0;
}
if(k==1){
return 1;
}
int leftAmounts=calKthLevel(head.leftNode,k-1);
int rightAmounts=calKthLevel(head.rightNode,k-1);
return leftAmounts+rightAmounts;
}
//计算叶子节点个数
public static int getLeafNodeNum(Node head){
if(head==null){
return 0;
}
if(head.leftNode==null&&head.rightNode==null){
return 1;
}
int leftNum=getLeafNodeNum(head.leftNode);
int rightNum=getLeafNodeNum(head.rightNode);
return leftNum+rightNum;
}
//判断两个二叉树结构是否相同
public static boolean structureCmp(Node head1,Node head2){
if(head1==null&&head2==null){
return true;
}
else if(head1==null||head2==null){
return false;
}
boolean leftResult=structureCmp(head1.leftNode,head2.leftNode);
boolean rightResult=structureCmp(head1.rightNode,head2.rightNode);
return leftResult&&rightResult;
}
//求二叉树的镜像
public static Node Mirror(Node head){
if(head==null){
return null;
}
Node leftNode=Mirror(head.leftNode);
Node rightNode=Mirror(head.rightNode);
head.leftNode=rightNode;
head.rightNode=leftNode;
return head;
}
}
class Node{
public int value=-1;
public Node leftNode;
public Node rightNode;
public Node(int val){
value=val;
}
public Node(){
}
}
View Code