二叉樹的三種遍歷常用於恢復:先序,中序,後序。對於先+中,後+中這兩種組合,對任意二叉樹的恢復都有唯一解,但對先+後的情況則不是,這種情況下要滿足要求:對所有非葉節點,其兩個子節點都存在,也即,乙個節點要麼是葉節點,要麼有兩個節點。
典型的恢復方法是遞迴建構節點的左,右子樹。乙個乙個看:
假設二叉樹原型如下,為了方便,節點的值剛好等於層次遍歷索引
先序:1,2,4,5,10,11,3,6,7,
中序:4,2,10,5,11,1,6,3,7,
後序:4,10,11,5,2,6,7,3,1,
先+中恢復:
對先序,注意第乙個節點是根節點,其遍歷順序是中左右,因此,若把第乙個節點作為基準,則其左右子樹連續儲存在該節點之後,不過,目前我們還不知道到底左右子樹的分界點在哪,因此需要結合中序來確定其分界點。先序的第乙個節點在中序的第5個位置(從0開始算),而我們知道中序的儲存順序是:先中後,因此,對中序列,該節點的左邊是其左子樹,右邊是右子樹。因此,根據節點在中序中的位置可以確定其左子樹的元素個數,對應到先序即可得到該節點的左,右子樹分別在先,中序的位置。根據上述資訊就可遞迴的恢復根節點的左,右子樹,進而得到整個樹。
後+中:
與上述類似,只不對後序,根節點在末尾,其它的可依此類推。
先+後:
這種情況下恢復的二叉樹不一定有唯一解,考慮如下的樹:1/
2先序:1,2
後序:2,1與1
\2先序: 1,2
後序:2,1
可看到不同的樹,先,後序遍歷是一樣的。
其唯一解的條件文章開頭已經說過了。不過沒有經過嚴格考究!
這裡只針對有唯一解的情況做討論,還考慮上圖的例子,結合例項描述如下:
先序:1,2,4,5,10,11,3,6,7,
後序:4,10,11,5,2,6,7,3,1,
對先序,第乙個節點與後序最後節點對應,然後再看先序的第二個節點(值為2),我們知道,如果先序存在子樹,則必同時存在左右子樹,因此可斷定,第二個節點正是根節點的左子樹節點,可先恢復成:1/
2而它又把後序分成兩個部分,一左一右(右邊不包括最末的根節點):左(4,10,11,5,2),右(6,7,3),說到這裡,再結合上圖,一切都明白了:「左」正是根的左子樹,「右」正是根的右子樹。於是,我們又得到了根節點的左右子樹,遞迴,搞定。
上**:
[cpp]view plain
copy
typedef
struct
tagtree
tree;
template
<
class
t>
void
show(t* vec,
intn)
cout
//按陣列裡指定的層次數值,生成任意二叉樹結構,陣列裡缺失的數值表示對應該層次的該節點沒有
void
createtree(tree** node,
inta,
intn )
intk=0;
for(
inti=0;i
tree* arrtree = new
tree[n];
//root
arrtree[0].parent = null;
for(
inti=1;i<=n;++i)
else
if( rightidx > a[n-1] || arr[rightidx-1] == 0 )
else
} *node = arrtree;
//test
for(
inti=1;i<=n;++i)
cout<
; if
(arrtree[i-1].right)
cout<
; if
(arrtree[i-1].parent)
cout
} //先序遍歷,第乙個引數是二叉樹的頭結點,第二個引數是用於記錄遍歷序列的陣列,下同
void
preorder(tree* ptree,
int** out)
void
inorder(tree* ptree,
int** out)
void
postorder(tree* ptree,
int** out)
//先+中恢復二叉樹
tree* pre_in(const
int* pre,
const
int* in,
intn)
//遞迴的構建節點的左右子樹,這裡需要確定左/右子樹對應的先序/中序段
tree* left = pre_in( pre+1,in,i );
tree* right = pre_in( pre+i+1,in+i+1,n-i-1 );
head->left = left;
head->right = right;
//返回頭節點
return
head;
} //後+中恢復二叉樹
tree* post_in(const
int* post,
const
int* in,
intn)
//遞迴的構建左右子樹,這裡需要確定左/右子樹對應的後序/中序段
tree* left = post_in(post,in,i);
tree* right = post_in(post+i,in+i+1,n-i-1);
head->left = left;
head->right = right;
return
head;
} //先+後恢復二叉樹
tree* pre_post(const
int* pre,
const
int* post,
intn)
tree* left = pre_post(pre+1,post,i+1);
tree* right = pre_post(pre+i+2,post+i+1,n-i-2);
head->left = left;
head->right = right;
return
head;
} int
_tmain(
intargc,
char
* argv)
;//先+後有唯一解的二叉樹,用於測試pre_post函式
const
intn = 9;
inta[n] = ;
createtree(&ptree,a,n);
intpre[n];
intin[n];
intpost[n];
int* pre_ptr = (
int*)pre;
int* in_ptr = (
int*)in;
int* post_ptr = (
int*)post;
preorder(ptree,&pre_ptr);
inorder(ptree,&in_ptr);
postorder(ptree,&post_ptr);
cout<
<
show(pre,n);
cout<
<
show(in,n);
cout<
<
show(post,n);
//------------- pre_in_post
tree* head = pre_in(pre,in,n);
intpre_in_post[n];
int* pre_in_post_ptr = (
int*)pre_in_post;
postorder(head,&pre_in_post_ptr);
cout
<
show(pre_in_post,n);
//------------- post_in_pre
head = post_in(post,in,n);
intpost_in_pre[n];
int* post_in_pre_ptr = (
int*)post_in_pre;
preorder(head,&post_in_pre_ptr);
cout
<
show(post_in_pre,n);
//------------- pre_post_in
//注意:這種情況況不是任意二叉樹都有唯一解,只對這種二叉樹才有唯一解:每個非葉節點都有個孩子
head = pre_post(pre,post,n);
intpre_post_in[n];
int* pre_post_in_ptr = (
int*)pre_post_in;
inorder(head,&pre_post_in_ptr);
cout
<
show(pre_post_in,n);
return
0;
}
根據二叉樹前序 中序遍歷還原二叉樹
在學習二叉樹遍歷的時候我們學習了三種遍歷方法 前序 中序 後序 同時我們知道給定前序和中序 中序和後序我們可以還原二叉樹,記得當時只是在紙上畫了一畫。現在把當時的想法完成。給定前序和中序生成二叉樹。include 在學習二叉樹遍歷的時候我們學習了三種遍歷方法 前序 中序 後序 同時我們知道給定前序和...
根據二叉樹的後序遍歷以及中序遍歷還原二叉樹
題目 假設一棵二叉樹的後序遍歷序列為 dgjhebifca 中序遍歷序列為 dbgehjacif 則其前序 遍歷序列為 a.abcdefghij b.abdeghjcfi c.abdeghjfic d.abdegjhcfi 由題,後序遍歷的最後乙個值為a,說明本二叉樹以節點a為根節點 當然,答案中第...
二叉樹遍歷序列還原
給出二叉樹的中序遍歷序列和後序遍歷序列,程式設計還原該二叉樹。輸入 第1行為二叉樹的中序遍歷序列 第2行為二叉樹的後序遍歷序列 輸出 二叉樹的按層遍歷序列 測試輸入 badcfeg bdfgeca 測試輸出 abcdefg 源 include include include includetyped...