二叉树介绍
二叉树的概念:一棵二叉树是节点的一个有限集合,该集合或者为空,或者由一个根节点加上两棵左子树和右子树组成
二叉树具有如下特点:
1、每个结点最多有两棵子树,结点的度最大为2。
2、左子树和右子树是有顺序的,次序不能颠倒。
3、即使某结点只有一个子树,也要区分左右子树。
二叉树是递归定义的,其结点有左右子树之分,逻辑上二叉树有五种基本形态:
(1)空二叉树——如图(a);
(2)只有一个根结点的二叉树——如图(b);
(3)只有左子树——如图(c);
(4)只有右子树——如图(d);
(5)完全二叉树——如图(e)。
注意:尽管二叉树与树有许多相似之处,但二叉树不是树的特殊情形。
类型
(1)完全二叉树——若设二叉树的高度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第h层有叶子结点,并且叶子结点都是从左到右依次排布,这就是完全二叉树。
(2)满二叉树——除了叶结点外每一个结点都有左右子叶且叶子结点都处在最底层的二叉树。
(3)平衡二叉树——平衡二叉树又被称为AVL树(区别于AVL算法),它是一棵二叉排序树,且具有以下性质:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。
二叉排序树的遍历
二叉排序树(Binary Sort Tree),又称二叉查找树(Binary Search Tree),亦称二叉搜索树。
二叉排序树或者是一棵空树,或者是具有下列性质的二叉树:
(1)若左子树不空,则左子树上所有结点的值均小于它的根结点的值;
(2)若右子树不空,则右子树上所有结点的值均大于它的根结点的值;
(3)左、右子树也分别为二叉排序树;
(4)没有键值相等的节点。
注:遍历顺序根据根节点遍历顺序而定
先序遍历 (根 –> 左 –> 右)
首先访问根,再先序遍历左子树,最后先序遍历右子树
升序中序遍历 (左 –> 根 –> 右)
首先中序遍历左子树,再访问根,最后中序遍历右子树
无序后序遍历 (左 –> 右 –> 根)
首先后序遍历左子树,再后序遍历右子树,最后访问根
上图遍历结果
先序遍历:8 6 3 7 10 12
中序遍历:3 6 7 8 10 12
后序遍历:3 7 6 12 10 8
代码如下:
/**
* @author zjj
* 二叉排序树类
*/
public class BinaryTree {
/**
* 先序
*/
public static final int PRE_ORDER = 0;
/**
* 中序
*/
public static final int IN_ORDER = 1;
/**
* 后序
*/
public static final int POST_ORDER = 2;
/**
* root节点
*/
private Node root;
/**
* 添加节点
* @param data
*/
public void add(int data){
if (root == null){
root = new Node(data);
}else{
root.addNode(data);
}
}
/**
* 根据指定的顺序遍历二叉树
* PRE_ORDER :先序遍历
* IN_ORDER :中序遍历
* POST_ORDER :后序遍历
* @param order
*/
public void printBinaryTree(int order){
switch (order){
case PRE_ORDER:
root.preOrderTraversal();
break;
case IN_ORDER:
root.inOrderTraversal();
break;
case POST_ORDER:
root.postOrderTraversal();
break;
default:
System.out.println("传入的遍历顺序错误!");
}
}
/**
* 节点类
*/
class Node{
/**
数据
*/
private int data;
/**
* 左节点
*/
private Node left;
/**
* 右节点
*/
private Node right;
Node(int data) {
this.data = data;
}
/**
* 添加节点(左 or 右)
* @param data
*/
void addNode(int data){
// 左子树
if (this.data > data){
if (this.left == null){
this.left = new Node(data);
}else {
// 递归
this.left.addNode(data);
}
}else { // 右子树
if (this.right == null){
this.right = new Node(data);
}else {
this.right.addNode(data);
}
}
}
// 三种遍历方式
/**
* 先序遍历
* 根 -> 左 -> 右
*/
void preOrderTraversal(){
// 根
System.out.print(this.data + "\t");
// 递归遍历左
if (this.left != null){
this.left.preOrderTraversal();
}
// 递归遍历右
if (this.right != null) {
this.right.preOrderTraversal();
}
}
/**
* 中序遍历
* 左 -> 根 -> 右
*/
void inOrderTraversal(){
// 递归遍历左
if (this.left != null){
this.left.inOrderTraversal();
}
// 根
System.out.print(this.data + "\t");
// 递归遍历右
if (this.right != null) {
this.right.inOrderTraversal();
}
}
/**
* 后序遍历
* 左 -> 右 -> 根
*/
void postOrderTraversal(){
// 递归遍历左
if (this.left != null){
this.left.postOrderTraversal();
}
// 递归遍历右
if (this.right != null) {
this.right.postOrderTraversal();
}
// 根
System.out.print(this.data + "\t");
}
}
}
/**
* 测试类
* @author zjj
*/
public class BinaryTreeTest {
public static void main(String[] args) {
BinaryTree tree = new BinaryTree();
tree.add(8);
tree.add(6);
tree.add(3);
tree.add(7);
tree.add(10);
tree.add(12);
System.out.println("=============中序============");
tree.printBinaryTree(BinaryTree.IN_ORDER);
System.out.println("\n=============先序============");
tree.printBinaryTree(BinaryTree.PRE_ORDER);
System.out.println("\n=============后序============");
tree.printBinaryTree(BinaryTree.POST_ORDER);
}
}
程序运行结果:
=============中序============
3 6 7 8 10 12
=============先序============
8 6 3 7 10 12
=============后序============
3 7 6 12 10 8