一、树的基本概念
树是由一个集合以及在该集合上定义的一种关系构成的。集合中的关系称的结点,所定义的关系为父子关系最上层为根节点树是n(n>=o)个结点的有限集
a.一颗空树,b.有一个根节点的树,c.有许多子结点
结点的度:结点拥有子结点的数目
树的度:树内各节点最大的度数
树的深度:树中结点的最大层树
有序树:各节点从左到右有次序
二、二叉树
每个结点的度都不超过二的有序树,称为二叉树
满二叉树:高度为并且有个2^(k+1)-1结点的二叉树,每层的结点都达到最大数
完全二叉树:在一棵满二叉树中,在最下层最右侧起去点相邻的叶子结点得到的二叉树
满二叉树必为完全二叉树,反之不一定
二叉树的性质:
1.在二叉树的第i层上最多有2^(i-1) 个结点(根是第一层)
2.高度为h的二叉树最多有2^h -1个节点
3.对于任何一个二叉树,如果其终端节点数为n,度为2 的结点数为m,则n=m+1
4.如果一颗二叉树有n个结点的完全二叉树进行编号,则对任一结点(1<=i<=n)
5.若i=1,则i是二叉树的根、、
6.如果2i>n,则结点i无左孩子,否则其左孩子为2i
7.如果2i+1>n,则结点i无右孩子,否则其右孩子为2i+1
三、叉树的存储结构
1.顺序存储结构
对于满二叉树和完全二叉树来说,可以将其数据元素筑层放到一组连续的存储单元
如果不是满二叉树,则比较浪费空间
2.链式存储结构
若将其采用链式存储,则只需从树的根节点开始,将各个节点及其左右孩子使用链表存储即可。因此,图 1 对应的链式存储结构如图 2 所示:
二叉树链式存储结构示意图
二叉树遍历
遍历:按着某种次序访问树中所以二叉树,且每个节点恰好访问一次。人为的将非线性化线性化。
先序遍历DLR:根 左 右
中序遍历LDR:左子树 根 右子树
后序遍历LRD:左 右 根
Node.java
/**
*
*/
package com.liang.datastructure.btree;
/**
* 二叉树链表节点
* @author Administrator
*
*/
public class Node {
private Node leftChild;//左子树引用
private Object data;
private Node rightChild;
public Node(Object data) {
super();
this.data = data;
}
public Node(Node leftChild, Object data, Node rightChild) {
super();
this.leftChild = leftChild;
this.data = data;
this.rightChild = rightChild;
}
public Node getLeftChild() {
return leftChild;
}
public void setLeftChild(Node leftChild) {
this.leftChild = leftChild;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
public Node getRightChild() {
return rightChild;
}
public void setRightChild(Node rightChild) {
this.rightChild = rightChild;
}
@Override
public String toString() {
return "Node [leftChild=" + leftChild + ", data=" + data + ", rightChild=" + rightChild + "]";
}
}
BinaryTree.java
package com.liang.datastructure.btree;
/**
* 二叉树接口
* 可以有不同的实现类,每个类可以使用不同的存储结构,比如顺序结构、链式结构
* @author Administrator
*
*/
public interface BinaryTree {
/**
* 是否空树
* @return
*/
public boolean isEmpty();
/**
* 树结点数量
* @return
*/
public int size();
/**
* 获取二叉树的高度
* @return
*/
public int getHeight();
/**
* 查询指定值的结点
* @param value
* @return
*/
public Node findKey(int value); // 查找
/**
* 前序递归遍历
*/
public void preOrderTraverse();
/**
* 中序遍历递归操作
*/
public void inOrderTraverse();
/**
* 后序遍历递归操作
*/
public void postOrderTraverse();
/**
* 后序遍历递归操作
* @param node 树根结点
*/
public void postOrderTraverse(Node node);
/**
* 中序遍历非递归操作
* 1)对于任意节点current,若该节点不为空则将该节点压栈,并将左子树节点置为current,重复此操作,直到current为空。
* 2)若左子树为空,栈顶节点出栈,访问节点后将该节点的右子树置为current
* 3) 重复1、2步操作,直到current为空且栈内节点为空。
*/
public void inOrderByStack();
/**
* 前序遍历非递归操作
* 1)对于任意节点current,若该节点不为空则访问该节点后再将节点压栈,并将左子树节点置为current,重复此操作,直到current为空。
* 2)若左子树为空,栈顶节点出栈,将该节点的右子树置为current
* 3) 重复1、2步操作,直到current为空且栈内节点为空。
*/
public void preOrderByStack();
/**
* 后序遍历非递归操作
* 1)对于任意节点current,若该节点不为空则访问该节点后再将节点压栈,并将左子树节点置为current,重复此操作,直到current为空。
* 2)若左子树为空,取栈顶节点的右子树,如果右子树为空或右子树刚访问过,则访问该节点,并将preNode置为该节点
* 3) 重复1、2步操作,直到current为空且栈内节点为空。
*/
public void postOrderByStack();
/**
* 按照层次遍历二叉树
*/
public void levelOrderByQueue();
}
LinkedBinaryTree.java
/**
*
*/
package com.liang.datastructure.btree;
import java.util.Deque;
import java.util.LinkedList;
import java.util.Queue;
/**
* @author Administrator
*链式实现类
*/
public class LinkedBinaryTree implements BinaryTree{
private Node root;
public LinkedBinaryTree() {
super();
}
public LinkedBinaryTree(Node root) {
super();
this.root = root;
}
@Override
public boolean isEmpty() {
// TODO 自动生成的方法存根
return root == null;
}
@Override
public int size() {
return this.size(root);
}
private int size(Node node) {
if(node==null) {
return 0;
}else {
//左子树节点数
int l = this.size(node.getLeftChild());
//右子树节点数
int r=this.size(node.getRightChild());
return l+r+1;
}
}
@Override
public int getHeight() {
return getHeight(root);
}
private int getHeight(Node node) {
if(node==null) {
//System.out.println("-------------");
return 0;
}else {
int l = this.getHeight(node.getLeftChild());
//System.out.print("l值:"+l+" ");
int r=this.getHeight(node.getRightChild());
//System.out.print("r值:"+r+" ");
return l>r ? l+1:r+1;
}
}
@Override
public Node findKey(int value) {
return findKey(value,root);
}
public Node findKey(Object value,Node root) {
if(root == null){//递归结束条件1:结点为空,可能是整个树的根节点,也可能是递归调用中叶子节点中左孩子和右孩子
return null;
}else if(root != null && root.getData() == value){//递归的结束条件2:找到了
return root;
}else {//递归体
Node node1 = this.findKey(value, root.getLeftChild());
Node node2 = this.findKey(value, root.getRightChild());
if(node1 != null && node1.getData() == value){
return node1;
}else if(node2 != null && node2.getData() == value){
return node2;
}else{
return null;
}
}
}
@Override
public void preOrderTraverse() {
if(root != null){
//1.输出根结点的值
System.out.print(root.getData()+" ");
//2.对左子树进行先序遍历
//构建一个二叉树,根是左子树的根
BinaryTree leftTree = new LinkedBinaryTree(root.getLeftChild());
leftTree.preOrderTraverse();
//对右子树进行先序遍历
//3.构建一个二叉树,根是右子树的根
BinaryTree rightTree = new LinkedBinaryTree(root.getRightChild());
rightTree.preOrderTraverse();
}
}
@Override
public void inOrderTraverse() {
System.out.println("中序遍历:");
inOrderTraverse(root);
System.out.println();
}
private void inOrderTraverse(Node root) {
if(root!=null) {
this.inOrderTraverse(root.getLeftChild());
System.out.print(root.getData()+" ");
this.inOrderTraverse(root.getRightChild());
}
}
@Override
public void postOrderTraverse() {
System.out.println("后序遍历:");
postOrderTraverse(root);
System.out.println();
}
@Override
public void postOrderTraverse(Node node) {
if(node!=null) {
this.postOrderTraverse(node.getLeftChild());
this.postOrderTraverse(node.getRightChild());
System.out.print(node.getData()+" ");
}
}
@Override
public void inOrderByStack() {
System.out.println("中序非递归遍历:");
// 创建栈
Deque<Node> stack = new LinkedList<Node>();
Node current = root;
while (current != null || !stack.isEmpty()) {
while (current != null) {
stack.push(current);
current = current.getLeftChild();
}
if (!stack.isEmpty()) {
current = stack.pop();
System.out.print(current.getData() + " ");
current = current.getRightChild();
}
}
System.out.println();
}
@Override
public void preOrderByStack() {
// TODO 自动生成的方法存根
}
@Override
public void postOrderByStack() {
// TODO 自动生成的方法存根
}
@Override
public void levelOrderByQueue() {
System.out.println("按照层次遍历二叉树");
if(root == null) return;
Queue<Node> queue = new LinkedList<Node>() ;
queue.add(root);
while(queue.size() != 0)
{
int len = queue.size();
for(int i=0;i <len; i++)
{
Node temp = queue.poll();
System.out.print(temp.getData()+" ");
if(temp.getLeftChild() != null) queue.add(temp.getLeftChild());
if(temp.getRightChild() != null) queue.add(temp.getRightChild());
}
}
System.out.println();
}
}
测试
/**
*
*/
package com.liang.datastructure.btree;
/**
* @author Administrator
*
*/
public class Test {
public static void main(String[] args) {
//创建一个二叉树
Node node5=new Node(5);
Node node4 = new Node(null, 4, node5);
Node node7 = new Node(7);
Node node6 = new Node(null, 6, node7);
Node node3 = new Node(3);
Node node2 = new Node(node3, 2, node6);
Node node1 = new Node(node4, 1, node2);
BinaryTree btree=new LinkedBinaryTree(node1);
//判断二叉树是否为空
System.out.println(btree.isEmpty());
//先序遍历递归 1 4 5 2 3 6 7
System.out.println("先序遍历");
btree.preOrderTraverse();
System.out.println();
//中序遍历递归 4 5 1 3 2 6 7
btree.inOrderTraverse();
//后序遍历递归 5 4 3 7 6 2 1
btree.postOrderTraverse();
System.out.println(btree.getHeight());
System.out.println(btree.size());
//中序遍历非递归(借助栈) 4 5 1 3 2 6 7
//btree.inOrderByStack();
btree.levelOrderByQueue();
}
}