树系列:
一、前言
最近在深入了解MySQL索引,发现MySQL索引主要用B+树实现的。本人对树这种数据结构,一直以来掌握都是模棱两可的状态,现在希望通过写一个关于树的专题系列,来掌握树这种数据结构,为深入了解MySQL索引打下基础,做到心中有"树"。
二、二叉树理论篇
二叉树的定义
二叉树(Binary Tree) 是n(n>=0)个结点的有限集合,该集合或者为空集(称为空二叉树),或者由一个根结点和两棵互不相交的,分别称为根结点的左子树和右子树组成。
通俗的说:每个结点的度均不超过2的有序树,称为二叉树
二叉树的分类
根据结点分布的不同可将二叉树分为:满二叉树、完全二叉树、斜树
满二叉树
在一棵二叉树中,如果所有分支结点都存在左子树和右子树,并且所有叶子都在同一层上,这样的二叉树称为满二叉树。
特点:
- 叶子只能出现在最下一层
- 非叶子结点的度一定是2
完全二叉树
对一颗具有n个结点的二叉树按层编号,如果编号为i(1<=i<=n)的结点与同样深度的满二叉树中编号为i的结点在二叉树中位置完全相同,则这棵二叉树称为完全二叉树。
特点:
- 叶子结点只能出现在最下层和倒数第二层。
- 最下层的叶子结点集中在树的左部。
- 倒数第二层若存在叶子结点,一定在右部连续位置。
注:满二叉树一定是完全二叉树,但反过来不一定成立。
斜树
斜树是特殊的二叉树,所有结点都只有左子树的二叉树左斜树,反之叫右斜树,统称为斜树。
斜树的特点所有结点都在一个方向,更像是数组或链表,已经失去了二叉树的优势,所以在实际的开发应用中尽量避免斜树的出现。
二叉树的存储结构
顺序存储
对于满二叉树和完全二叉树来说,可以将结点逐层的放到一组连续的存储空间里,一维数组就比较适合,并且结点的存储位置就是数组的下标索引。
完全二叉树的顺序存储
可以看出,刚好填满整个数组下标和完全二叉树的结点一一对应,不浪费存储空间。
对于一般二叉树来说,需要用虚拟结点来补充成一颗完全二叉树来存储,否则无法确定结点间的关系,这样的话会造成空间的浪费。
极端情况需要补充很多结点,比如斜树
链式存储
既然顺序存储对完全二叉树和满树比较适用,一般的二叉树我们可以考虑用链式存储结构。二叉树中每个结点最多有二个孩子结点,因此可以设计成:数据域加左右孩子域,左右孩子域分别存放左右子树的引用
采用一种链表结构存储二叉树,二叉链表
三、实现篇
前面讲了二叉树的一些概念,下面讲解代码实现
类结构
public class BinTree {
Node root;
private static class Node {
private String data;
private Node left;
private Node right;
public Node(String data) {
this.data = data;
}
@Override
public String toString() {
return "Node{" +
"data='" + data + '\'' +
'}';
}
}
}
创建二叉树
public void createTree(String[] dataList) {
List<Node> nodeList = new ArrayList<>();
for (String item : dataList) {
Node node = new Node(item);
nodeList.add(node);
}
this.root = nodeList.get(0);
for (int i = 0; i < nodeList.size() / 2; i++) {
nodeList.get(i).left = nodeList.get(i * 2 + 1);
int index = i * 2 + 2;
if (index < nodeList.size()) {//防止集合越界
nodeList.get(i).right = nodeList.get(index);
}
}
}
前序遍历
根结点->左子树->右子树
public void preOrder(Node node) {
if (node == null) {
return;
}
System.out.println(node);
preOrder(node.left);
preOrder(node.right);
}
结果:ABDECGH
中序遍历
左子树->根结点->右子树
public void inOrder(Node node){
if (node == null) {
return;
}
inOrder(node.left);
System.out.println(node);
inOrder(node.right);
}
结果:DBEAGCH
后序遍历
左子树->右子树->根结点
public void postOrder(Node node){
if (node == null) {
return;
}
postOrder(node.left);
postOrder(node.right);
System.out.println(node);
}
结果:DEBGHCA
四 完整代码
public class BinTree {
Node root;
private static class Node {
private String data;
private Node left;
private Node right;
public Node(String data) {
this.data = data;
}
@Override
public String toString() {
return "Node{" +
"data='" + data + '\'' +
'}';
}
}
public void createTree(String[] dataList) {
List<Node> nodeList = new ArrayList<>();
for (String item : dataList) {
Node node = new Node(item);
nodeList.add(node);
}
this.root = nodeList.get(0);
for (int i = 0; i < nodeList.size() / 2; i++) {
nodeList.get(i).left = nodeList.get(i * 2 + 1);
int index = i * 2 + 2;
if (index < nodeList.size()) {//防止集合越界
nodeList.get(i).right = nodeList.get(index);
}
}
}
/**
* 前序遍历
* @param node
*/
public void preOrder(Node node) {
if (node == null) {
return;
}
System.out.println(node);
preOrder(node.left);
preOrder(node.right);
}
/**
* 中序遍历
* @param node
*/
public void inOrder(Node node){
if (node == null) {
return;
}
inOrder(node.left);
System.out.println(node);
inOrder(node.right);
}
/**
* 后序遍历
* @param node
*/
public void postOrder(Node node){
if (node == null) {
return;
}
postOrder(node.left);
postOrder(node.right);
System.out.println(node);
}
}