1. 树的简介
1.1 树的定义
树是一种特殊的数据结构,它可以用来描述有分支的结构,是由一个或一个以上的节点所组成的有限集合。
1.2 树的特点
a. 存在一个特殊的节点,称为根节点;
b. 没有父节点的节点称为根节点;
c. 每一个非根节点有且只有一个父节点;
d. 除了根节点外,每个子节点可以分为多个不相交的子树;
图中A节点就称为根节点,B、C、D 均为A的子节点。
1.3 树的专有名词
a. 树根或者根节点(root):没有父节点的节点称为根节点,如下图中树的根节点为 A。
b. 父节点(parent):每一个节点的上层节点为父节点,如下图中 B 的父节点为 A,E 的父节点为 C。
c. 子节点(children):每一个节点的下层节点为子节点,如 A的子节点有 B、C、D,而 C 的子节点有 E、F、G。
d. 兄弟节点(siblings):有共同父节点的节点为兄弟节点,如 B、C、D 的父节点均为 A,所以彼此称为兄弟节点。
e. 度(degree):子树的个数称为该节点的度,如 A的度为3,D 的度为1。
f. 叶子节点或终端节点(terminal node):没有子节点的节点,即度为 0 的节点,如图中的 B、E、F、G、I。
g. 阶层或级(level):根节点的阶层为 1,图中 A的阶层为 1,B、C、D的阶层为 2,E、F、G、H的阶层为3,I 的阶层为4。
h. 高度(height):树的最大阶层,例如此树的高度为 4。
i. 森林(forest):森林是由 n 个不相交的树组成,移去树根即为森林。如图中,移除节点 A,则包含三个树的森林。
2. 二叉树
2.1 二叉树的定义
二叉树是由有限个节点所组成的集合,此集合可以为空集合,或由一个树根及其左右两个子树所组成。简单的说,二叉树最多只能有两个子节点,就是度小于或者等于2。二叉树的数据结构如下:
2.2 二叉树的性质
1. 二叉树第 i 层上的节点数目最多为 ,其中 i ≥ 1。
2. 深度为 k 的二叉树至多有 -1个节点,其中 k ≥ 1。
2.3. 满二叉树
定义
高度为 h,并且由 2^h - 1 个节点的二叉树,被称为满二叉树。如下图所示,这是一棵满二叉树
2.4. 完全二叉树
定义
一棵二叉树中,只有最下层节点的度可以小于2,并且最下层的叶节点集中在靠左的若干位置上,这样的二叉树称为完全二叉树。
特点
叶子节点只能出现在最下层和次下层,且最下层的叶子节点集中在树的左部。显然,一棵满二叉树必定是一棵完全二叉树,而完全二叉树未必是满二叉树。如下图,这是一棵完全二叉树:
而下图不是一棵完全二叉树:
2.5 二叉查找树
定义
二叉查找树,又称为二叉搜索树。假设 x 为二叉查找树中的一个节点,x 节点包含关键字 key,节点的 key 值记为 key[x]。如果 y 是 x 的左子树中的一个节点,则 key[y] ≤ key[x] ;如果 y 是 x 的右子树的一个节点,则 key[y] ≥ key[x]。如下图所示:
特点
a. 每个树根的值需大于左子树的值。
b. 每一个树根的值需小于右子树的值。
c. 左右子树也是二叉搜索树。
d. 没有键值相等的节点。
3. 二叉树存储
3.1 数组表示法
如果要使用一维数组来存储二叉树,首先将二叉树想象成一个满二叉树,而且第 k 个阶层具有 个节点,并且按照顺序存放在此一维数组之中。这里从数组下标为1的位置开始存放。
如下图所示的二叉树,用数组表示为:{0,13,65,5,97,25,0,37,22,0,4,28,0,0,32,0}。
3.2 链表表示法
树的节点:
package zzw.cn.tree;
/**
* @author 鹭岛猥琐男
* @create 2019/8/24 21:37
*/
public class TreeNode
{
int value;//节点值
TreeNode leftNode;//指向左节点
TreeNode rightNode;//指向右节点
public TreeNode(int value)
{
this.value = value;
}
}
二叉树:
package zzw.cn.tree;
/**
* @author 鹭岛猥琐男
* @create 2019/8/25 0:40
*/
public class BinaryTree
{
TreeNode root;//根节点
public BinaryTree(int[] array)
{
root = transformArrayToBinaryTree(array, 1);
}
//采用递归方式创建二叉树
public TreeNode transformArrayToBinaryTree(int[] array, int index)
{
if (index < array.length)
{
int value = array[index];
if (value != 0)
{
TreeNode node = new TreeNode(value);
array[index] = 0;
node.leftNode = transformArrayToBinaryTree(array, index * 2);
node.rightNode = transformArrayToBinaryTree(array, index * 2 + 1);
return node;
}
}
return null;
}
}
4. 二叉树的遍历
二叉树的遍历,就是访问树的所有节点各一次,并且在遍历后,将树中的数据转化为线性关系。树的遍历存在三种方式:
a. 中序遍历
b. 前序遍历
c. 后续遍历
4.1 中序遍历
若二叉树非空,则执行以下操作:左子树 → 树根 → 右子树。就是沿着树的左子树一直往下,直到无法前进后退回返回父节点,再往右子树一直往下。如果右子树也走完了就退回上层的左节点,再重复左、中、右的顺序遍历。
上图树的中序遍历如下所示:
package zzw.cn.tree;
/**
* @author 鹭岛猥琐男
* @create 2019/8/25 1:18
*/
public class BinaryTreeTest
{
public static void main(String[] args)
{
int[] arr = {0, 13, 65, 5, 97, 25, 0, 37, 22, 0, 4, 28, 0, 0, 32, 0};
BinaryTree tree = new BinaryTree(arr);
inOrder(tree);//中序遍历
}
//中序遍历
private static void inOrder(TreeNode node)
{
if (node != null)
{
inOrder(node.leftNode);
System.out.print(node.value + " ");
inOrder(node.rightNode);
}
}
private static void inOrder(BinaryTree tree)
{
System.out.print("中序遍历:");
inOrder(tree.root);
}
}
结果:
中序遍历:22 97 65 4 25 28 13 5 32 37
4.2 前序遍历
前序遍历的顺序为:树根 → 左子树 → 右子树。前序遍历就是从根节点开始处理,根节点处理完往左子树,直到无法前进再处理右子树。
上图树的前序遍历如下所示:
package zzw.cn.tree;
/**
* @author 鹭岛猥琐男
* @create 2019/8/25 1:18
*/
public class BinaryTreeTest
{
public static void main(String[] args)
{
int[] arr = {0, 13, 65, 5, 97, 25, 0, 37, 22, 0, 4, 28, 0, 0, 32, 0};
BinaryTree tree = new BinaryTree(arr);
preOrder(tree);//前序遍历
}
//前序遍历
private static void preOrder(TreeNode node)
{
if (node != null)
{
System.out.print(node.value + " ");
preOrder(node.leftNode);
preOrder(node.rightNode);
}
}
private static void preOrder(BinaryTree tree)
{
System.out.print("前序遍历:");
preOrder(tree.root);
}
}
结果:
前序遍历:13 65 97 22 25 4 28 5 37 32
4.3 后序遍历
后序遍历的顺序为:左子树 → 右子树 → 树根。后序遍历和前序遍历的方法相反,它是把左子树的节点和右节点都处理完了才处理树根。
上图树的后序遍历如下所示:
package zzw.cn.tree;
/**
* @author 鹭岛猥琐男
* @create 2019/8/25 1:18
*/
public class BinaryTreeTest
{
public static void main(String[] args)
{
int[] arr = {0, 13, 65, 5, 97, 25, 0, 37, 22, 0, 4, 28, 0, 0, 32, 0};
BinaryTree tree = new BinaryTree(arr);
postOrder(tree);//后序遍历
}
//后序遍历
private static void postOrder(TreeNode node)
{
if (node != null)
{
postOrder(node.leftNode);
postOrder(node.rightNode);
System.out.print(node.value + " ");
}
}
private static void postOrder(BinaryTree tree)
{
System.out.print("后序遍历:");
postOrder(tree.root);
}
}
结果:
后序遍历:22 97 4 28 25 65 32 37 5 13
参考:
https://github.com/LRH1993/android_interview/blob/master/data-structure/tree/tree-introduction.md
《图解数据结构-使用Java》