資料結構(四)二叉樹的遍歷
阿新 • • 發佈:2018-12-18
二叉樹的遍歷
0. 樹的表示
typedef struct TreeNode *BinTree;
struct TreeNode{
int Data; // 存值
BinTree Left; // 左兒子結點
BinTree Right; // 右兒子結點
};
1. 先序遍歷
遍歷過程:
- 訪問根結點
- 先序遍歷其左子樹
- 先序遍歷其右子樹
1. 遞迴實現
void PreOrderTraversal(BinTree BT){
if(BT){
printf("%d",BT->Data); // 列印根
PreOrderTraversal(BT->Left) ; // 進入左子樹
PreOrderTraversal(BT->Right); // 進入右子樹
}
}
2. 非遞迴實現
void PreOrderTraversal(BinTree BT){
BinTree T = BT;
Stack S = CreateStack(); // 建立並初始化堆疊 S
while(T || !IsEmpty(S)){ // 當樹不為空或堆疊不空
while(T){
Push(S,T); // 壓棧,第一次遇到該結點
printf("%d",T->Data); // 訪問結點
T = T->Left; // 遍歷左子樹
}
if(!IsEmpty(S)){ // 當堆疊不空
T = Pop(S); // 出棧,第二次遇到該結點
T = T->Right; // 訪問右結點
}
}
}
2. 中序遍歷
遞迴過程:
- 中序遍歷其左子樹
- 訪問根結點
- 中序遍歷其右子樹
1. 遞迴實現
void InOrderTraversal(BinTree BT){
if(BT){
InOrderTraversal(BT->Left); // 進入左子樹
printf("%d",BT->Data); // 列印根
InOrderTraversal (BT->Right); // 進入右子樹
}
}
2. 非遞迴實現
void InOrderTraversal(BinTree BT){
BinTree T = BT;
Stack S = CreateStack(); // 建立並初始化堆疊 S
while(T || !IsEmpty(S)){ // 當樹不為空或堆疊不空
while(T){
Push(S,T); // 壓棧
T = T->Left; // 遍歷左子樹
}
if(!IsEmpty(S)){ // 當堆疊不空
T = Pop(S); // 出棧
printf("%d",T->Data); // 訪問結點
T = T->Right; // 訪問右結點
}
}
}
3. 後序遍歷
遍歷過程:
- 後序遍歷其左子樹
- 後序遍歷其右子樹
- 訪問根結點
1. 遞迴實現
void PostOrderTraversal(BinTree BT){
if(BT){
PostOrderTraversal(BT->Left); // 進入左子樹
PostOrderTraversal(BT->Right); // 進入右子樹
printf("%d",BT->Data); // 列印根
}
}
2. 非遞迴實現
void PostOrderTraversal(BinTree BT){
BinTree T = BT;
Stack S = CreateStack(); // 建立並初始化堆疊 S
vector<BinTree> v;
Push(S,T);
while(!IsEmpty(S)){ // 當樹不為空或堆疊不空
T = Pop(S);
v.push_back(T);
if(T->Left)
Push(S,T->Left);
if(T->Right)
Push(S,T->Right);
}
reverse(v.begin(),v.end()); // 逆轉
for(int i=0;i<v.size();i++)
printf("%d",v[i]->Data);
}
4. 總結
先序、中序和後序遍歷過程:遍歷過程中經過結點的路線一樣,只是訪問各 結點的時機不同,即:
- 先序遍歷是第一次"遇到"該結點時訪問
- 中序遍歷是第二次"遇到"該結點(此時該結點從左子樹返回)時訪問
- 後序遍歷是第三次"遇到"該結點(此時該結點從右子樹返回)時訪問
5. 層序遍歷
遍歷過程:從上至下,從左至右訪問所有結點
佇列實現過程:
- 從佇列中取出一個元素
- 訪問該元素所指結點
- 若該元素所指結點的左孩子結點非空,左孩子結點入隊
- 若該元素所指結點的右孩子結點非空,右孩子結點入隊
6. 例子
1. 輸出葉子結點
前序遍歷加個沒有孩子結點的約束即可
void FindLeaves(BinTree BT){
if(BT){
if( !BT->Left && !BT->Right)
printf("%d",BT->Data); // 列印葉子結點
FindLeaves(BT->Left); // 進入左子樹
FindLeaves(BT->Right); // 進入右子樹
}
}
2. 樹的高度
當前樹的高度為其子樹最大高度 +1
int GetHeight(BinTree BT){
int hl,hr,maxh;
if(BT){
hl = GetHeight(BT->Left); // 求左子樹高度
hr = GetHeight(BT->Right); // 求右子樹高度
maxh = (hl>hr)?hl:hr;
return maxh+1; // 當前結點高度為左右子樹最大的高度+1
}else
return 0;
}
3. 由兩種遍歷序列確定二叉樹
前提:有一種序列必須是中序!
方法:
- 根據先序(或後序)遍歷序列第一個(或最後一個)結點確定根結點
- 根據根結點在中序序列中分割出左右兩個子序列
- 對左子樹和右子樹分別遞迴使用同樣的方法繼續分解