algorithm-binary-tree-fml-order

二叉树是数据结构里经常使用的一种数据结构,需要注意其和树的区别(二叉树的一个节点最多只能有2个子树,而树没这个限制),还有完全二叉树和满二叉树。

创建如下图的一颗二叉树:

这里写图片描述

####一、创建二叉树

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
public class BinaryTree {
private Node root=null;

public BinaryTree(){
root=new Node("A");
}

/**
* 创建一颗二叉树
* @param root
*/

public void createBinaryTree(Node root){
Node nodeB=new Node("B");
Node nodeC=new Node("C");
Node nodeD=new Node("D");
Node nodeE=new Node("E");
Node nodeF=new Node("F");
Node nodeG=new Node("G");
Node nodeH=new Node("H");
Node nodeI=new Node("I");
Node nodeM=new Node("M");
Node nodeN=new Node("N");

root.leftChild=nodeB;
root.rightChild=nodeC;
nodeB.leftChild=nodeD;
nodeB.rightChild=nodeE;
nodeD.leftChild=nodeH;
nodeC.leftChild=nodeF;
nodeC.rightChild=nodeG;
nodeE.rightChild=nodeI;
nodeI.leftChild=nodeM;
nodeI.rightChild=nodeN;
}

/**
* 二叉树结点
* @author: lixiaolin
* @CreateDate: 2015-10-14 下午10:18:35
* @version: 1.0
*/


private class Node{
private String data;
private Node leftChild;
private Node rightChild;

public Node(){
}

public Node(String data){
this.data=data;
this.leftChild=null;
this.rightChild=null;
}
}

####二、遍历二叉树
遍历是二叉树经常使用的操作。
常用的遍历方式有先序、中序、后序,这个是针对跟节点的访问顺序而言的。
下面先给出递归遍历二叉树的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
/**
* 先序递归遍历
* @param root
*/

public void preOrder(Node root){
if(root==null){
return;
}
visted(root);
preOrder(root.leftChild);
preOrder(root.rightChild);
}

/**
* 中序递归遍历
* @param root
*/

public void inOrder(Node root){
if(root==null){
return ;
}
inOrder(root.leftChild);
visted(root);
inOrder(root.rightChild);
}

/**
* 后序递归遍历
* @param root
*/

public void postOrder(Node root){
if(root==null){
return ;
}
postOrder(root.leftChild);
postOrder(root.rightChild);
visted(root);
}

####三、非递归遍历
先序遍历和中序遍历的思路差不多,都在先遍历完所有的左子树,将之存储到栈中,利用栈的先进后出的特点,碰到有右子树的节点,先将其输出,然后加入栈中。
后序的思路不一样。要保证根结点在左孩子和右孩子访问之后才能访问,因此对于任一结点P,先将其入栈。如果P不存在左孩子和右孩子,则可以直接访问它;或者P存在左孩子或者右孩子,但是其左孩子和右孩子都已被访问过了,则同样可以直接访问该结点。若非上述两种情况,则将P的右孩子和左孩子依次入栈,这样就保证了每次取栈顶元素的时候,左孩子在右孩子前面被访问,左孩子和右孩子都在根结点前面被访问。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
/**
* 非递归先序遍历
* @param root
*/
public void noRecPreOrder(Node root){
if(root==null){
return ;
}
Node node=root;
Stack<Node> stack=new Stack<Node>();
while(node!=null){
visted(node);
stack.push(node);
node=node.leftChild;

}
while(!stack.empty()){
node=stack.pop();
node=node.rightChild;
while(node!=null){
visted(node);
stack.push(node);
node=node.leftChild;

}
}

}

/**
* 非递归实现中序遍历
* @param root
*/
public void noRecInOrder(Node root){
if(root==null){
return;
}
Stack<Node> stack=new Stack<Node> ();
Node node=root;
while(node!=null){
stack.push(node);
node=node.leftChild;

}

while(!stack.empty()){
node=stack.pop();
visted(node);
node=node.rightChild;

while(node!=null){
stack.push(node);
node=node.leftChild;

}
}
}

/**
* 非递归后序遍历
* @param root
*/
public void noRecPostOrder(Node root){
if(root==null){
return;
}
Stack<Node> stack=new Stack<Node>();
Node node=root;
Node preVisted=null;
stack.push(node);
while(!stack.isEmpty()){

node=stack.peek();
if((node.leftChild==null&&node.rightChild==null)||(preVisted!=null&&(node.leftChild==preVisted||node.rightChild==preVisted))){
node=stack.pop();
visted(node);
preVisted=node;
}else{

if(node.rightChild!=null){
stack.push(node.rightChild);
}
if(node.leftChild!=null){
stack.push(node.leftChild);
}
}
}

}