BinTree::遍歷

   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); //右孩子入隊
   }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章