通过前序遍历二维数组生成二叉树
ublic class BinaryTree {
private TreeNode root = null;//根结点
public BinaryTree() {
root = new TreeNode(1, "A");
}
/**
* 构建二叉树
* A
* B C
* D E F
*/
private 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.leftNodes = nodeB;
root.rightNodes = nodeC;
nodeB.leftNodes = nodeD;
nodeB.rightNodes = nodeE;
nodeC.rightNodes = nodeF;
}
public int getHeight() {
return getHeight(root);
}
/**
* 获得二叉树的高度或深度
*/
private int getHeight(TreeNode root) {
if (root == null) {
return 0;
}
int i = getHeight(root.leftNodes);
int j = getHeight(root.rightNodes);
return (i < j) ? j + 1 : i + 1;
}
/**
* 获取二叉树的结点数
*/
private int getSize() {
return getSize(root);
}
private int getSize(TreeNode root) {
if (root == null) {
return 0;
} else {
//遍历所有的结点
return 1 + getSize(root.leftNodes) + getSize(root.rightNodes);
}
}
/**
* 前序遍历——非迭代
*/
public void nonRecOrder(TreeNode node) {//前序遍历:A B D E C F
if (node == null) {
return;
} else {
//根左右,也就是先把栈弹出
Stack<TreeNode> stack = new Stack<>();
stack.push(root);
while (!stack.isEmpty()) {
//出栈和进栈
TreeNode n = stack.pop();
//压入子结点
System.out.println("nonRecOrder data" + n.getData());
//先进后出
if (n.rightNodes != null) {
stack.push(n.rightNodes);
}
if (n.leftNodes != null) {
stack.push(n.leftNodes);
}
}
}
}
/**
* 前序遍历——迭代
* A
* B C
* D E F
*/
public void preOrder(TreeNode node) {//前序遍历:A B D E C F
if (node == null) {
return;
} else {
//根然后左然后右
System.out.println(node.data);
preOrder(node.leftNodes);
preOrder(node.rightNodes);
}
}
/**
* 中序遍历——迭代
* A
* B C
* D E F
*/
public void midOrder(TreeNode node) {//D B E A C F
if (node == null) {
return;
} else {
//左然后根然后右
midOrder(node.leftNodes);
System.out.println(node.data);
midOrder(node.rightNodes);
}
}
/**
* 后序遍历——迭代
* A
* B C
* D E F
*/
public void postOrder(TreeNode node) {//D E B F C A
if (node == null) {
return;
} else {
//左然后右然后根
postOrder(node.leftNodes);
postOrder(node.rightNodes);
System.out.println(node.data);
}
}
/**
* 通过前序遍历二维数组生成二叉树
* A
* B C
* D E # F
* # # # # # #
* <p>
* ABD##E##C#F##
*/
public void createBinaryTreePre(ArrayList<String> data) {
createBinaryTree(data.size(), data);
}
private TreeNode createBinaryTree(int size, ArrayList<String> data) {
if (data.size() == 0) {//如果数组的大小等于0,则返回null
return null;
}
String d = data.get(0);
int index = size - data.size();
TreeNode node;
if (d.equals("#")) {
node = null;
data.remove(0);
return node;
}
node = new TreeNode(index, d);
if (index == 0) {
//创建根结点
root = node;
}
data.remove(0);//从数据中移除第一个
node.leftNodes = createBinaryTree(size, data);
node.rightNodes = createBinaryTree(size, data);
return node;
}
public class TreeNode {
private int index;//当前结点的层次
private String data;//当前结点的数据
private TreeNode leftNodes;//左结点
private TreeNode rightNodes;//右结点
public TreeNode(int index, String data) {
this.index = index;
this.data = data;
}
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
}
@Test
public void main() {
BinaryTree binaryTree = new BinaryTree();
/*binaryTree.createBinaryTree();
int height = binaryTree.getHeight();
System.out.println(height);
int size = binaryTree.getSize();
System.out.println(size);*/
// binaryTree.preOrder(binaryTree.root);
// binaryTree.midOrder(binaryTree.root);
// binaryTree.postOrder(binaryTree.root);
//binaryTree.nonRecOrder(binaryTree.root);
ArrayList<String> data = new ArrayList<>();
String[] arrays = new String[]{"A", "B", "D", "#", "#", "E", "#", "#", "C", "#", "F", "#", "#"};
for (String array : arrays) {
data.add(array);
}
binaryTree.createBinaryTreePre(data);
binaryTree.preOrder(binaryTree.root);
}
}
树、森林、二叉树的转换
树转换为二叉树
- 1.加线。在所有兄弟结点之间加一条连线。
- 2.去线。对树中每个结点,只保留它与第一个孩子结点的连线,删除它与其他孩 子结点之间的连线。
- 3.层次调整。以树的根结点为轴心,将整棵树顺时针旋转一定的角度,使之结构 层次分明。注意第一个孩子是二叉树结点的左孩子,兄弟转换过来的孩子是结 点的右孩子。
森林转化为二叉树
- 1.把每个树转换为二叉树。
- 2.第一棵二又树不动,从第二棵二叉树开始,依次把后一棵二叉树的根结点作为 前一棵二叉树的根结点的右孩子,用线连接起来。当所有的二叉树连接起来后 就得到了由森林转换来的二叉树。
二叉树转换为树
- 1.加线。若某结点的左孩子结点存在,则将这个左孩子的右孩子结点、右孩子的 右孩子结点、右孩子的右孩子的右孩子结点…哈,反正就是左孩子的n 个 右孩子结点都作为此结点的孩子。将该结点与这些右孩子结点用线连接起来。
- 2.去线。删 除原 二 叉 树 中 所 有结点 与 其 右 孩 子 结点 的连 线。
- 3.层次调整。使之结构层次分明。
二叉树转换为森林
判断一棵二叉树能够转换成一棵树还是森林,标准很简单,那就是只要看这棵二
叉树的根结点有没有右孩子,有就是森林,没有就是一棵树。那么如果是转换成森
林,
步骤如下:
- 1.从根结点开始,若右孩子存在,则把与右孩子结点的连线删除,再查看分离后 的二叉树,若右孩子存在,则连线删除…直到所有右孩子连线都删除为 止,得到分离的二叉树。
- 2.再将 每 棵 分离后 的二 叉树转换 为树 即 可。
赫夫曼树
####查找二叉树:根结点的右结点一定比根结点大,左结点一定比根结点小
通过数组生成查找二叉树
public class SearchBinaryTree {
private TreeNode root;
public SearchBinaryTree() {
}
@Test
public void main() {
SearchBinaryTree serchBinaryTree = new SearchBinaryTree();
int[] datas = new int[]{15, 10, 50, 30, 70, 65, 90};
for (int data : datas) {
serchBinaryTree.put(data);
}
serchBinaryTree.midOrder(serchBinaryTree.root);
}
/**
* 中序遍历——迭代
*/
public void midOrder(TreeNode node) {
if (node == null) {
return;
} else {
//左然后根然后右
midOrder(node.leftChild);
System.out.println(node.data);
midOrder(node.rightChild);
}
}
public TreeNode put(int data) {
//根结点不会变,相对的父结点,当前结点
TreeNode parent = null;//父结点
TreeNode node = null;//当前结点
//1.首先判断当前根结点是否为空
if (root == null) {//根布局为空
node = new TreeNode(0, data);
root = node;
}
//2.不为空的时候每次从根结点开始遍历
node = root;
while (node != null) {
parent=node;//最终目的是获得父结点
//3.判断你传入的值与根结点的值进行判断,如果大于切换到右边的结点,小于切换到左结点
if (node.data < data) {//右边
node = node.rightChild;
} else if (node.data > data) {//左边
node = node.leftChild;
}else {
return node;//相等的话跳出整个put方法
}
}
//4.获得切换的结点之后,放值
node=new TreeNode(0,data);//当前结点为空的时候new一个节点
if(data>parent.data){//放到右边
parent.rightChild=node;
}else{
parent.leftChild=node;
}
return node;
}
public class TreeNode {
private int data;
private int key;
private TreeNode leftChild;
private TreeNode rightChild;
private TreeNode parent;
public TreeNode(int key, int data) {
this.data = data;
this.key = key;
leftChild = null;
rightChild = null;
parent = null;
}
}
}
新增结点删除
/**
* 删除二叉树某个结点
*/
public void deleteNote(int data) throws Exception {
//查找获取到当前的结点
TreeNode node = searchNode(data);
if (node == null) {//查找到结点为空
throw new Exception("改结点无法找到");
} else {
//删除该结点
delete(node);
}
}
/**
* 删除该结点
*/
private void delete(TreeNode node) throws Exception {
if (node == null) {//查找到结点为空
throw new Exception("改结点无法找到");
} else {
//1.被删除的结点无孩子(如上图的65)
TreeNode parent = node.parent;
//首先判断删除的结点位于哪边
if (node.leftChild == null && node.rightChild == null) {
if (parent.leftChild == node) {//父结点大于子结点,则删除左结点
parent.leftChild = null;
} else {
parent.rightChild = null;
}
return;
}
//2.被删除的结点有左结点无右结点(如上图的10)
if (node.leftChild != null && node.rightChild == null) {
//首先判断当前的结点位于父布局的什么位置
if (parent.leftChild == node) {//位于左结点
parent.leftChild = node.leftChild;
} else {
parent.rightChild = node.leftChild;
}
return;
}
//3.被删除的结点无左结点有右结点(如上图的90)
if (node.rightChild != null && node.leftChild == null) {
//首先判断当前的结点位于父布局的什么位置
if (parent.rightChild == node) {//位于右结点
parent.rightChild = node.rightChild;
} else {
parent.leftChild = node.rightChild;
}
return;
}
//4.被删除的结点有左结点也有右结点(如上图的30),此时需要找个后继者(未新增(红色的是新增)30后面的最小的应该是45)
//寻找下一个后继者
TreeNode next = getNextNode(node);//如此时是45
delete(next);//删除45这个结点
node.data = next.data;//当前结点数据改变为下一个结点的数据
}
}
/**
* 寻找下一个后继者
*/
private TreeNode getNextNode(TreeNode node) {
//后继者一定比当前节点大,所以肯定在当前节点的右边寻找(比如新增红线45,此时后继者应该是40)
if (node == null) {
return null;
} else {
if (node.rightChild != null) {//右结点不为空
return getMinTreeNode(node.rightChild);
} else {//比如49的后继者是50此时应该怎么做
TreeNode parent = node.parent;
while (parent != null && parent.rightChild == node) {
node = parent;
parent = node.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 data) {
//从根结点开始找
TreeNode node = root;
if (node == null) {
return null;
}
while (node != null && node.data != data) {
if (node.data > data) {//左结点
node = node.leftChild;
} else if (node.data < data) {
node = node.rightChild;
}
}
return node;
}