回顾
前面学习了一些数据结构,根据其实现方式,这些数据结构可以划分为两种类型:基于数组的实现与基于链表的实现。
正如我们已经看到的,就其效率而言,这两种实现方式各有长短。
具体来说,基于数组实现的结构允许我们通过下标或秩,在常数的时间内找到目标对象,并读取或更新其内容。然而,一旦需要对这类结构进行修改,那么无论是插入还是删除,都需要耗费线性的时间。
反过来,基于链表实现的结构允许我们借助引用或位置对象,在常数的时间内插入或删除元素;但是为了找出居于特定次序的元素,我们不得不花费线性的时间对整个结构进行遍历查找。
能否将这两类结构的优点结合起来,并回避其不足呢?接下来将要介绍的树结构,将正面回答这一问题。
线性结构(Linear structures)、非线性结构(Non-linear structures )、半线性结构(Semi-linear structures)。
树
“树的某一元素是另一元 素‘直接上邻’”,也可以说“某一元素是另一元素的‘直接下邻’之一”。
术语
节点(Node)的深度、树的深度depth(v)与高度、树根(Root)、父 亲(Parent)、孩子(Child)、树边(Edge)、“兄弟” (Sibling)、“度”(Degree)、“内部节点”(Internal node)、“外部节点”(External node)、“叶子”(Leaf)、路径(Path)、“祖先”(Ancestor)、“后代”(Descendent)、子树(Subtree)、“空树”(Empty tree)、共同祖先(Common ancestor)、最低共同祖先(Lowerest common ancestor)、“有 序树(Ordered tree)”、二叉树(Binary tree)、真二叉树(Proper bina ry tree )、非真二叉树 (Improper binary tree)、完全二叉树(Complete binary tree)
/*
> 节点的深度、树的深度与高度
定义.1 在树结构中,
b 每个节点的深度都是一个非负整数;
c 深度为 0 的节点有且仅有一个,称作树根(Root);
d 对于深度为 k (k≥1)的每个节点 u,都有且仅有一个深度为 k-1 的节点 v 与之对应,称作 u 的父亲(Parent)或父节点。
定义.2 若节点 v 是节点 u 的父亲,则 u 称作 v 的孩子(Child),并在二者之间建立一条树边(Edge)。
定义.3 树中所有节点的最大深度,称作树的深度或高度。
观察结论.1 树中节点的数目,总是等于边数加一。
> 度、内部节点与外部节点
定义.4 任一节点的孩子数目,称作它的“度”(Degree)。
定义.5 至少拥有一个孩子的节点称作“内部节点”(Internal node);没有任何孩子的节点则称作“外部节点”(External node)或“叶子”(Leaf)。
定义.6 由树中 k+1 节点通过树边首尾衔接而构成的序列{ (v0, v1), (v1, v2), …, (vk-1, vk) | k ≥ 0},称作树中长度为 k 的一条路径(Path)。
观察结论.2 树中任何两个节点之间都存在唯一的一条路径。
观察结论.3 若 v 是 u 的父亲,则 depth(v) + 1 = depth(u)。
推论.1 从树根通往任一节点的路径长度,恰好等于该节点的深度。
> 祖先、后代、子树和节点的高度
定义.7
0. 每个节点都是自己的“祖先”(Ancestor),也是自己的“后代”(Descendent);
1. 若 v 是 u 的父节点的祖先,则 v 也是 u 的祖先;
2. 若 u 的父节点是 v 的后代,则 u 也是 v 的后代。
定义.8 除节点本身以外的祖先(后代),称作真祖先(后代)。
观察结论.4 任一节点 v 的深度,等于其真祖先的数目。
观察结论.5 任一节点 v 的祖先,在每一深度上最多只有一个。
定义.9 树 T 中每一节点 v 的所有后代也构成一棵树,称作 T 的“以 v 为根的子树(Subtree)”。
定义.10 若子树 v 的深度(高度)为 h,则称 v 的高度为 h,记作 height(v) = h。
观察结论.6 对于叶子节点 u 的任何祖先 v,必有 depth(v) + height(v) ≥ depth(u)。
> 共同祖先及最低共同祖先
定义.11 在树 T 中,若节点 u 和 v 都是节点 a 的后代,则称节点 a 为节点 u 和 v 的共同祖先(Commonancestor)。
定义.11 在树 T 中,若节点 u 和 v 都是节点 a 的后代,则称节点 a 为节点 u 和 v 的共同祖先(Commonancestor)。
观察结论.7 每一对节点至少存在一个共同祖先。
定义.12 在一对节点 u 和 v 的所有共同祖先中,深度最大者称为它们的最低共同祖先(Lowerestcommon ancestor),记作 lca(u, v)。
观察结论.8 每一对节点的最低共同祖先必存在且唯一。
> 有序树、m 叉树
定义.13 在树 T 中,若在每个节点的所有孩子之间都可以定义某一线性次序,则称 T 为一棵“有序树(Ordered tree)”。
定义.14 每个内部节点均为 m 度的有序树,称作 m 叉树。
二叉树>
定义.15 每个节点均不超过 2 度的有序树,称作二叉树(Binary tree)。
定义.16 不含 1 度节点的二叉树,称作真二叉树(Proper bina ry tree ),否则称作非真二叉树(Improper binary tree)。
观察结论.9 在二叉树中,深度为 k 的节点不超过 2k 个。
推论.2 高度为 h 的二叉树最多包含 2h+1-1 个节点。
推论.3 由 n 个节点构成的二叉树,高度至少为⎣log2n⎦。
观察结论.10 在二叉树中,叶子总是比 2 度节点多一个。
> 满二叉树与完全二叉树
定义.17 若二叉树 T 中所有叶子的深度完全相同,则称之为满二叉树(Full binary tree)。
观察结论.11 高度为 h 的二叉树是满的,当且仅当它拥有 2h匹叶子、2h+1-1 个节点。
定义.18 若在一棵满二叉树中,从最右侧起将相邻的若干匹叶子节点摘除掉,则得到的二叉树称作完全二叉树(Complete binary tree)。
引理.1 由 n 个节点构成的完全二叉树,高度 h = ⎣log2n⎦。
推论.4 在由固定数目的节点所组成的所有二叉树中,完全二叉树的高度最低。
> 树的基本算法
getSize()⎯⎯统计(子)树的规模
观察结论四.12 一棵树的规模,等于根节点下所有子树规模之和再加一,也等于根节点的后代总数。
getHeight()⎯⎯计算节点的高度
推论四.5 c 若 u 是 v 的孩子,则 height(v) ≥ height(u) + 1;
d height(v) = 1 + max height(u)。
u是v的孩子
推论四.6 若 u 是 v 的孩子,则 depth(u) = depth(v) + 1。
定理四.1 树的前序、后序及层次遍历,均可在 O(n)时间内完成,其中 n 为树本身的规模。
*/
树抽象数据类型及其实现
public interface Tree {
/**
* @return 当前节点中存放的对象
*/
Object getElem();
/**
* 将对象obj存入当前节点,并返回此前的内容
*
* @param obj
* @return
*/
Object setElem(Object obj);
/**
* @return 当前节点的父节点
*/
TreeLinkedList getParent();
/**
* @return 当前节点的长子
*/
TreeLinkedList getFirstChild();
/**
* @return 当前节点的最大弟弟
*/
TreeLinkedList getNextSibling();
/**
* @return 当前节点后代元素的数目,即以当前节点为根的子树的规模
*/
int getSize();
/**
* @return 当前节点的高度
*/
int getHeight();
/**
* @return 当前节点的深度
*/
int getDepth();
}
基于链表实现树
public class TreeLinkedList implements Tree {
/**
* 树根节点
*/
private Object element;
/**
* 父亲、长子及最大的弟弟
*/
private TreeLinkedList parent, firstChild, nextSibling;
/**
* (单节点树)构造方法
*/
public TreeLinkedList() {
this(null, null, null, null);
}
/**
* 构造方法
* @param e
* @param p
* @param c
* @param s
*/
public TreeLinkedList(Object e, TreeLinkedList p, TreeLinkedList c, TreeLinkedList s) {
element = e;
parent = p;
firstChild = c;
nextSibling = s;
}
/*---------- Tree接口中各方法的实现 ----------*/
/**
* 返回当前节点中存放的对象
*
* @return
*/
@Override
public Object getElem() {
return element;
}
//
/**
* 将对象obj存入当前节点,并返回此前的内容
*
* @param obj
* @return
*/
@Override
public Object setElem(Object obj) {
Object bak = element;
element = obj;
return bak;
}
/**
* 返回当前节点的父节点;对于根节点,返回null
*
* @return
*/
@Override
public TreeLinkedList getParent() {
return parent;
}
/**
* 返回当前节点的长子;若没有孩子,则返回null
*
* @return
*/
@Override
public TreeLinkedList getFirstChild() {
return firstChild;
}
/**
* 返回当前节点的最大弟弟;若没有弟弟,则返回null
*
* @return
*/
@Override
public TreeLinkedList getNextSibling() {
return nextSibling;
}
/**
* 返回当前节点后代元素的数目,即以当前节点为根的子树的规模
*
* @return
*/
@Override
public int getSize() {
/**
* 当前节点也是自己的后代
*/
int size = 1;
/**
* 从长子开始
*/
TreeLinkedList subtree = firstChild;
/**依次
*
*/
while (null != subtree) {
/**
* 累加
*/
size += subtree.getSize();
/**
* 所有孩子的后代数目
*/
subtree = subtree.getNextSibling();
}
/**
* 即可得到当前节点的后代总数
*/
return size;
}
/**
* 返回当前节点的高度
*
* @return
*/
@Override
public int getHeight() {
int height = -1;
/**
* 从长子开始
*/
TreeLinkedList subtree = firstChild;
/**
* 依次
*/
while (null != subtree) {
/**
* 在所有孩子中取最大高度
*/
height = Math.max(height, subtree.getHeight());
subtree = subtree.getNextSibling();
}
/**
* 即可得到当前节点的高度
*/
return height + 1;
}
/**
* 返回当前节点的深度
* @return
*/
@Override
public int getDepth() {
int depth = 0;
/**
* 从父亲开始
*/
TreeLinkedList p = parent;
/**
* 依次
*/
while (null != p) {
depth++;
/**访问各个真祖先
*
*/
p = p.getParent();
}
/**
* 真祖先的数目,即为当前节点的深度
*/
return depth;
}
}
前序、后序遍历
所谓树的遍历(Traversal),就是按照某种次序访问树中的节点,且每个节点恰好访问一次。
也就是说,按照被访问的次序,可以得到由树中所有节点排成的一个序列。
两种最基本的树遍历算法⎯⎯前序遍历(PreorderTraversal)和后序遍历(Postorder traversal)。这两种遍历算法都是递归定义的,只是其中对“次序”的定义略有 不同。
PreorderTraversal
if (null != v) {
for (u = v.getFirstChild(); null != u; u = u.getNextSibling())
PreorderTraversal(u);
}
LevelorderTraversal
if (null != v) {
Q.enqueue(v);
while (!Q.isEmpty()) {
u = Q.dequeue();
for (w = u.getFirstChild(); null != w; w = w.nextSibling())
Q.enqueue(w);
}
}
树迭代器
public class IteratorTree implements Iterator {
/**
* 列表
*/
private List list;
/**
* 当前(下一个)元素的位置
*/
private Position nextPosition;
/**
* 默认构造方法
*/
public IteratorTree() {
list = null;
}
/**
* 前序遍历
*
* @param T
*/
public void elementsPreorderIterator(TreeLinkedList T) {
if (null == T) {
//递归基
return;
}
//首先输出当前节点
list.insertLast(T);
//从当前节点的长子开始
TreeLinkedList subtree = T.getFirstChild();
//依次对当前节点的各个孩子
while (null != subtree) {
//做前序遍历
this.elementsPreorderIterator(subtree);
subtree = subtree.getNextSibling();
}
}
/**
* 后序遍历
*
* @param T
*/
public void elementsPostorderIterator(TreeLinkedList T) {
if (null == T) {
//递归基
return;
}
//从当前节点的长子开始
TreeLinkedList subtree = T.getFirstChild();
//依次对当前节点的各个孩子
while (null != subtree) {
//做后序遍历
this.elementsPostorderIterator(subtree);
subtree = subtree.getNextSibling();
}
//当所有后代都访问过后,最后才访问当前节点
list.insertLast(T);
}
/**
* 层次遍历
*
* @param T
*/
public void levelTraversalIterator(TreeLinkedList T) {
if (null == T) {
return;
}
//空队
QueueList Q = new QueueList();
//根节点入队
Q.enqueue(T);
//在队列重新变空之前
while (!Q.isEmpty()) {
//取出队列首节点
TreeLinkedList tree = (TreeLinkedList) (Q.dequeue());
//将新出队的节点接入迭代器中
list.insertLast(tree);
//从tree的第一个孩子起
TreeLinkedList subtree = tree.getFirstChild();
//依次找出所有孩子,并
while (null != subtree) {
//将其加至队列中
Q.enqueue(subtree);
subtree = subtree.getNextSibling();
}
}
}
/**
* 检查迭代器中是否还有剩余的元素
*
* @return
*/
@Override
public boolean hasNext() {
return (null != nextPosition);
}
/**
* 返回迭代器中的下一元素
*
* @return
* @throws ExceptionNoSuchElement
*/
@Override
public Object getNext() throws ExceptionNoSuchElement {
if (!hasNext()) {
throw new ExceptionNoSuchElement("No next position");
}
Position currentPosition = nextPosition;
if (currentPosition == list.last()) {//若已到达尾元素,则
//不再有下一元素
nextPosition = null;
} else {//转向下一元素
//否则
nextPosition = list.getNext(currentPosition);
}
return currentPosition.getElem();
}
}
二叉树
二叉树类的 Java 接口
/**
* <b>Description:</b> 二叉树接口 <br>
*/
public interface BinTree {
/**
* 返回树根
*
* @return
*/
public BinTreePosition getRoot();
/**
* 判断是否树空
*
* @return
*/
public boolean isEmpty();
/**
* 返回树的规模(即树根的后代数目)
*
* @return
*/
public int getSize();
/**
* 返回树(根)的高度
*
* @return
*/
public int getHeight();
/**
* 前序遍历
*
* @return
*/
public Iterator elementsPreorder();
/**
* 中序遍历
*
* @return
*/
public Iterator elementsInorder();
/**
* 后序遍历
*
* @return
*/
public Iterator elementsPostorder();
/**
* 层次遍历
*
* @return
*/
public Iterator elementsLevelorder();
}
二叉树节点ADT接口
为了在遵循面向对象规范的同时保证效率,这里也将使用位置的概念来描述和实现二叉树节点。
/**
* <b>Description:</b> 二叉树节点ADT接口 <br>
*/
public interface BinTreePosition extends Position {
/**
* 判断是否有父亲(为使代码描述简洁)
*
* @return
*/
public boolean hasParent();
/**
* 返回当前节点的父节点
*
* @return
*/
public BinTreePosition getParent();
/**
* 设置当前节点的父节点
*
* @param p
*/
public void setParent(BinTreePosition p);
/**
* 判断是否为叶子
*
* @return
*/
public boolean isLeaf();
/**
* 判断是否为左孩子(为使代码描述简洁)
*
* @return
*/
public boolean isLChild();
/**
* 判断是否有左孩子(为使代码描述简洁)
*
* @return
*/
public boolean hasLChild();
/**
* 返回当前节点的左孩子
*
* @return
*/
public BinTreePosition getLChild();
/**
* 设置当前节点的左孩子(注意:this.lChild和c.parent都不一定为空)
*
* @param c
*/
public void setLChild(BinTreePosition c);
/**
* 判断是否为右孩子(为使代码描述简洁)
*
* @return
*/
public boolean isRChild();
/**
* 判断是否有右孩子(为使代码描述简洁)
*
* @return
*/
public boolean hasRChild();
/**
* 返回当前节点的右孩子
*
* @return
*/
public BinTreePosition getRChild();
/**
* 设置当前节点的右孩子(注意:this.rChild和c.parent都不一定为空)
*
* @param c
*/
public void setRChild(BinTreePosition c);
/**
* 返回当前节点后代元素的数目
*
* @return
*/
public int getSize();
/**
* 在孩子发生变化后,更新当前节点及其祖先的规模
*/
public void updateSize();
/**
* 返回当前节点的高度
*
* @return
*/
public int getHeight();
/**
* 在孩子发生变化后,更新当前节点及其祖先的高度
*/
public void updateHeight();
/**
* 返回当前节点的深度
*
* @return
*/
public int getDepth();
/**
* 在父亲发生变化后,更新当前节点及其后代的深度
*/
public void updateDepth();
/**
* 按照中序遍历的次序,找到当前节点的直接前驱
*
* @return
*/
public BinTreePosition getPrev();
/**
* 按照中序遍历的次序,找到当前节点的直接后继
*
* @return
*/
public BinTreePosition getSucc();
/**
* 断绝当前节点与其父亲的父子关系 返回当前节点
*
* @return
*/
public BinTreePosition secede();
/**
* 将节点c作为当前节点的左孩子
*
* @param c
* @return
*/
public BinTreePosition attachL(BinTreePosition c);
/**
* 将节点c作为当前节点的右孩子
*
* @param c
* @return
*/
public BinTreePosition attachR(BinTreePosition c);
/**
* 前序遍历
*
* @return
*/
public Iterator elementsPreorder();
/**
* 中序遍历
*
* @return
*/
public Iterator elementsInorder();
/**
* 后序遍历
*
* @return
*/
public Iterator elementsPostorder();
/**
* 层次遍历
*
* @return
*/
public Iterator elementsLevelorder();
}
基于链表节点实现二叉树节点
/**
* <b>Description:</b> 基于链表节点实现二叉树节点 <br>
*/
public class BinTreeNode implements BinTreePosition {
/**
* 该节点中存放的对象
*/
protected Object element;
/**
* 父亲
*/
protected BinTreePosition parent;
/**
* 左孩子
*/
protected BinTreePosition lChild;
/**
* 右孩子
*/
protected BinTreePosition rChild;
/**
* 后代数目
*/
protected int size;
/**
* 高度
*/
protected int height;
/**
* 深度
*/
protected int depth;
/**************************** 构造方法 ****************************/
public BinTreeNode() {
this(null, null, true, null, null);
}
/**
* @param e 节点内容
* @param p 父节点
* @param asLChild 是否作为父节点的左孩子
* @param l 左孩子
* @param r 右孩子
*/
public BinTreeNode(Object e, BinTreePosition p, boolean asLChild, BinTreePosition l, BinTreePosition r) {
size = 1;
height = depth = 0;
//初始化
parent = lChild = rChild = null;
//存放的对象
element = e;
// 建立与父亲的关系
if (null != p) {
if (asLChild) {
p.attachL(this);
} else {
p.attachR(this);
}
}
//建立与孩子的关系
if (null != l) {
attachL(l);
}
if (null != r) {
attachR(r);
}
}
/**************************** Position接口方法 ********************************/
/**
* 返回当前节点中存放的对象
*
* @return
*/
@Override
public Object getElem() {
return element;
}
/**
* 将对象obj存入当前节点,并返回此前的内容
*
* @param obj
* @return
*/
@Override
public Object setElem(Object obj) {
Object bak = element;
element = obj;
return bak;
}
/**************************** BinTreePosition接口方法 *************************/
/**
* 判断是否有父亲(为使代码描述简洁)
*
* @return
*/
@Override
public boolean hasParent() {
//返回当前节点的父节点
return null != parent;
}
@Override
public BinTreePosition getParent() {
//设置当前节点的父节点
return parent;
}
@Override
public void setParent(BinTreePosition p) {
parent = p;
}
/**
* 判断是否为叶子
*
* @return
*/
@Override
public boolean isLeaf() {
//判断是否为左孩子(为使代码描述简洁)
return !hasLChild() && !hasRChild();
}
/**
* 若当前节点有父亲,而且是左孩子,则返回true;否则,返回false
*
* @return
*/
@Override
public boolean isLChild() {
return (hasParent() && this == getParent().getLChild()) ? true : false;
}
/**
* 判断是否有左孩子(为使代码描述简洁)
*
* @return
*/
@Override
public boolean hasLChild() {
return null != lChild;
}
/**
* 返回当前节点的左孩子
*
* @return
*/
@Override
public BinTreePosition getLChild() {
return lChild;
}
/**
* 设置当前节点的左孩子(注意:this.lChild和c.parent都不一定为空)
*
* @param c
*/
@Override
public void setLChild(BinTreePosition c) {
lChild = c;
}
/**
* 判断是否为右孩子(为使代码描述简洁)
*
* @return 若当前节点有父亲,而且是右孩子,则返回true;否则,返回false
*/
@Override
public boolean isRChild() {
return (hasParent() && this == getParent().getRChild()) ? true : false;
}
/**
* 判断是否有右孩子(为使代码描述简洁)
*
* @return
*/
@Override
public boolean hasRChild() {
return null != rChild;
}
/**
* 返回当前节点的右孩子
*
* @return
*/
@Override
public BinTreePosition getRChild() {
return rChild;
}
/**
* 设置当前节点的右孩子(注意:this.rChild和c.parent都不一定为空)
*
* @param c
*/
@Override
public void setRChild(BinTreePosition c) {
rChild = c;
}
/**
* 返回当前节点后代元素的数目
*
* @return
*/
@Override
public int getSize() {
return size;
}
/**
* 在孩子发生变化后,更新当前节点及其祖先的规模
*/
@Override
public void updateSize() {
//当前节点
size = 1;
if (hasLChild()) {
//左子树的规模
size += getLChild().getSize();
}
if (hasRChild()) {
//右子树的规模
size += getRChild().getSize();
}
if (hasParent()) {
//递归更新各个真祖先的规模记录
getParent().updateSize();
}
}
/**
* 返回当前节点的高度
*
* @return
*/
@Override
public int getHeight() {
return height;
}
/**
* 在孩子发生变化后,更新当前节点及其祖先的高度
*/
@Override
public void updateHeight() {
//先假设没有左、右孩子
height = 0;
if (hasLChild()) {
//左孩子
height = Math.max(height, 1 + getLChild().getHeight());
}
if (hasRChild()) {
//右孩子
height = Math.max(height, 1 + getRChild().getHeight());
}
if (hasParent()) {
//递归更新各个真祖先的高度记录
getParent().updateHeight();
}
}
/**
* 返回当前节点的深度
*
* @return
*/
@Override
public int getDepth() {
return depth;
}
/**
* 在父亲发生变化后,更新当前节点及其后代的深度
*/
@Override
public void updateDepth() {
//当前节点
depth = hasParent() ? 1 + getParent().getDepth() : 0;
if (hasLChild()) {
//沿孩子引用逐层向下,
getLChild().updateDepth();
}
if (hasRChild()) {
//递归地更新所有后代的深度记录
getRChild().updateDepth();
}
}
/**
* 按照中序遍历的次序,找到当前节点的直接前驱
*
* @return
*/
@Override
public BinTreePosition getPrev() {
//若左子树非空,则其中的最大者即为当前节点的直接前驱
if (hasLChild()) {
return findMaxDescendant(getLChild());
}
//至此,当前节点没有左孩子
if (isRChild()) {
//若当前节点是右孩子,则父亲即为其直接前驱
return getParent();
}
//至此,当前节点没有左孩子,而且是左孩子
//从当前节点出发
BinTreePosition v = this;
while (v.isLChild()) {
//沿左孩子链一直上升
v = v.getParent();
}
//至此,v或者没有父亲,或者是父亲的右孩子
return v.getParent();
}
/**
* 按照中序遍历的次序,找到当前节点的直接后继
*
* @return
*/
@Override
public BinTreePosition getSucc() {
//若右子树非空,则其中的最小者即为当前节点的直接后继
if (hasRChild()) {
return findMinDescendant(getRChild());
}
//至此,当前节点没有右孩子
if (isLChild()) {
//若当前节点是左孩子,则父亲即为其直接后继
return getParent();
}
//至此,当前节点没有右孩子,而且是右孩子
//从当前节点出发
BinTreePosition v = this;
while (v.isRChild()) {
//沿右孩子链一直上升
v = v.getParent();
}
//至此,v或者没有父亲,或者是父亲的左孩子
return v.getParent();
}
/**
* 断绝当前节点与其父亲的父子关系。
* 将以某一节点为根的子树从母树中分离出来。
*
* @return 返回当前节点
*/
@Override
public BinTreePosition secede() {
if (null != parent) {
if (isLChild()) {
//切断父亲指向当前节点的引用
parent.setLChild(null);
} else {
parent.setRChild(null);
}
//更新当前节点及其祖先的规模
parent.updateSize();
//更新当前节点及其祖先的高度
parent.updateHeight();
//切断当前节点指向原父亲的引用
parent = null;
//更新节点及其后代节点的深度
updateDepth();
}
//返回当前节点
return this;
}
/**
* 将节点c作为当前节点的左孩子
*
* @param c
* @return
*/
@Override
public BinTreePosition attachL(BinTreePosition c) {
if (hasLChild()) {
//摘除当前节点原先的左孩子
getLChild().secede();
}
if (null != c) {
//c脱离原父亲
c.secede();
lChild = c;
//确立新的父子关系
c.setParent(this);
//更新当前节点及其祖先的规模
updateSize();
//更新当前节点及其祖先的高度
updateHeight();
//更新c及其后代节点的深度
c.updateDepth();
}
return this;
}
/**
* 将节点c作为当前节点的右孩子
*
* @param c
* @return
*/
@Override
public BinTreePosition attachR(BinTreePosition c) {
if (hasRChild()) {
//摘除当前节点原先的右孩子
getRChild().secede();
}
if (null != c) {
//c脱离原父亲
c.secede();
rChild = c;
//确立新的父子关系
c.setParent(this);
//更新当前节点及其祖先的规模
updateSize();
//更新当前节点及其祖先的高度
updateHeight();
//更新c及其后代节点的深度
c.updateDepth();
}
return this;
}
/**
* 前序遍历
*
* @return
*/
@Override
public Iterator elementsPreorder() {
List list = new ListDLNode();
preorder(list, this);
return list.elements();
}
/**
* 中序遍历
*
* @return
*/
@Override
public Iterator elementsInorder() {
List list = new ListDLNode();
inorder(list, this);
return list.elements();
}
/**
* 后序遍历
*
* @return
*/
@Override
public Iterator elementsPostorder() {
List list = new ListDLNode();
postorder(list, this);
return list.elements();
}
/**
* 层次遍历
*
* @return
*/
@Override
public Iterator elementsLevelorder() {
List list = new ListDLNode();
levelorder(list, this);
return list.elements();
}
/**************************** 辅助方法 ****************************/
/**
* 在v的后代中,找出最小者
*
* @param v
* @return
*/
protected static BinTreePosition findMinDescendant(BinTreePosition v) {
if (null != v) {
while (v.hasLChild()) {
//从v出发,沿左孩子链一直下降
v = v.getLChild();
}
}
//至此,v或者为空,或者没有左孩子
return v;
}
/**
* 在v的后代中,找出最大者
*
* @param v
* @return
*/
protected static BinTreePosition findMaxDescendant(BinTreePosition v) {
if (null != v) {
while (v.hasRChild()) {
//从v出发,沿右孩子链一直下降
v = v.getRChild();
}
}
//至此,v或者为空,或者没有右孩子
return v;
}
/**
* 前序遍历以v为根节的(子)树
*
* @param list
* @param v
*/
protected static void preorder(List list, BinTreePosition v) {
if (null == v) {
//递归基:空树
return;
}
//访问v
list.insertLast(v);
//遍历左子树
preorder(list, v.getLChild());
//遍历右子树
preorder(list, v.getRChild());
}
/**
* 中序遍历以v为根节的(子)树
*
* @param list
* @param v
*/
protected static void inorder(List list, BinTreePosition v) {
if (null == v) {
//递归基:空树
return;
}
//遍历左子树
inorder(list, v.getLChild());
//访问v
list.insertLast(v);
//遍历右子树
inorder(list, v.getRChild());
}
/**
* 后序遍历以v为根节的(子)树
*
* @param list
* @param v
*/
protected static void postorder(List list, BinTreePosition v) {
if (null == v) {
//递归基:空树
return;
}
//遍历左子树
postorder(list, v.getLChild());
//遍历右子树
postorder(list, v.getRChild());
//访问v
list.insertLast(v);
}
/**
* 层次遍历以v为根节的(子)树
*
* @param list
* @param v
*/
protected static void levelorder(List list, BinTreePosition v) {
//空队
QueueList Q = new QueueList();
//根节点入队
Q.enqueue(v);
while (!Q.isEmpty()) {
//出队
BinTreePosition u = (BinTreePosition) Q.dequeue();
//访问v
list.insertLast(u);
if (u.hasLChild()) {
Q.enqueue(u.getLChild());
}
if (u.hasRChild()) {
Q.enqueue(u.getRChild());
}
}
}
}
基于链表实现二叉树
/**
* <b>Create Date:</b> 2018/9/25<br>
* <b>Email:</b> 289286298@qq.com<br>
* <b>Description:</b> 基于链表实现二叉树 <br>
*
* @author tongson
*/
public class BinTreeLinkedList implements BinTree {
/**
* 根节点
*/
protected BinTreePosition root;
/**************************** 构造函数 ****************************/
public BinTreeLinkedList() {
this(null);
}
public BinTreeLinkedList(BinTreePosition r) {
root = r;
}
/**************************** BinaryTree接口方法 ****************************/
/**
* 返回树根
*
* @return
*/
@Override
public BinTreePosition getRoot() {
return root;
}
/**
* 判断是否树空
*
* @return
*/
@Override
public boolean isEmpty() {
return null == root;
}
/**
* 返回树的规模(即树根的后代数目)
*
* @return
*/
@Override
public int getSize() {
return isEmpty() ? 0 : root.getSize();
}
/**
* 返回树(根)的高度
*
* @return
*/
@Override
public int getHeight() {
return isEmpty() ? -1 : root.getHeight();
}
/**
* 前序遍历
*
* @return
*/
@Override
public Iterator elementsPreorder() {
return root.elementsPreorder();
}
/**
* 中序遍历
*
* @return
*/
@Override
public Iterator elementsInorder() {
return root.elementsInorder();
}
/**
* 后序遍历
*
* @return
*/
@Override
public Iterator elementsPostorder() {
return root.elementsPostorder();
}
/**
* 层次遍历
*
* @return
*/
@Override
public Iterator elementsLevelorder() {
return root.elementsLevelorder();
}
}
完全二叉树
接口
/**
* <b>Description:</b> 完全二叉树接口 <br>
*/
public interface ComplBinTree extends BinTree {
/**
* 生成并返回一个存放e的外部节点,该节点成为新的末节点
*
* @param e
* @return
*/
BinTreePosition addLast(Object e);
/**
* 删除末节点,并返回其中存放的内容
*
* @return
*/
Object delLast();
/**
* 返回按照层次遍历编号为i的节点的位置,0 <= i < size()
*
* @param i
* @return
*/
BinTreePosition posOfNode(int i);
}
基于秩实现的完全二叉树节点
/**
* <b>Description:</b> 基于秩实现的完全二叉树节点 <br>
*/
public class ComplBinTreeNodeRank extends BinTreeNode implements BinTreePosition {
/**
* 所属的树
*/
private Vector T;
/**
* 在所属树中的秩
*/
private int rank;
/**
* 存放的对象
*/
private Object element;
/**
* 构造函数
*
* @param t
* @param obj
*/
public ComplBinTreeNodeRank(Vector t, Object obj) {
element = obj;
T = t;
rank = T.getSize();
T.insertAtRank(rank, this);
}
/**
* 返回当前节点中存放的对象
*
* @return
*/
@Override
public Object getElem() {
return element;
}
/**
* 将对象obj存入当前节点,并返回此前的内容
*
* @param obj
* @return
*/
@Override
public Object setElem(Object obj) {
Object bak = element;
element = obj;
return bak;
}
/**
* 判断是否有父亲(为使代码描述简洁)
*
* @return
*/
@Override
public boolean hasParent() {
return (0 != rank) ? true : false;
}
/**
* 返回当前节点的父节点
*
* @return
*/
@Override
public BinTreePosition getParent() {
return hasParent() ? (BinTreePosition) T.getAtRank((rank - 1) / 2) : null;
}
/**
* 判断是否有左孩子(为使代码描述简洁)
*
* @return
*/
@Override
public boolean hasLChild() {
return (1 + rank * 2 < T.getSize()) ? true : false;
}
/**
* 返回当前节点的左孩子
*
* @return
*/
@Override
public BinTreePosition getLChild() {
return hasLChild() ? (BinTreePosition) (T.getAtRank(1 + rank * 2)) : null;
}
/**
* 判断是否有右孩子(为使代码描述简洁)
*
* @return
*/
@Override
public boolean hasRChild() {
return (2 + rank * 2 < T.getSize()) ? true : false;
}
/**
* 返回当前节点的右孩子
*
* @return
*/
@Override
public BinTreePosition getRChild() {
return hasRChild() ? (BinTreePosition) (T.getAtRank(2 + rank * 2)) : null;
}
/**
* 返回当前节点后代元素的数目
*
* @return
*/
@Override
public int getSize() {
int size = 1;
if (hasLChild()) {
size += getLChild().getSize();
}
if (hasRChild()) {
size += getRChild().getSize();
}
return size;
}
/**
* 返回当前节点的高度
*
* @return
*/
@Override
public int getHeight() {
int hL = hasLChild() ? getLChild().getHeight() : -1;
int hR = hasRChild() ? getRChild().getHeight() : -1;
return 1 + Math.max(hL, hR);
}
/**
* 返回当前节点的深度
*
* @return
*/
@Override
public int getDepth() {
return hasParent() ? 1 + getParent().getDepth() : 0;
}
}
基于向量的实现
/**
* <b>Description:</b> 基于向量实现的完全二叉树 <br>
*/
public class ComplBinTreeVector extends BinTreeLinkedList implements ComplBinTree {
/**
* 向量
*/
private Vector T;
/**
* 构造方法:默认的空树
*/
public ComplBinTreeVector() {
T = new VectorExtArray();
root = null;
}
/**
* 构造方法:按照给定的节点序列,批量式建立完全二叉树
*
* @param s
*/
public ComplBinTreeVector(Sequence s) {
this();
if (null != s) {
while (!s.isEmpty()) {
addLast(s.removeFirst());
}
}
}
/*---------- BinaryTree接口中各方法的实现 ----------*/
/**
* 返回树根(重写)
*
* @return
*/
@Override
public BinTreePosition getRoot() {
return T.isEmpty() ? null : posOfNode(0);
}
/**
* 判断是否树空(重写)
*
* @return
*/
@Override
public boolean isEmpty() {
return T.isEmpty();
}
/**
* 返回树的规模(重写)
*
* @return
*/
@Override
public int getSize() {
return T.getSize();
}
/**
* 返回树(根)的高度(重写)
*
* @return
*/
@Override
public int getHeight() {
return isEmpty() ? -1 : getRoot().getHeight();
}
/*---------- ComplBinTree接口中各方法的实现 ----------*/
/**
* 生成并返回一个存放e的外部节点,该节点成为新的末节点
*
* @param e
* @return
*/
@Override
public BinTreePosition addLast(Object e) {
BinTreePosition node = new ComplBinTreeNodeRank(T, e);
root = (BinTreePosition) T.getAtRank(0);
return node;
}
/**
* 删除末节点,并返回其中存放的内容
*
* @return
*/
@Override
public Object delLast() {
if (isEmpty()) {
//若树(堆)已空,无法删除
return null;
}
if (1 == getSize()) {
//若删除最后一个节点,则树空
root = null;
}
return T.removeAtRank(T.getSize() - 1);
}
/**
* 返回按照层次遍历编号为i的节点的位置,0 <= i < size()
*
* @param i
* @return
*/
@Override
public BinTreePosition posOfNode(int i) {
return (BinTreePosition) T.getAtRank(i);
}
}