二叉树的相关概念

二叉树的定义

二叉树(Binary Tree)是n(n>=0)个有限元素的集合,该集合或者为空,或者由一个称为根(root)的元素及两个不相交的,被称为左子树和右子树的二叉树组成。当集合为空时,称该二叉树为空二叉树,在二叉树中,一个元素也称为一个结点。

二叉树是有序的,即若将其左右子树颠倒,就称为另一颗不同的二叉树。

结点的度:结点所拥有的子树的个数称为该结点的度。

叶结点:度为0的结点称为叶结点,或者称为终端结点。

树的深度:树中所有结点的最大层数称为树的深度。

树的度:树中个结点度的最大值称为该树的度。

2.二叉树的三种遍历方式

二叉树有三种遍历方式:前序(父节点,左节点,右节点),中序(左节点,父节点,右节点),后序(左节点,右节点,父节点)。

二叉树遍历(先序、中序、后序)_结点

如上图所示的一颗二叉树,按照三种遍历方式所打印的结果应该是:

前序:1 2 4 8 9 5 10 11 3 6 7

中序:8 4 9 2 10 5 11 1 6 3 7

后序:8 9 4 10 11 5 2 6 7 3 1

 

遍历方式的代码:



import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Queue;

public class Main {
public static void main(String[] args) {

TreeNode root =new TreeNode(0);
TreeNode left=new TreeNode(1);
TreeNode right=new TreeNode(2);
TreeNode left2=new TreeNode(3);
TreeNode right2=new TreeNode(4);
TreeNode left3=new TreeNode(5);
TreeNode right3=new TreeNode(6);
TreeNode left4=new TreeNode(7);
TreeNode right4=new TreeNode(8);
left.left=left2;
left.right=right2;
right.left=left3;
right.right=right3;
root.left=left;
root.right=right;
left2.left=left4;
left2.right=right4;
Print.PrintTreeNode(root);

System.out.println("先序遍历:");
PreOrderTraverse(root);
System.out.println();
System.out.println("中序遍历:");
MidOrderTraverse(root);
System.out.println();
System.out.println("后序遍历:");
LastOrderTraverse(root);
System.out.println();
}

public static void PreOrderTraverse(TreeNode root){
TreeNode node=root;
if(node!=null){
System.out.print(node.val+" ");
PreOrderTraverse(node.left);
PreOrderTraverse(node.right);
}
}

public static void MidOrderTraverse(TreeNode root){
TreeNode node=root;
if(node!=null){
MidOrderTraverse(node.left);
System.out.print(node.val+" ");
MidOrderTraverse(node.right);
}
}

public static void LastOrderTraverse(TreeNode root){
TreeNode node=root;
if(node!=null){
LastOrderTraverse(node.left);
LastOrderTraverse(node.right);
System.out.print(node.val+" ");
}
}
}

class TreeNode {
int val;
TreeNode left;
TreeNode right;

TreeNode(int x) {
val = x;
}
}



class Print{
//打印TreeNode
public static void PrintTreeNode(TreeNode root){
ArrayList arrayList=PrintFromTopToBottom(root);
printTree(arrayList,arrayList.size());
}
//转换TreeNode为ArrayList
private static ArrayList<Integer> PrintFromTopToBottom(TreeNode root) {

ArrayList<Integer> list = new ArrayList();
if(root == null)
return list;

Queue<TreeNode> queue = new LinkedList();
queue.offer(root);

while(!queue.isEmpty()){
TreeNode treeNode = queue.poll();
list.add(treeNode.val);
if(treeNode.left != null)
queue.offer(treeNode.left);
if(treeNode.right != null)
queue.offer(treeNode.right);
}

return list;
}

//以树形打印ArrayList
private static void printTree(ArrayList array,int len){

int layers = (int)Math.floor(Math.log((double)len)/Math.log((double)2))+1; //树的层数
int maxWidth = (int)Math.pow(2,layers)-1; //树的最大宽度
int endSpacing = maxWidth;
int spacing;
int numberOfThisLayer;
for(int i=1;i<=layers;i++){ //从第一层开始,逐层打印
endSpacing = endSpacing/2; //每层打印之前需要打印的空格数
spacing = 2*endSpacing+1; //元素之间应该打印的空格数
numberOfThisLayer = (int)Math.pow(2, i-1); //该层要打印的元素总数

int j;
for(j=0;j<endSpacing;j++){
System.out.print(" ");
}

int beginIndex = (int)Math.pow(2,i-1)-1; //该层第一个元素对应的数组下标
for(j=1;j<=numberOfThisLayer;j++){
System.out.print(array.get(beginIndex++)+"");
for(int k=0;k<spacing;k++){ //打印元素之间的空格
System.out.print(" ");
}
if(beginIndex == len){ //已打印到最后一个元素
break;
}
}

System.out.println();
}
System.out.println();
}

}



0                              
1 2
3 4 5 6
7 8

先序遍历:
0 1 3 7 8 4 2 5 6
中序遍历:
7 3 8 1 4 0 5 2 6
后序遍历:
7 8 3 4 1 5 6 2 0

Process finished with exit code 0


非遍历方式的代码:

先序遍历:



public static void PreOrderTraverse(TreeNode root) {
TreeNode node = root;
Stack<TreeNode> stack = new Stack<TreeNode>();
while(node!=null||!stack.isEmpty()){
while(node!=null){
System.out.print(node.val+" ");
stack.push(node);
node=node.left;
}
if(!stack.isEmpty()){
node=stack.pop();
node=node.right;
}
}
}

public static void PreOrderTraverse2(TreeNode root){
Stack<TreeNode> stack=new Stack<TreeNode>();
TreeNode node=root;
stack.push(node);
while(!stack.isEmpty()){
node=stack.pop();
System.out.print(node.val+" ");
if(node.right!=null) {
stack.push(node.right);
}
if(node.left!=null){
stack.push(node.left);
}
}
}


第二种方式比较容易,效率也应该高一些。

中序遍历:



public static void MidOrderTraverse(TreeNode root){
TreeNode node = root;
Stack<TreeNode> stack = new Stack<TreeNode>();
while(node!=null||!stack.isEmpty()){
while(node!=null){

stack.push(node);
node=node.left;
}
if(!stack.isEmpty()){
node=stack.pop();
System.out.print(node.val+" ");
node=node.right;
}
}
}


后序遍历:



// 非递归后序遍历
public static void LastOrderTraverse(TreeNode root) {
Stack<TreeNode> treeNodeStack = new Stack<TreeNode>();
TreeNode node = root;
TreeNode lastVisit = root;
while (node != null || !treeNodeStack.isEmpty()) {
while (node != null) {
treeNodeStack.push(node);
node = node.left;
}
//查看当前栈顶元素
node = treeNodeStack.peek();
//如果其右子树也为空,或者右子树已经访问
//则可以直接输出当前节点的值
if (node.right == null || node.right == lastVisit) {
System.out.print(node.val + " ");
treeNodeStack.pop();
lastVisit = node;
node = null;
} else {
//否则,继续遍历右子树
node = node.right;
}
}
}