- /*
- 前中後序的遞歸實現理解起來最爲簡單,要點在於visit(node)的位置。
- */
- /*
- 前中後序遞歸實現
- */
- //前序遍歷
- void BT_PreOrder(BitTree node)
- {
- if(!node) return;
- visit(node);
- BT_PreOrder(node->left);
- BT_PreOrder(node->right);
- }
- //中序遍歷
- void BT_InOrder(BitTree node)
- {
- if(!node) return;
- BT_PreOrder(node->left);
- visit(node);
- BT_PreOrder(node->right);
- }
- //中序遍歷
- void BT_PostOrder(BitTree node)
- {
- if(!node) return;
- BT_PreOrder(node->left);
- BT_PreOrder(node->right);
- visit(node);
- }
二:層序遞歸實現
- /*
- 層序遍歷
- 這種方式用隊列來實現,也是最容易理解的方式,思路如下:
- 按照層序遍歷的定義,訪問完當前節點之後,則當前節點的左子節點具備了倒數第二優先級,當前節點的右子節點具備了倒數第一優先級,利用隊列先進先出的特性(可以確定最低的優先級),可以實現。
- */
- void BT_LevelOrder(BitTree node)
- {
- if(!node) return;
- queue<BitTree> q;
- q.push(node);
- BitTree pvNode;
- while(!q.empty())
- {
- pvNode = q.pop();
- visit(pvNode);
- if(!pvNode->left) q.push(pvNode->left);
- if(!pvNode->right) q.push(pvNode->right);
- }
- }
- /*
- 前序遍歷非遞歸實現1
- 這種方式用棧來實現,也是最容易理解的方式,思路如下:
- 按照前序遍歷的定義,訪問完當前節點之後,則當前節點的左子節點具備了第一優先級,當前節點的右子節點具備了第二優先級,
- 利用棧後進先出的特性(可以確定最高的優先級),可以實現。
- */
- void BT_PreOrderNoRec(BitTree node)
- {
- if(!node) return;
- stack<BitTree> s;
- BitTree pvNode;
- s.push(node);
- while(!s.empty())
- {
- pvNode = s.pop();
- visit(pvNode);
- if(!pvNode->right) s.push(pvNode->right);
- if(!pvNode->left) s.push(pvNode->left);
- }
- }
- /*
- 前序遍歷非遞歸實現2
- 在網上看到的一種寫法,個人覺得不如第一種實現起來更易懂
- */
- void BT_PreOrderNoRec2(BitTree node)
- {
- if(!node) return;
- stack<BitTree> s;
- while(!node && !s.empty())
- {
- /*如果當前節點不爲空,則直接訪問,然後將節點存儲到棧中(僅僅用來將來尋找右子節點),然後當前節點變爲左字節點*/
- if(node)
- {
- visit(node);
- s.push(node);
- node = node->left;
- }
- /*如果當前節點爲空,則到棧中取出上一個節點,並找出右子節點進行訪問*/
- else
- {
- node = s.pop();
- node = s.right;
- }
- }
- }
四:中序非遞歸
- /*
- 中序遍歷非遞歸實現
- 用棧來實現,這種方式可以用遞歸的思路來理解
- */
- void BT_InOrderNoRec(BitTree node)
- {
- if(!node) return;
- stack<BitTree> s;
- while(!s.empty())
- {
- /*如果當前節點不爲空,則不訪問,而是將它放入棧中,然後當前節點變爲左字節點;
- 一直採取這種方式,根據棧先進後出的特點,將來訪問的時候左字節點在前,當前節點在後;
- 正好是中序遍歷的特性
- */
- if(!node)
- {
- push(node);
- node = node->left();
- }
- /*如果當前節點爲空,則去棧裏取出節點訪問,然後訪問右子節點。
- 這裏有些不好理解,其實這裏的開端是左字節點爲空了,所以訪問了當前節點,然後右子節點;
- 同時當前節點爲根的二叉樹其實是上層的左字節點,依次類推正好是中序遍歷的特性
- */
- else
- {
- node = s.pop();
- visit(node);
- node = node->right;
- }
- }
- }
五:後序非遞歸
- /*
- 後序遍歷非遞歸實現
- 用棧來實現,不是很好理解,但是起碼不用藉助各種標誌位
- 思路如註釋所寫
- */
- void BT_PostOrderNoRec(BitTree node)
- {
- if(!node) return;
- stack<BitTree> s;
- BitTree tmp;//用來標誌剛剛訪問過的節點
- while(!node && !s.empty())
- {
- //如果當前節點不爲空,則壓入棧,當前節點變爲左字節點
- if(node)
- {
- s.push(node);
- node = node->left;
- }
- //如果爲空,則需要根據棧頂的節點來判定下一步
- else
- {
- //獲取棧頂節點,不是pop
- node = s.getPop();
- //如果棧頂節點有右子節點,並且(這不好理解,但很重要)右子節點不是我們剛剛訪問過的,
- //則,我們要去右子樹訪問
- if(node->right && node->right != tmp)
- {
- //把右子樹當作一個新的開始進行訪問:根節點壓入棧,訪問左字節點
- s.push(node->right);
- node = node->right->left;
- }
- //如果棧頂節點沒有右子節點,或者我們剛剛訪問過右子節點,則達到後序遍歷的要求,我們可以訪問當前節點
- else
- {
- //訪問當前節點,設置標誌節點(tmp)爲當前節點,當前節點置爲空
- node = s.pop();
- visit(node);
- tmp = node;
- node = null;
- }
- }
- }
- }