树的概念:
树是数据元素之间具有次层关系的非线性的结构,树是由n(n≥0)个结点组成的有限集合,n=0的树是空树。
二叉树:
二叉树(Binary Tree)是n(n≥0)个结点组成的有限集合,n=0时称为空二叉树;n>0的二叉树由一个根结点和两棵互不相交、分别称为左子树和右子树的子二叉树构成,二叉树也是递归定义的,在树种定义的度、层次等术语,同样适用于二叉树。
完全二叉树:
对于一个具有n个结点的二叉树按层序编号,如果编号为i(1-n)的结点与同样深度的满二叉树编号为i的结点在二叉树中位置完全相同,则这颗二叉树称为完全二叉树。
二叉树的性质:
性质1:在二叉树的第i层上至多有2i-1个结点(i>=1)。
性质2:深度为k的二叉树至多有2k-1个结点(k>=1)。
性质3:对任何一颗二叉树T,如果其终端结点数为n0,度为2的结点数为n2,则n0 = n2+1.
性质4:具有n个结点的完全二叉树深度为[log2n]+1。 ([x]表示不大于x的最大整数)。
性质5:如果对一颗有n个结点的完全二叉树(其深度为[log2n]+1) 的结点按层序编号(从第1层到第[log2n]+1层,每层从左到 右),对任意一个结点i(1<=i<=n)有:
1)如果i=1,则结点i是二叉树的根,无双亲;如果i>1,则其双亲是结点[i/2]
2)如果2i>n,则结点i无左孩子(结点i为叶子结点);否则其左孩 子是结点2i。
3)如果2i+1>n,则结点i无右孩子;否则其右孩子是结点2i+1。
二叉树的遍历:
前序遍历:根->左->右(左图:ABDGHCEIF)
中序遍历:左->根->右(中图:GDHBAEICF)
后序遍历:左->右->根(右图:GHDBIEFCA)
性质1:在二叉树的第i层上至多有2i-1个结点(i>=1)。
package com.structures.tree;
import java.util.ArrayList;
import java.util.Stack;
public class BinaryTree {
private TreeNode root=null;
public BinaryTree(){
root=new TreeNode(1,"A");
}
public void createBinaryTree(){
TreeNode nodeB=new TreeNode(2,"B");
TreeNode nodeC=new TreeNode(3,"C");
TreeNode nodeD=new TreeNode(4,"D");
TreeNode nodeE=new TreeNode(5,"E");
TreeNode nodeF=new TreeNode(6,"F");
root.leftChild=nodeB;
root.rightChild=nodeC;
nodeB.leftChild=nodeD;
nodeB.rightChild=nodeE;
nodeC.rightChild=nodeF;
}
/**
* 求二叉树的高度
*/
public int getHeight(){
return getHeight(root);
}
private int getHeight(TreeNode node) {
if(node==null){
return 0;
}else{
int i=getHeight(node.leftChild);
int j=getHeight(node.rightChild);
return (i<j)?j+1:i+1;
}
}
/**
* 获取二叉树的大小
*/
public int getSize(){
return getSize(root);
}
private int getSize(TreeNode node) {
if(node==null){
return 0;
}else{
return 1+getSize(node.leftChild)+getSize(node.rightChild);
}
}
/**
* 前序遍历---迭代
*/
public void preOrder(TreeNode node){
if(node==null){
return;
}else{
System.out.println("preOrder data:"+node.getData());
preOrder(node.getLeftChild());
preOrder(node.getRightChild());
}
}
/**
* 中序遍历--迭代
*/
public void midOrder(TreeNode node){
if(node==null){
return;
}else{
midOrder(node.leftChild);
System.out.println("midOrder:"+node.getData());
midOrder(node.rightChild);
}
}
/**
* 后序遍历--迭代
*/
public void lastOrder(TreeNode node){
if(node==null){
return;
}else{
lastOrder(node.leftChild);
lastOrder(node.rightChild);
System.out.println("midOrder:"+node.getData());
}
}
/**
* 前序遍历--非迭代法
*/
public void nonPreOrder(TreeNode node){
Stack<TreeNode> stack=new Stack<TreeNode>();
if(node==null){
return;
}else{
stack.push(node);
while(!stack.isEmpty()){
TreeNode n=stack.pop();
System.out.println("nonPreOrder data"+n.getData());
if(n.rightChild!=null){stack.push(n.rightChild);}
if(n.leftChild!=null){stack.push(n.leftChild);}
}
}
}
/**
* 中序遍历--非迭代法
*/
public void nonMidOrder(TreeNode node) {
Stack<TreeNode> stack = new Stack<TreeNode>();
TreeNode p = node;
while (p != null || !stack.isEmpty()) {
while (p != null) {
stack.push(p);
p = p.getLeftChild();
}
if (!stack.isEmpty()) {
TreeNode n = stack.pop();
System.out.println("nonMidOrder data"+n.getData());
p = n.getRightChild();
}
}
}
public void nonLastOrder(TreeNode node) {
Stack<TreeNode> stack = new Stack<TreeNode>();
TreeNode cur, pre = null;
stack.push(node);
while (!stack.empty()) {
cur = stack.peek();
if ((cur.getLeftChild() == null && cur.getRightChild() == null)||(pre != null && (cur.getLeftChild() == pre||cur.getRightChild() == pre))) {
TreeNode temp = stack.pop();
System.out.print(" "+temp.getData());
pre = temp;
} else {
if (cur.getRightChild() != null)
stack.push(cur.getRightChild());
if (cur.getLeftChild() != null)
stack.push(cur.getLeftChild());
}
}
}
/**
* 创建二叉树
*/
public void createBinaryTreePre(ArrayList<String> data){
createBinaryTree(data.size(),data);
}
private TreeNode createBinaryTree(int size,ArrayList<String> data){
if(data.size()==0){
return null;
}
String d=data.get(0);
int index=size-data.size();
TreeNode node;
if("#".equals(d)){
node=null;
data.remove(0);
return node;
}
node=new TreeNode(index,d);
if(index==0){
root=node;
}
data.remove(0);
node.leftChild=createBinaryTree(size,data);
node.rightChild=createBinaryTree(size,data);
return node;
}
public class TreeNode{
private int index;
private String data;
private TreeNode leftChild;
private TreeNode rightChild;
public TreeNode(int index,String data){
this.index=index;
this.data=data;
this.leftChild=null;
this.rightChild=null;
}
public int getIndex() {
return index;
}
public void setIndex(int index) {
this.index = index;
}
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
public TreeNode getLeftChild() {
return leftChild;
}
public void setLeftChild(TreeNode leftChild) {
this.leftChild = leftChild;
}
public TreeNode getRightChild() {
return rightChild;
}
public void setRightChild(TreeNode rightChild) {
this.rightChild = rightChild;
}
}
public static void main(String[] args) {
BinaryTree binaryTree=new BinaryTree();
binaryTree.createBinaryTree();
int height=binaryTree.getHeight();
System.out.println("height:"+height);
int size=binaryTree.getSize();
System.out.println("size:"+size);
// binaryTree.preOrder(binaryTree.root);
// binaryTree.midOrder(binaryTree.root);
// binaryTree.lastOrder(binaryTree.root);
// binaryTree.nonPreOrder(binaryTree.root);
// binaryTree.nonMidOrder(binaryTree.root);
// String[] strs=new String[]{"A","B","D","#","#","E","#","#","C","#","F","#","#"};
// ArrayList<String> list=new ArrayList<>();
// for(String str:strs){
// list.add(str);
// }
// binaryTree.createBinaryTreePre(list);
// binaryTree.midOrder(binaryTree.root);
// binaryTree.nonPreOrder(binaryTree.root);
//
// binaryTree.nonMidOrder(binaryTree.root);
binaryTree.lastOrder(binaryTree.root);
binaryTree.nonLastOrder(binaryTree.root);
}
}
性质2:深度为k的二叉树至多有2k-1个结点(k>=1)。
赫夫曼树基本概念:
别名“最优树”,是一种带权路径最短的树。
(1)路径:从树中一个结点到另一个结点之间的分支构成这两个结点之间的路径。
(2)路径长度:路径上的分支数目。
(3)树的路径长度:从树根到一每结点的路径长度之和。
(4)结点的带权路径长度:从该结点到树根之间的路径长度与结点上权值的乘积。
(5)树的带权路径长度:树中所有叶子结点的带权路径长度之和。记作:WPL
如图:
二叉树a的树路径长度:1+1+2+2+3+3+4+4=20
二叉树b的树路径长度:1+1+2+2+2+2+3+3=16
二叉树a的WPL:5*1+15*2+40*3+30*4+10*4=315
二叉树b的WPL:10*2+30*2+40*2+15*3+5*3=220
性质3:对任何一颗二叉树T,如果其终端结点数为n0,度为2的 结点 数为n2,则n0 = n2+1.
性质4:二具有n个结点的完全二叉树深度为[log2n]+1 ([x]表示不 大于 x的最大整数)。
赫夫曼树的构造:
2).如果2i>n,则结点i无左孩子(结点i为叶子结点);否则其左孩 子是结点2
3).如果2i+1>n,则结点i无右孩子;否则其右孩子是结点2i+1。he fu man
赫夫曼树的应用:
二叉查找树:
二叉查找树,也叫二叉搜索树、有序二叉树,排序二叉树,满足以下性质(非严谨描述):
1.对于每个节点,其左子节点要么为空,要么值小于该节点值。
2.对于每个节点,其右子节点要么为空,要么值大于该节点值。
3.没有键值相等的点。
通俗的归纳一下性质,二叉查找树中每个节点的值都大于其左子节点,小于其右子节点(如果左右子节点存在的话)。所以二叉查找树中每个节点的左边,整棵左树都是小于它的节点;右边,整棵右树都是大于它的节点。
package com.structures.tree;
public class SearchBinaryTree {
public static void main(String[] args) {
SearchBinaryTree binaryTree=new SearchBinaryTree();
binaryTree.createBinaryTree();
int[] intArray={3,54,56,4,67,50,89,5,7,12};
for(int i:intArray){
binaryTree.put(i);
}
System.out.print("中序遍历必然是递增序列:");
midOrder(binaryTree.root);
}
private TreeNode root;
public SearchBinaryTree(){
}
public void createBinaryTree(){
root=new TreeNode(1,40);
TreeNode nodeB=new TreeNode(2,30);
TreeNode nodeC=new TreeNode(3,60);
TreeNode nodeD=new TreeNode(4,25);
TreeNode nodeE=new TreeNode(5,35);
TreeNode nodeF=new TreeNode(6,70);
root.leftChild=nodeB;
root.rightChild=nodeC;
nodeB.leftChild=nodeD;
nodeB.rightChild=nodeE;
nodeC.rightChild=nodeF;
}
public static void midOrder(TreeNode node){
if(node==null){
return;
}else{
midOrder(node.leftChild);
System.out.print(node.data+" ");
midOrder(node.rightChild);
}
}
class TreeNode{
private int key;
private TreeNode leftChild;
private TreeNode rightChild;
private TreeNode parent;
private int data;
public TreeNode(int key,int data){
this.key=key;
this.data=data;
this.leftChild=null;
this.rightChild=null;
this.parent=null;
}
public int getKey() {
return key;
}
public void setKey(int key) {
this.key = key;
}
public TreeNode getLeftChild() {
return leftChild;
}
public void setLeftChild(TreeNode leftChild) {
this.leftChild = leftChild;
}
public TreeNode getRightChild() {
return rightChild;
}
public void setRightChild(TreeNode rightChild) {
this.rightChild = rightChild;
}
public TreeNode getParent() {
return parent;
}
public void setParent(TreeNode parent) {
this.parent = parent;
}
public int getData() {
return data;
}
public void setData(int data) {
this.data = data;
}
}
/**
* 向查找二叉树添加结点
*/
public TreeNode put(int data) {
TreeNode node = null;
TreeNode parent = null;
if (root == null) {
node = new TreeNode(0, data);
root = node;
}
node=root;
while (node != null) {
parent = node;
if (data < node.data) {
node = node.leftChild;
} else if (data > node.data) {
node = node.rightChild;
} else {
return node;
}
}
node=new TreeNode(0,data);
if(data<parent.data){
parent.leftChild=node;
}else {
parent.rightChild=node;
}
node.parent=parent;
return node;
}
}
输出:中序遍历必然是递增序列:3 4 5 7 12 25 30 35 40 50 54 56 60 67 70 89