1:万树基于二叉树!
二猪(红黑树、B树、B+树等集合):你说,你有三棵子树,也是树,四棵子树,也是树,要不你干脆就别超过2棵子树,做个二叉树,给我看树厂去得了......
我看程序员,谁敢不给咱面子!!!!
言归正传,万树基于二叉树,确实夸张了点,你也不知道那群计算机科学家哪天又给你整出点骚结构出来。但是可以肯定的是,大部分程序员,这辈子能打上交道的树,基本都是基于二叉树!
每个节点最多有两棵子树的树,就是二叉树!树结构,通常情况下,不会存储相同的元素,即每个节点都是唯一的!
2:要创造,先遍历啦!
在谈如何用代码构造一棵二叉树前,我们不妨先从如何遍历一棵二叉树开始入手。
二叉树的遍历,主要是三种:
- 先序遍历
- 中序遍历
- 后序遍历
所谓的序,就是根。所以可以这样理解:
- 先序遍历:整棵树的根是第一位,即 树根 -> 左子树 -> 右子树
- 中序遍历:整棵树的根是在中间位置,即 左子树 -> 树根 -> 右子树
- 后序遍历:整棵树的根在最后一位,即 左子树 -> 右子树 -> 树根
所以整个遍历的过程,就是拆子树的过程。
以下图为例,学习如何根据遍历要求拆树:
先序遍历拆树法:
之前提到,先序遍历的顺序是: 根,左,右
根 | 左子树 | 右子树 |
---|---|---|
A | 左子树B | 右子树C |
B | 左子树D | 右子树E(只有一个元素) |
C | 左子树G | 右子树H |
好了,可以不必继续拆下去了,再拆下去就变单节点了!
OK,开始遍历!从下往上!
C—— 左子树G按照根左右的顺序得到:G,I,J
C—— 右子树H按照根左右的顺序得到:H,NULL,K。NULL可以忽略,得到:H,K
B—— 左子树D = D,F
B—— 右子树E = E
组合:
根 | 左子树 | 右子树 |
---|---|---|
A | B,D,F,E | C,G,I,J,H,K |
最后先序遍历的结果就是:A,B,D,F,E,C,G,I,J,H,K;
中序遍历拆树法:
左子树 | 根 | 右子树 |
---|---|---|
左子树B | A | 右子树C |
左子树D | B | 右子树E(只有一个元素) |
左子树G | C | 右子树H |
这里就不多展开来说了,读者可以根据先序遍历的拆树法,套一套,这里我只给出最后结果供大家对比:
F,D,B,E,A,I,G,J,C,H,K
后序遍历拆树法:
左子树 | 右子树 | 根 |
---|---|---|
左子树B | 右子树C | A |
左子树D | 右子树E | B |
左子树G | 右子树H | C |
结果:
F,D,E,B,I,J,G,K,H,C,A
3:开始创建一棵二叉树!
我们在上述遍历二叉树的时候,不难发现,我们是通过一步步的拆树,把整棵树拆成一棵棵子树,来去遍历再重新组装结果的。
所以我们创建一棵二叉树,也不妨从一棵棵小树苗种起,慢慢嫁接起来形成一棵大树!
定义二叉树:
public class BinaryTree<T> {
//这里只存储了双亲节点的数据域,也可以存储双亲节点的引用
//即: private BinaryTree<T> parent;
private T parent;
private T data;
private BinaryTree<T> leftTree;
private BinaryTree<T> rightTree;
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public BinaryTree<T> getLeftTree() {
return leftTree;
}
public void setLeftTree(BinaryTree<T> leftTree) {
this.leftTree = leftTree;
}
public BinaryTree<T> getRightTree() {
return rightTree;
}
public void setRightTree(BinaryTree<T> rightTree) {
this.rightTree = rightTree;
}
public void setParent(T parent) {
this.parent = parent;
}
public T getParent() {
return this.parent;
}
}
创建二叉树:
public class BinaryTreeLauncher {
public static void main(String[] args) {
//create Root
BinaryTree<String> root = new BinaryTree<>();
root.setData("A");
root.setParent(null);
root.setLeftTree(null);
root.setRightTree(null);
//create the whole left tree;
BinaryTree<String> leftTreeB = new BinaryTree<>();
leftTreeB.setData("B");
leftTreeB.setLeftTree(null);
leftTreeB.setRightTree(null);
BinaryTree<String> leftTreeD = new BinaryTree<>();
leftTreeD.setData("D");
leftTreeD.setRightTree(null);
leftTreeD.setLeftTree(null);
BinaryTree<String> leftTreeF = new BinaryTree<>();
leftTreeF.setData("F");
leftTreeF.setLeftTree(null);
leftTreeF.setRightTree(null);
BinaryTree<String> rightTreeEofLeft = new BinaryTree<>();
rightTreeEofLeft.setData("E");
rightTreeEofLeft.setLeftTree(null);
rightTreeEofLeft.setRightTree(null);
//composing the whole left tree
leftTreeF.setParent(leftTreeD.getData());
leftTreeD.setLeftTree(leftTreeF);
leftTreeD.setParent(leftTreeB.getData());
leftTreeB.setLeftTree(leftTreeD);
rightTreeEofLeft.setParent(leftTreeB.getData());
leftTreeB.setRightTree(rightTreeEofLeft);
leftTreeB.setParent(root.getData());
root.setLeftTree(leftTreeB);
//Create the whole right tree
BinaryTree<String> rightTreeC = new BinaryTree<>();
rightTreeC.setData("C");
BinaryTree<String> leftTreeGofRight = new BinaryTree<>();
leftTreeGofRight.setData("G");
BinaryTree<String> leftTreeIofRight = new BinaryTree<>();
leftTreeIofRight.setData("I");
BinaryTree<String> rightTreeJ = new BinaryTree<>();
rightTreeJ.setData("J");
BinaryTree<String> rightTreeH = new BinaryTree<>();
rightTreeH.setData("H");
BinaryTree<String> rightTreeK = new BinaryTree<>();
rightTreeK.setData("K");
//Let's compose the whole right tree;
leftTreeIofRight.setParent(leftTreeGofRight.getData());
leftTreeGofRight.setLeftTree(leftTreeIofRight);
rightTreeJ.setParent(leftTreeGofRight.getData());
leftTreeGofRight.setRightTree(rightTreeJ);
leftTreeGofRight.setParent(rightTreeC.getData());
rightTreeC.setLeftTree(leftTreeGofRight);
rightTreeK.setParent(rightTreeH.getData());
rightTreeH.setRightTree(rightTreeK);
rightTreeH.setParent(rightTreeC.getData());
rightTreeC.setRightTree(rightTreeH);
rightTreeC.setParent(root.getData());
root.setRightTree(rightTreeC);
System.out.println(root);
}
}
到这里,你就种了一棵像本章图里的那样的二叉树了!
4:Found anything 因垂丝汀??
仔细观察我们创建这棵二叉树的流程,有没有发现,我们把每一个节点,都当成了一棵只有一个元素的小树,最后一层层的向上挂载,直到根节点?
A,B,C,D,E...K。在一开始,是一片孤立的元素,且不重复。
这完全就是我们之前提到的一群并查集 !
而挂载过程中,比如子树F挂到D下,其实就是并查集 connect(T D, T F)算法的一个变种!
有兴趣的,不妨改一下这个算法(参考并查集章节贴出来的代码,CV一下就可以跑的),通过connect(T D, T F)算法,把二叉树嫁接起来!
5:What's the next ?
下一章节,将会介绍二叉树的操作的代码实现,比如前文提到的遍历!