13. m m m 叉树
我们来定义 m m m 叉树, 并将二叉树作为其特例来分析.
13.1 预备知识: 字符串
- 字母表记作 Σ \Sigma Σ, 源码: \Sigma;
- 英文字母表 Σ = { a , b , … , z } \Sigma = \{\mathrm{a}, \mathrm{b}, \dots, \mathrm{z}\} Σ={a,b,…,z}, 我们故意写成 \mathrm{a} 以表示它为常量;
- 阿拉伯数字字母表 Σ = { 0 , 1 , … , 9 } \Sigma = \{0, 1, \dots, 9\} Σ={0,1,…,9};
- 二进制数字字母表 Σ = { 0 , 1 } \Sigma = \{0, 1\} Σ={0,1};
- 字母表的乘积: { 0 , 1 } × { 0 , 1 } = { ( 0 , 0 ) , ( 0 , 1 ) , ( 1 , 0 ) , ( 1 , 1 ) } = { 00 , 01 , 10 , 11 } \{0, 1\} \times \{0, 1\} = \{(0, 0), (0, 1), (1, 0), (1, 1)\} = \{00, 01, 10, 11\} {0,1}×{0,1}={(0,0),(0,1),(1,0),(1,1)}={00,01,10,11}, 我们通常使用简记;
- 字母表的正闭包: Σ + = { 0 , 1 } + \Sigma^+ = \{0, 1\}^+ Σ+={0,1}+ 表示长度至少为 1 的字符串 (0, 1 串);
- 字母表的克林闭包: Σ ∗ = Σ + ∪ { ε } \Sigma^* = \Sigma^+ \cup \{\varepsilon\} Σ∗=Σ+∪{ε}, 其中 ε \varepsilon ε 表示空串, 源码: \varepsilon.
13.2 m m m-叉树的定义
Let ϕ \phi ϕ be the empty node, an m m m-tree is a quadruple M T = ( V , r , Σ , c ) MT = (\mathbf{V}, r, \Sigma, c) MT=(V,r,Σ,c) where
- V \mathbf{V} V is the set of nodes;
- r ∈ V r \in \mathbf{V} r∈V is the root node;
- Σ \Sigma Σ is the alphabet;
-
c
:
(
V
∪
{
ϕ
}
)
×
Σ
∗
→
V
∪
{
ϕ
}
c: (\mathbf{V} \cup \{\phi\}) \times \Sigma^* \to \mathbf{V} \cup \{\phi\}
c:(V∪{ϕ})×Σ∗→V∪{ϕ} satisfying
- ∀ v ∈ V \forall v \in \mathbf{V} ∀v∈V, c ( v , ε ) = v c(v, \varepsilon) = v c(v,ε)=v;
- ∀ v ∈ V \forall v \in \mathbf{V} ∀v∈V, s = a 1 a 2 … a n s = a_1 a_2 \dots a_n s=a1a2…an, c ( v , s ) = c ( ( v , a 1 ) , a 2 a 3 … a n ) c(v, s) = c((v, a_1), a_2 a_3 \dots a_n) c(v,s)=c((v,a1),a2a3…an);
- ∀ v ∈ V \forall v \in \mathbf{V} ∀v∈V, ∃ ! \exists ! ∃! s ∈ Σ ∗ s \in \Sigma^* s∈Σ∗ st. c ( r , s ) = v c(r, s) = v c(r,s)=v.
说明:
- 一般只给定 c : V × Σ → V ∪ { ϕ } c: \mathbf{V} \times \Sigma \to \mathbf{V} \cup \{\phi\} c:V×Σ→V∪{ϕ} 即可推导出 c : V × Σ ∗ → V ∪ { ϕ } c: \mathbf{V} \times \Sigma^* \to \mathbf{V} \cup \{\phi\} c:V×Σ∗→V∪{ϕ}. 前者简洁, 后者完备.
- 从有限状态自动机的角度, c c c 被称为状态转移函数, 即从一个状态读入一个字符, 转移下一个状态.
- 令 Σ = { l , r } \Sigma = \{\textrm{l}, \textrm{r}\} Σ={l,r}, 即获得我们熟悉的二叉树.
- 叶节点读入任何串, 都转移到空状态.
- 空状态读入任何串, 都转移到自己.
图 1. 二叉树
图 2. 带空节点的二叉树
13.3 Java 代码
public class MTree {
/**
* 节点数. 表示节点 v_0 至 v_{n-1}.
*/
int n;
/**
* 根节点. 0 至 n-1.
*/
int root;
/**
* 字母表大小. 字母表为 {1, 2, ..., m}
*/
int m;
/**
* 子节点. child[i][j] 表示在节点 i 读入字母 j 后转移到的状态.
*/
int[][] child;
/**
* 初始化一棵 m-树, 但现在它还无法表示一棵真正的 m-树.
*/
public MTree(int paraN, int paraM) {
n = paraN;
child = new int[n][m];
}// Of the constructor
/**
* 从当前节点读入一系列字符 (其实是整数), 转到相应的节点.
*/
public int getChild(int paraNode, int[] paraString) {
int resultNode = paraNode;
for (int i = 0; i < paraString.length; i++) {
resultNode = child[resultNode][paraString[i]];
if (resultNode == -1) {
break;
}//Of if
}//Of for i
return resultNode;
}// Of getChild
}//Of class MTree
说明:
- 为了广泛适应性, 字母表并未写成 {l, r} 这种形式, 而是直接定义了字母表大小. 这样, 可以认为字母表为 { 1 , … , m } \{1, \dots, m\} {1,…,m}, 二叉树的字母表则为 { 1 , 2 } \{1, 2\} {1,2}.
- 二维数组 child 确定了 m m m-叉树的结构.
- 需要根据数据初始化 m m m-叉树.
- 一般使用 -1 表示 ϕ \phi ϕ.
- 课堂练习: 写出图 1 二叉树所对应的 child 数组.
13.4 作业
- 画一棵三叉树, 并写出它的 child 数组.
- 按照本贴风格, 重新定义树. 提示: 还是应该定义 parent 函数, 字母表里面只有一个元素.
- 根据图、树、 m m m-叉树的学习, 谈谈你对元组的理解.