C++:二叉查詢樹實現(二)——遍歷操作
建立好二叉樹,有時候我們需要對整個二叉樹錦星遍歷,即輸出二叉樹的所有結點元素。理論上,遍歷的方式有無數種,順序可以自己任意選定,但是絕大部分遍歷方式在實際中並沒有用處,比較有用的的遍歷方式有兩種:廣度優先遍歷、深度優先遍歷。
(1)廣度優先遍歷
廣度優先遍歷的意思是每次優先遍歷完一層的所有子節點,遍歷完N層子節點後再遍歷N+1層節點,遵循的原則是自上而下、自左向右。
圖1.典型二叉查詢樹
圖中的二叉查詢樹使用廣度優先遍歷的方法,獲得的結果是:8,3,10,1,6,14,4,7,13.。
要實現廣度優先遍歷,可以考慮使用佇列實現,我們知道佇列的性質是先進先出,我們先將節點8壓入佇列,輸出節點後,彈出節點8,再將節點3和節點10壓入佇列(注意順序)。接下來繼續對佇列處理,節點3先壓入佇列,所以先處理節點3,處理完之後將該節點彈出,將其左有兩個節點1和6壓入佇列,但是要注意此時佇列中還有節點10沒有處理,因此先處理節點10,處理完之後彈出並將其子節點14壓入佇列。以此類推,二叉樹的節點壓入佇列的順序為
圖2.廣度優先遍歷時節點入隊順序以及輸出順序
圖中的豎線表示這些節點是在不同的迴圈中壓入佇列,按這個順序對二叉樹輸出,,圖中相同顏色曲線表示這些節點在相同層輸出的,這樣就能完成廣度優先遍歷,程式如下:
void Btree::BreadthFirstVisit() { BreadthFirstVisit(root); } void Btree::BreadthFirstVisit(BtreeNode *Bvs) { queue<BtreeNode *> nodeQueue; nodeQueue.push(root); while (!nodeQueue.empty()) { BtreeNode *node = nodeQueue.front(); cout << node->ele << ' '; nodeQueue.pop(); if (node->left) nodeQueue.push(node->left); if (node->right) nodeQueue.push(node->right); }
(1)深度優先遍歷
深度優先遍歷就是優先遍歷完某一條線的所有子節點,遍歷完之後再考慮下一條線,所遵循的順序仍然是自上而下,自左向右。圖1的二叉樹,如果採用深度優先遍歷原則,輸出的順序為8 3 1 6 4 7 10 14 13。
類似廣度優先遍歷,我們可以考慮用棧實現深度優先遍歷,將節點一次壓入棧,注意棧的原則是後進先出。我們首先將8壓入棧,此時棧中只有8一個元素,輸出並彈出,然後將其右節點10和左結點3分別壓入棧,注意是先壓右再壓左,這樣才能保證左邊的先輸出。接著輸出節點3並彈出節點,彈出後將節點3的右節點6和左結點1分別壓入棧,注意此時節點1是最後入棧的,因此需要先處理節點1,處理完節點1之後,因為節點1沒有子節點了,再來處理節點6,處理完節點6後還有其左節點4和右節點7,這兩個節點肯定是後入棧的,所以必然會先處理,將這些處理完之後,再回去處理節點10。以此類推。所有節點入棧的順序為
圖3. 深度優先遍歷法節點入棧順序以及輸出順序
圖3顯示了採用深度優先遍歷是節點入棧順序,豎線同樣表示節點是在不同迴圈壓入棧的,兩種不同顏色的路線表示其中一條完成後才會進行另一條輸出,紅色代表節點8的左結點產生的分支,綠色部分表示節點8右節點產生的分支。深度優先遍歷的程式如下
void Btree::DepthFirstVisit(BtreeNode* dvs)
{
stack<BtreeNode*> nodeStack;
nodeStack.push(root);
while (!nodeStack.empty())
{
BtreeNode *node = nodeStack.top();
cout << node->ele << ' ';
nodeStack.pop();
if (node->right)
{
nodeStack.push(node->right);
}
if (node->left)
{
nodeStack.push(node->left);
}
}
}