回顧
前面學習了一些資料結構,根據其實現方式,這些資料結構可以劃分為兩種型別:基於陣列
的實現與基於連結串列
的實現。
正如我們已經看到的,就其效率而言,這兩種實現方式各有長短
。
具體來說,基於陣列
實現的結構允許我們通過下標或秩,在常數的時間內找到
目標物件,並讀取或更新
其內容。然而,一旦需要對這類結構進行修改,那麼無論是插入還是刪除,都需要耗費線性的時間。
反過來,基於連結串列
實現的結構允許我們藉助引用或位置
物件,在常數的時間內插入或刪除
元素;但是為了找出居於特定次序的元素,我們不得不花費線性的時間對整個結構進行遍歷查詢。
能否將這兩類結構的優點結合起來,並回避其不足呢?接下來將要介紹的樹
結構,將正面回答這一問題。
線性結構(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);
}
}
複製程式碼