二叉树的建立:
通过前序遍历的数据序列反向生成二叉树。
public class TreeNode {//树的节点
public int index;
public String date;
public TreeNode leftChild;
public TreeNode rightChild;
public TreeNode(int index, String date) {
this.index = index;
this.date = date;
}
public int getIndex() {
return index;
}
public String getDate() {
return date;
}
}
public class TreeTest {
private TreeNode root;
public TreeNode createBinaryTree(int size,ArrayList<String> data){
if (data==null) {
return null;
}
String d = data.get(0);
TreeNode treeNode;
int index=size-data.size();
if (d.equals("#")) {//遇到#代表没有子分支节点
treeNode = null;
data.remove(0);
return treeNode;
}
treeNode=new TreeNode(index,d);
if (index == 0) {
//创建根节点
root = treeNode;
}
data.remove(0);
treeNode.leftChild=createBinaryTree(size,data);//创建左分支节点
treeNode.rightChild=createBinaryTree(size,data);//创建右分支节点
return treeNode;
}
//前序遍历
public void printTreeNode(TreeNode treeNode){
if (treeNode==null) {
return;
}
System.out.println(treeNode.getDate());
printTreeNode(treeNode.leftChild);
printTreeNode(treeNode.rightChild);
}
}
@Test
public void TreeTest() throws Exception {
TreeTest treeTest = new TreeTest();
String [] data={"A","B","#","D","#","#","C","#","#"};
ArrayList<String> list = new ArrayList<>();
for (String datum : data) {
list.add(datum);
}
TreeNode binaryTree = treeTest.createBinaryTree(list.size(), list);
treeTest.printTreeNode(binaryTree);
}
运行test程序,输出结果为ABDC。
赫夫曼树
给定n个权值作为n个叶子结点,构造一棵二叉树,若带权路径长度达到最小,称这样的二叉树为最优二叉树,也称为哈夫曼树(Huffman Tree)。哈夫曼树是带权路径长度最短的树,权值较大的结点离根较近。
赫夫曼大叔说,从树中一个结点到另一个结点之间的分支构成两个结点之间的路径,路径上的分支数目称做路径长度。图二叉树a中,根结点到结点D的路径长度就为4,二叉树b中根结点到结点D的路径长度为2。树的路径长度就是从树根到每一结点的路径长度之和。二叉树a的树路径长度就为1+1+2+2+3+3+4+4=20。二叉树b的树路径长度就为1+2+3+3+2+1+2+2=16。
如果考虑到带权的结点,结点的带权的路径长度为从该结点到树根之间的路径长度与结点上权的乘积。树的带权路径长度为树中所有叶子结点的带权路径长度之和。假设有n个权值{w1,w2,…"wn},构造一棵有n个叶子结点的二叉树,每个叶子结点带权wk,每个叶子的路径长度为lk,我们通记作,则其中带权路径长度WPL最小的二叉树称做赫夫曼树。
二叉树a的WPL=5×1+15×2+40×3+30X4+10×4=315
二叉树b的wPL=5X3+15X3+40×2+30×2+10×2=220
赫夫曼树可以提高效率,赫夫曼编码还可以压缩文件。
查找二叉树
二叉查找树(Binary Search Tree),(又:二叉搜索树,二叉排序树)它或者是一棵空树,或者是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉排序树。
创建查找二叉树
public class TreeNode {//双向链表
public int key;
public int date;
public TreeNode leftChild;
public TreeNode rightChild;
public TreeNode parent;
public TreeNode(int key, int date) {
this.key = key;
this.date = date;
}
public int getIndex() {
return key;
}
public int getDate() {
return date;
}
}
public class TreeTest {
public TreeNode root;
//创建查找二叉树,添加节点
public TreeNode put(int data){
TreeNode treeNode = null;
TreeNode parent = null;
if (root==null) {//创建根节点
treeNode = new TreeNode(0, data);
root=treeNode;
return treeNode;
}
treeNode = root;//从根节点开始查找
//查找添加元素父节点的位置
while (treeNode != null) {
parent=treeNode;
if (data > treeNode.date) {//大于就往右找
treeNode=treeNode.rightChild;
} else if (data < treeNode.date) {//小于就往左找
treeNode = treeNode.leftChild;
} else {
//相等跳出循环
return treeNode;
}
}
//循环完毕表示此节点添加到相应位置
treeNode = new TreeNode(0, data);
if (data < parent.date) {
parent.leftChild = treeNode;
} else {
parent.rightChild = treeNode;
}
treeNode.parent=parent;
return treeNode;
}
//中序遍历
public void printTreeNode(TreeNode treeNode){
if (treeNode==null) {
return;
}
printTreeNode(treeNode.leftChild);
System.out.println(treeNode.getDate());
printTreeNode(treeNode.rightChild);
}
}
@Test
public void TreeTest1() throws Exception {
TreeTest treeTest = new TreeTest();
int [] data={10,20,50,30,40,60};
ArrayList<Integer> list = new ArrayList<>();
for (int datum : data) {
treeTest.put(datum);
}
treeTest.printTreeNode(treeTest.root);//中序打印
}
查找二叉树用中序打印是按数值的顺序打印,所以打印结果为10,20,30,40,50,60
删除查找二叉树
public class TreeNode {
public int key;
public int data;
public TreeNode leftChild;
public TreeNode rightChild;
public TreeNode parent;
public TreeNode(int key, int date) {
this.key = key;
this.data = date;
}
public int getIndex() {
return key;
}
public int getData() {
return data;
}
}
public void deleteNode(int key) throws Exception {
//查找是否有这个节点
TreeNode treeNode=searchNode(key);
if (treeNode == null) {
throw new Exception("该节点无法找到");
} else {
//删除节点
delete(treeNode);
}
}
private void delete(TreeNode treeNode) {
TreeNode parent = treeNode.parent;
//被删除的节点无左右孩子
if (treeNode.leftChild==null&&treeNode.rightChild==null) {
if (parent.rightChild==treeNode) {
parent.rightChild=null;
} else if (parent.leftChild==treeNode) {
parent.leftChild = null;
}
treeNode.parent = null;
}
//被删除的节点有左无右
else if (treeNode.leftChild!=null&&treeNode.rightChild==null) {
if (treeNode==root) {//删除无右孩子的根节点
root=treeNode.rightChild;
root.parent=null;
return;
}
if (parent.rightChild==treeNode) {
parent.rightChild=treeNode.leftChild;
treeNode.leftChild.parent = parent;
}else if (parent.leftChild==treeNode) {
parent.leftChild = treeNode.leftChild;
treeNode.leftChild.parent = parent;
}
treeNode.parent = null;
}
//被删除的节点有右无左
else if (treeNode.leftChild==null&&treeNode.rightChild!=null) {
if (treeNode==root) {//删除无左孩子的根节点
root=treeNode.rightChild;
root.parent=null;
return;
}
if (parent.rightChild==treeNode) {
parent.rightChild=treeNode.rightChild;
treeNode.rightChild.parent = parent;
}else if (parent.leftChild==treeNode) {
parent.leftChild = treeNode.rightChild;
treeNode.rightChild.parent = parent;
}
treeNode.parent = null;
}
else //既有左孩子又有右孩子
{ //找到该节点后继节点
TreeNode next=getNextNode(treeNode);
delete(next);
treeNode.data = next.data;
}
}
//获取一个节点的后继节点
private TreeNode getNextNode(TreeNode treeNode) {
if (treeNode == null) {
return null;
} else {
if (treeNode.rightChild != null) {
//查找右节点中最小节点
return getMinTreeNode(treeNode.rightChild);
} else {
TreeNode parent=treeNode.parent;
while (parent != null && treeNode == parent.rightChild) {
treeNode=parent;
parent = parent.parent;
}
return parent;
}
}
}
//查找最小节点
private TreeNode getMinTreeNode(TreeNode node) {
if (node == null) {
return null;
} else {
while (node.leftChild != null) {
node=node.leftChild;
}
}
return node;
}
//查找节点
private TreeNode searchNode(int key) {
TreeNode node = root;
if (node == null) {
return null;
} else {
//如果node为空了代表没找到,或者找到了跳出循环
while (node != null && key != node.data) {
if (key < node.data) {
node=node.leftChild;
} else {
node=node.rightChild;
}
}
}
return node;
}
@Test
public void TreeTest() throws Exception {
TreeTest treeTest = new TreeTest();
int [] data={10,20,50,30,40,60};
ArrayList<Integer> list = new ArrayList<>();
for (int datum : data) {
treeTest.put(datum);
}
treeTest.printTreeNode(treeTest.root);
treeTest.deleteNode(60);
treeTest.printTreeNode(treeTest.root);
}
上面是删除查找二叉树节点的全部代码。