問題
- 給定一個插入序列就可以唯一確定一棵二叉搜索樹。然而,一棵給定的二叉搜索樹卻可以由多種不同的插入序列得到。
- 例如,按照序列{2, 1, 3}和{2, 3, 1}插入初始為空的二叉搜索樹,都得到一樣的結果。
- 問題:對於輸入的各種插入序列,你需要判斷它們是否能生成一樣的二叉搜索樹。

輸入輸出示例
三種求解思路
-
分別建兩棵搜索樹的判別方法:
根據兩個序列分別建樹,再判別樹是否一樣。 -
不建樹的判別方法:根據根結點,把序列按左右子樹分為兩個分序列,再進行比較
3 1 2 4 vs 3 4 1 2
{1 2} 3 {4} {1 2} 3 {4}
3 1 2 4 vs 3 2 4 1
{1 2} 3 {4} {2 1} 3 {4} -
建一棵樹,再判別其他序列是否與該樹一致:
- 搜索樹表示
- 建搜索樹T
- 判別一序列是否與搜索樹T一致
搜索樹表示
- flag:標記序列中是否有這個結點
typedef struct TreeNode *Tree;
struct TreeNode {
int v;
Tree Left, Right;
int flag;
};
主函數部分
int main() {
對每組數據
1 讀入N和L
2 根據第一行序列建樹T
3 依據樹T分別判別后面的L個序列是否能與T形成同一搜索樹並輸出結果 return 0; }
需要設計的主要函數:
- 讀數據建搜索樹T
- 判別一序列是否與T構成一樣的搜索樹
int main()
{ int N, L, i;
Tree T;
scanf("%d", &N);
while (N) {
scanf("%d", &L);
T = MakeTree(N);
for (i=0; i<L; i++) {
if (Judge(T, N)) printf("Yes\n");
else printf("No\n");
ResetT(T); /*清除T中的標記flag*/
}
FreeTree(T);
scanf("%d", &N);
}
return 0;
}
建搜索樹
建立搜索樹
Tree MakeTree( int N )
{ Tree T;
int i, V;
scanf("%d", &V);
T = NewNode(V);
for (i=1; i<N; i++) {
scanf("%d", &V);
T = Insert(T, V);
}
return T;
}
插入操作
- 結點指針為空時,新建一個結點
- 結點非空,按照大小關系進入搜索樹
Tree Insert( Tree T, int V )
{
if ( !T ) T = NewNode(V);
else {
if ( V>T->v )
T->Right = Insert( T->Right, V );
else
T->Left = Insert( T->Left, V );
}
return T;
}
建立新結點
- 初始化:動態創建結點,結點值,左右結點值
Tree NewNode( int V )
{ Tree T = (Tree)malloc(sizeof(struct TreeNode));
T->v = V;
T->Left = T->Right = NULL;
T->flag = 0;
return T;
}
判別序列是否一致
方法:在樹T中按順序搜索序列3 2 4 1中的每個數
-
如果每次搜索所經過的結點在前面均出現過,則一致
-
否則(某次搜索中遇到前面未出現的結點),則不一致

-
分為兩種情況:該結點與序列中的一致(flag=0)或不一致(flag=1)
-
到達一個結點,若未遍歷過,則判斷是否與序列的一致。
-
若不一致,則返回0,一致則標記為1。
-
若遍歷過,則判斷該結點值與序列中的值的大小關系,進入下一個子樹。
int check ( Tree T, int V )
{
if ( T->flag ) {
if ( V<T->v ) return check(T->Left, V);
else if ( V>T->v ) return check(T->Right, V);
else return 0;
}
else {
if ( V==T->v ) {
T->flag = 1;
return 1;
}
else return 0;
}
}
int Judge( Tree T, int N )
{
int i, V, flag = 0;
/* flag: 0代表目前還一致,1代表已經不一致*/
scanf("%d", &V);
if ( V!=T->v ) flag = 1;
else T->flag = 1;
for (i=1; i<N; i++) {
scanf("%d", &V);
if ( (!flag) && (!check(T, V)) ) flag = 1;
}
if (flag) return 0;
else return 1;
}
- 遞歸重置
void ResetT ( Tree T ) /* 清除T中各結點的flag標記 */
{
if (T->Left) ResetT(T->Left);
if (T->Right) ResetT(T->Right);
T->flag = 0;
}
- 遞歸重置
void FreeTree ( Tree T ) /* 釋放T的空間 */
{
if (T->Left) FreeTree(T->Left);
if (T->Right) FreeTree(T->Right);
free(T);
}
