數據結構:判斷是否為同一棵二叉搜索樹


問題

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

輸入輸出示例

三種求解思路

  1. 分別建兩棵搜索樹的判別方法:
    根據兩個序列分別建樹,再判別樹是否一樣。

  2. 不建樹的判別方法:根據根結點,把序列按左右子樹分為兩個分序列,再進行比較
    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}

  3. 建一棵樹,再判別其他序列是否與該樹一致:

    1. 搜索樹表示
    2. 建搜索樹T
    3. 判別一序列是否與搜索樹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);
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM