二叉樹是一種非常重要的資料結構,很多其它資料結構都是基於二叉樹的基礎演變而來的。對於二叉樹,有前序、中序以及後序三種遍歷方法。因為樹的定義本身就是遞迴定義,因此採用遞迴的方法去實現樹的三種遍歷不僅容易理解而且**很簡潔。而對於樹的遍歷若採用非遞迴的方法,就要採用棧去模擬實現。在三種遍歷中,前序和中序遍歷的非遞迴演算法都很容易實現,非遞迴後序遍歷實現起來相對來說要難一點。
一.前序遍歷
前序遍歷按照「根結點-左孩子-右孩子」的順序進行訪問。
1.遞迴實現
2.非遞迴實現void preorder1(bintree *root) //遞迴前序遍歷
}
根據前序遍歷訪問的順序,優先訪問根結點,然後再分別訪問左孩子和右孩子。即對於任一結點,其可看做是根結點,因此可以直接訪問,訪問完之後,若其左孩子不為空,按相同規則訪問它的左子樹;當訪問其左子樹時,再訪問它的右子樹。因此其處理過程如下:
對於任一結點p:
1)訪問結點p,並將結點p入棧;
2)判斷結點p的左孩子是否為空,若為空,則取棧頂結點並進行出棧操作,並將棧頂結點的右孩子置為當前的結點p,迴圈至1);若不為空,則將p的左孩子置為當前的結點p;
3)直到p為null並且棧為空,則遍歷結束。
void preorder2(bintree *root) //非遞迴前序遍歷
if(!s.empty())
}}
二.中序遍歷
中序遍歷按照「左孩子-根結點-右孩子」的順序進行訪問。
1.遞迴實現
void inorder1(bintree *root) //遞迴中序遍歷
}
2.非遞迴實現
根據中序遍歷的順序,對於任一結點,優先訪問其左孩子,而左孩子結點又可以看做一根結點,然後繼續訪問其左孩子結點,直到遇到左孩子結點為空的結點才進行訪問,然後按相同的規則訪問其右子樹。因此其處理過程如下:
對於任一結點p,
1)若其左孩子不為空,則將p入棧並將p的左孩子置為當前的p,然後對當前結點p再進行相同的處理;
2)若其左孩子為空,則取棧頂元素並進行出棧操作,訪問該棧頂結點,然後將當前的p置為棧頂結點的右孩子;
3)直到p為null並且棧為空則遍歷結束
void inorder2(bintree *root) //非遞迴中序遍歷
if(!s.empty())
}
}
三.後序遍歷
後序遍歷按照「左孩子-右孩子-根結點」的順序進行訪問。
1.遞迴實現
void postorder1(bintree *root) //遞迴後序遍歷
}
2.非遞迴實現
後序遍歷的非遞迴實現是三種遍歷方式中最難的一種。因為在後序遍歷中,要保證左孩子和右孩子都已被訪問並且左孩子在右孩子前訪問才能訪問根結點,這就為流程的控制帶來了難題。下面介紹兩種思路。
第一種思路:對於任一結點p,將其入棧,然後沿其左子樹一直往下搜尋,直到搜尋到沒有左孩子的結點,此時該結點出現在棧頂,但是此時不能將其出棧並訪問,因此其右孩子還為被訪問。所以接下來按照相同的規則對其右子樹進行相同的處理,當訪問完其右孩子時,該結點又出現在棧頂,此時可以將其出棧並訪問。這樣就保證了正確的訪問順序。可以看出,在這個過程中,每個結點都兩次出現在棧頂,只有在第二次出現在棧頂時,才能訪問它。因此需要多設定乙個變數標識該結點是否是第一次出現在棧頂。
void postorder2(bintree *root) //非遞迴後序遍歷
if(!s.empty())
else //第二次出現在棧頂
}}
}
第二種思路:要保證根結點在左孩子和右孩子訪問之後才能訪問,因此對於任一結點p,先將其入棧。如果p不存在左孩子和右孩子,則可以直接訪問它;或者p存在左孩子或者右孩子,但是其左孩子和右孩子都已被訪問過了,則同樣可以直接訪問該結點。若非上述兩種情況,則將p的右孩子和左孩子依次入棧,這樣就保證了每次取棧頂元素的時候,左孩子在右孩子前面被訪問,左孩子和右孩子都在根結點前面被訪問。
void postorder3(bintree *root) //非遞迴後序遍歷
else
}
}
四.整個程式完整的**
/*二叉樹的遍歷* 2011.8.25*/
#include #include#includeusing namespace std;
typedef struct node
bintree;
typedef struct node1
btnode;
void creatbintree(char *s,bintree *&root) //建立二叉樹,s為形如a(b,c(d,e))形式的字串
if(root->rchild!=null)
}}void preorder1(bintree *root) //遞迴前序遍歷
}void inorder1(bintree *root) //遞迴中序遍歷
} void postorder1(bintree *root) //遞迴後序遍歷
} void preorder2(bintree *root) //非遞迴前序遍歷
if(!s.empty())
}}void inorder2(bintree *root) //非遞迴中序遍歷
if(!s.empty())
}
} void postorder2(bintree *root) //非遞迴後序遍歷
if(!s.empty())
else //第二次出現在棧頂
}}
} void postorder3(bintree *root) //非遞迴後序遍歷
else
}
}int main(int argc, char *argv)
{ char s[100];
while(scanf("%s",s)==1)
{bintree *root=(bintree *)malloc(sizeof(bintree));
creatbintree(s,root);
display(root);
cout<
構建二叉樹 遍歷二叉樹
陣列法構建二叉樹 public class main public static void main string args 用陣列的方式構建二叉樹 public static void createbintree 把linkedlist集合轉成二叉樹的形式 for int j 0 j 最後乙個父節...
二叉樹遍歷
二叉樹的遍歷非常重要,但對已一棵比較複雜的樹,要寫出它的先 中 後序遍歷,往往不是那麼簡單,也很容易犯錯。這裡介紹一種比較直觀且不容易犯錯的方法。對於圖1所示的二叉樹,要寫出它的先 中 後序遍歷,往往很容易出錯。圖 1 其實,我們可以用圖2中的紅線描畫出二叉樹的輪廓。圖 2 而對於樹上的每乙個節點,...
二叉樹遍歷
描述 華為實習生招聘,有一道類似如下的題目 給出二叉樹,如圖1所示 圖 1 二叉樹 要求給出中序遍歷的結果。下面分別就前序遍歷 中序遍歷 後序遍歷進行分析。規律 前序遍歷 根在前 子樹在根後且左子樹比右子樹靠前 中序遍歷 根在中 左子樹在根左邊,右子樹在根右邊 後序遍歷 根在後 子樹在根前且左子樹比...