template <typename VST> //操作器
void travLevel(VST& visit) { if (_root) _root->travLevel(visit); } //層次遍歷
template <typename VST> //操作器
void travPre(VST& visit) { if (_root) _root->travPre(visit); } //先序遍歷
template <typename VST> //操作器
void travIn(VST& visit) { if (_root) _root->travIn(visit); } //中序遍歷
template <typename VST> //操作器
void travPost(VST& visit) { if (_root) _root->travPost(visit); } //後序遍歷
先序遍歷:
/*DSA*/#include "../stack/Stack.h" //引入棧模板類
/*DSA*/#include "BinNode_TravPreorder_R.h"
/*DSA*/#include "BinNode_TravPreorder_I1.h"
/*DSA*/#include "BinNode_TravPreorder_I2.h"
template <typename T> template <typename VST> //元素類型、操作器
void BinNode<T>::travPre(VST& visit) { //二叉樹先序遍歷算法統一入口
switch (rand() % 3) { //此處暫隨機選擇以做測試,共三種選擇
case 1: travPre_I1(this, visit); break; //迭代版#1
case 2: travPre_I2(this, visit); break; //迭代版#2
default: travPre_R(this, visit); break; //遞歸版
}
}
遞歸版:
template <typename T, typename VST> //元素類型、操作器
void travPre_R(BinNodePosi(T) x, VST& visit) { //二叉樹先序遍歷算法(遞歸版)
if (!x) return;
visit(x->data);
travPre_R(x->lChild, visit);
travPre_R(x->rChild, visit);
}
迭代版#1:
template <typename T, typename VST> //元素類型、操作器
void travPre_I1(BinNodePosi(T) x, VST& visit) { //二叉樹先序遍歷算法(迭代版#1)
Stack<BinNodePosi(T)> S; //輔助棧
if (x) S.push(x); //根節點入棧
while (!S.empty()) { //在棧變空之前反覆循環
x = S.pop(); visit(x->data); //彈出並訪問當前節點,其非空孩子的入棧次序爲
if (HasRChild(*x)) S.push(x->rChild); if (HasLChild(*x)) S.push(x->lChild); //先右後左
}
}
迭代版#2:
//從當前節點出發,沿左分支不斷深入,直至沒有左分支的節點;沿途節點遇到後立即訪問
template <typename T, typename VST> //元素類型、操作器
static void visitAlongLeftBranch(BinNodePosi(T) x, VST& visit, Stack<BinNodePosi(T)>& S) {
while (x) {
visit(x->data); //訪問當前節點
S.push(x->rChild); //右孩子入棧暫存(可優化:通過判斷,避免空的右孩子入棧)
x = x->lChild; //沿左分支深入一層
}
}
template <typename T, typename VST> //元素類型、操作器
void travPre_I2(BinNodePosi(T) x, VST& visit) { //二叉樹先序遍歷算法(迭代版#2)
Stack<BinNodePosi(T)> S; //輔助棧
while (true) {
visitAlongLeftBranch(x, visit, S); //從當前節點出發,逐批訪問
if (S.empty()) break; //直到棧空
x = S.pop(); //彈出下一批的起點
}
}
中序遍歷:
/*DSA*/#include "../stack/Stack.h" //引入棧模板類
/*DSA*/#include "BinNode_TravInorder_R.h"
/*DSA*/#include "BinNode_TravInorder_I1.h"
/*DSA*/#include "BinNode_TravInorder_I2.h"
/*DSA*/#include "BinNode_TravInorder_I3.h"
/*DSA*/#include "BinNode_TravInorder_I4.h"
template <typename T> template <typename VST> //元素類型、操作器
void BinNode<T>::travIn(VST& visit) { //二叉樹中序遍歷算法統一入口
switch (rand() % 5) { //此處暫隨機選擇以做測試,共五種選擇
case 1: travIn_I1(this, visit); break; //迭代版#1
case 2: travIn_I2(this, visit); break; //迭代版#2
case 3: travIn_I3(this, visit); break; //迭代版#3
case 4: travIn_I4(this, visit); break; //迭代版#4
default: travIn_R(this, visit); break; //遞歸版
}
}
遞歸版:
template <typename T, typename VST> //元素類型、操作器
void travIn_R(BinNodePosi(T) x, VST& visit) { //二叉樹中序遍歷算法(遞歸版)
if (!x) return;
travIn_R(x->lChild, visit);
visit(x->data);
travIn_R(x->rChild, visit);
}
迭代版#1:
template <typename T> //從當前節點出發,沿左分支不斷深入,直至沒有左分支的節點
static void goAlongLeftBranch(BinNodePosi(T) x, Stack<BinNodePosi(T)>& S) {
while (x) { S.push(x); x = x->lChild; } //當前節點入棧後隨即向左側分支深入,迭代直到無左孩子
}
template <typename T, typename VST> //元素類型、操作器
void travIn_I1(BinNodePosi(T) x, VST& visit) { //二叉樹中序遍歷算法(迭代版#1)
Stack<BinNodePosi(T)> S; //輔助棧
while (true) {
goAlongLeftBranch(x, S); //從當前節點出發,逐批入棧
if (S.empty()) break; //直至所有節點處理完畢
x = S.pop(); visit(x->data); //彈出棧頂節點並訪問之
x = x->rChild; //轉向右子樹
}
}
迭代版#2:
template <typename T, typename VST> //元素類型、操作器
void travIn_I2(BinNodePosi(T) x, VST& visit) { //二叉樹中序遍歷算法(迭代版#2)
Stack<BinNodePosi(T)> S; //輔助棧
while (true)
if (x) {
S.push(x); //根節點進棧
x = x->lChild; //深入遍歷左子樹
} else if (!S.empty()) {
x = S.pop(); //尚未訪問的最低祖先節點退棧
visit(x->data); //訪問該祖先節點
x = x->rChild; //遍歷祖先的右子樹
} else
break; //遍歷完成
}
迭代版#3:
template <typename T> BinNodePosi(T) BinNode<T>::succ() { //定位節點v的直接後繼
BinNodePosi(T) s = this; //記錄後繼的臨時變量
if (rChild) { //若有右孩子,則直接後繼必在右子樹中,具體地就是
s = rChild; //右子樹中
while (HasLChild(*s)) s = s->lChild; //最靠左(最小)的節點
} else { //否則,直接後繼應是“將當前節點包含於其左子樹中的最低祖先”,具體地就是
while (IsRChild(*s)) s = s->parent; //逆向地沿右向分支,不斷朝左上方移動
s = s->parent; //最後再朝右上方移動一步,即抵達直接後繼(如果存在)
}
return s;
}
template <typename T, typename VST> //元素類型、操作器
void travIn_I3(BinNodePosi(T) x, VST& visit) { //二叉樹中序遍歷算法(迭代版#3,無需輔助棧)
bool backtrack = false; //前一步是否剛從右子樹回溯——省去棧,僅O(1)輔助空間
while (true)
if (!backtrack && HasLChild(*x)) //若有左子樹且不是剛剛回溯,則
x = x->lChild; //深入遍歷左子樹
else { //否則——無左子樹或剛剛回溯(相當於無左子樹)
visit(x->data); //訪問該節點
if (HasRChild(*x)) { //若其右子樹非空,則
x = x->rChild; //深入右子樹繼續遍歷
backtrack = false; //並關閉回溯標誌
} else { //若右子樹空,則
if (!(x = x->succ())) break; //回溯(含抵達末節點時的退出返回)
backtrack = true; //並設置回溯標誌
}
}
}
迭代版#4:
template <typename T, typename VST> //元素類型、操作器
void travIn_I4(BinNodePosi(T) x, VST& visit) { //二叉樹中序遍歷算法(迭代版#4,無需棧或標誌位)
while (true)
if (HasLChild(*x)) //若有左子樹,則
x = x->lChild; //深入遍歷左子樹
else { //否則
visit(x->data); //訪問當前節點,並
while (!HasRChild(*x)) //不斷地在無右分支處
if (!(x = x->succ())) return; //回溯至直接後繼節點(在沒有後繼的末節點處,直接退出)
else visit(x->data); //訪問新的當前節點
x = x->rChild; //(直至有右分支處)轉向非空的右子樹
}
}
後序遍歷:
/*DSA*/#include "../stack/Stack.h" //引入棧模板類
/*DSA*/#include "BinNode_TravPostorder_R.h"
/*DSA*/#include "BinNode_TravPostorder_I.h"
template <typename T> template <typename VST> //元素類型、操作器
void BinNode<T>::travPost(VST& visit) { //二叉樹後序遍歷算法統一入口
switch (rand() % 2) { //此處暫隨機選擇以做測試,共兩種選擇
case 1: travPost_I(this, visit); break; //迭代版
default: travPost_R(this, visit); break; //遞歸版
}
}
遞歸版:
template <typename T, typename VST> //元素類型、操作器
void travPost_R(BinNodePosi(T) x, VST& visit) { //二叉樹後序遍歷算法(遞歸版)
if (!x) return;
travPost_R(x->lChild, visit);
travPost_R(x->rChild, visit);
visit(x->data);
}
迭代版#1:
template <typename T> //在以S棧頂節點爲根的子樹中,找到最高左側可見葉節點
static void gotoHLVFL(Stack<BinNodePosi(T)>& S) { //沿途所遇節點依次入棧
while (BinNodePosi(T) x = S.top()) //自頂而下,反覆檢查當前節點(即棧頂)
if (HasLChild(*x)) { //儘可能向左
if (HasRChild(*x)) S.push(x->rChild); //若有右孩子,優先入棧
S.push(x->lChild); //然後才轉至左孩子
} else //實不得已
S.push(x->rChild); //才向右
S.pop(); //返回之前,彈出棧頂的空節點
}
template <typename T, typename VST>
void travPost_I(BinNodePosi(T) x, VST& visit) { //二叉樹的後序遍歷(迭代版)
Stack<BinNodePosi(T)> S; //輔助棧
if (x) S.push(x); //根節點入棧
while (!S.empty()) {
if (S.top() != x->parent) //若棧頂非當前節點之父(則必爲其右兄),此時需
gotoHLVFL(S); //在以其右兄爲根之子樹中,找到HLVFL(相當於遞歸深入其中)
x = S.pop(); visit(x->data); //彈出棧頂(即前一節點之後繼),並訪問之
}
}
層次遍歷:
/*DSA*/#include "../queue/queue.h" //引入隊列
template <typename T> template <typename VST> //元素類型、操作器
void BinNode<T>::travLevel(VST& visit) { //二叉樹層次遍歷算法
Queue<BinNodePosi(T)> Q; //輔助隊列
Q.enqueue(this); //根節點入隊
while (!Q.empty()) { //在隊列再次變空之前,反覆迭代
BinNodePosi(T) x = Q.dequeue(); visit(x->data); //取出隊首節點並訪問之
if (HasLChild(*x)) Q.enqueue(x->lChild); //左孩子入隊
if (HasRChild(*x)) Q.enqueue(x->rChild); //右孩子入隊
}
}