1. 程式人生 > >PTA練習題---樹的同構

PTA練習題---樹的同構

問題描述:

給定兩棵樹T1和T2。如果T1可以通過若干次左右孩子互換就變成T2,則我們稱兩棵樹是“同構”的。例如圖1給出的兩棵樹就是同構的,因為我們把其中一棵樹的結點A、B、G的左右孩子互換後,就得到另外一棵樹。而圖2就不是同構的。


圖1

圖2

現給定兩棵樹,請你判斷它們是否是同構的。

輸入格式:

輸入給出2棵二叉樹樹的資訊。對於每棵樹,首先在一行中給出一個非負整數N (10),即該樹的結點數(此時假設結點從0到N1編號);隨後N行,第i行對應編號第i個結點,給出該結點中儲存的1個英文大寫字母、其左孩子結點的編號、右孩子結點的編號。如果孩子結點為空,則在相應位置上給出“-”。給出的資料間用一個空格分隔。注意:題目保證每個結點中儲存的字母是不同的。

輸出格式:

如果兩棵樹是同構的,輸出“Yes”,否則輸出“No”。

輸入樣例1(對應圖1):

8
A 1 2
B 3 4
C 5 -
D - -
E 6 -
G 7 -
F - -
H - -
8
G - 4
B 7 6
F - -
A 5 1
H - -
C 0 -
D - -
E 2 -

輸出樣例1:

Yes

輸入樣例2(對應圖2):

8
B 5 7
F - -
A 0 3
C 6 -
H - -
D - -
G 4 -
E 1 -
8
D 6 -
B 5 -
E - -
H - -
C 0 2
G - 3
F - -
A 1 4

輸出樣例2:

No

題目思路講解:https://www.bilibili.com/video/av14272542/index_2.html#page=2

需要解決的問題:

1.二叉樹用什麼形式表示,本題用了靜態連結串列的形式表示二叉樹。

2.怎麼建立二叉樹

3.如何判別兩個二叉樹是否同構

具體程式碼如下:

#include <stdio.h>

#define MaxTree 10
#define ElementType char
#define Tree int
#define Null -1
 
struct TreeNode     
{
	ElementType Element;
	Tree Left;
	Tree Right;	
}T1[MaxTree],T2[MaxTree];   	//T1和T2陣列的每一個元素的型別都是struct TreeNode型別
								 //T1和T2是全域性變數

Tree BuildTree(struct TreeNode T[])
{
	int i,N,check[MaxTree];
	Tree Root=Null;
	char cl,cr;
	
	scanf("%d\n",&N);   
	if(N)
	{						 
		for(i=0;i<N;i++)   //check陣列用來判斷根的位置
			check[i]=0;	   //每個結點初始對應的 check[i]初始化為0 
		
		for(i=0;i<N;i++)
		{
			scanf("%c %c %c\n",&T[i].Element,&cl,&cr);
			
			if(cl!='-')   //這個if。。else語句用來設定當前結點的左兒子是否存在 
			{
				T[i].Left=cl-'0';
				check[T[i].Left]=1;   //如果左兒子存在,則左兒子位置處的check值設定為1 
			}
			else
				T[i].Left=Null;	
				
			if(cr!='-')
			{
				T[i].Right=cr-'0';
				check[T[i].Right]=1;
			}
			else
				T[i].Right=Null;
		}
		
		for(i=0;i<N;i++)
		{
			if(!check[i])  	//如果check[i]為0,則找到了這個位置i為根,立馬跳出迴圈 
			{
				Root=i;    //T[i]中某一個結點,如果沒有任何其他結點的 Left和Right指向它,則該結點是根
				break;	
			}	
		}
	}
	return Root;
} 

int Isomorphic(Tree R1,Tree R2)     //從根開始比較每個結點的兩個兒子是否相等。必然會用到遞迴 
{
	if((R1==Null)&&(R2==Null))  //如果兩個樹的根均為空 ,基準情形
		return 1;
		
	if(((R1==Null)&&(R2!=Null))||((R1!=Null)&&(R2==Null))) //如果兩個樹的僅其中 一個根為空
		return 0;
	
	if(T1[R1].Element!=T2[R2].Element)		//如果兩個樹的根的元素不同 
		return 0;
	
	if((T1[R1].Left==Null)&&(T2[R2].Left==Null))        //如果根結點左子樹是空的,則從右子樹開始判斷 
		return Isomorphic(T1[R1].Right,T2[R2].Right);
	
		
	if((T1[R1].Left!=Null)&&(T2[R2].Left!=Null)&&((T1[T1[R1].Left].Element)==(T2[T2[R2].Left].Element)))   //左邊同時是不空的,且左兒子元素也是一樣的 
		return(Isomorphic(T1[R1].Left,T2[R2].Left)&&Isomorphic(T1[R1].Right,T2[R2].Right)); 			//則通過遞迴判斷左兒子和右兒子 是否相同 
	else		//兩個樹的左子樹都不空,但是左兒子不想等, 交換左右兒子進行判斷 
		return(Isomorphic(T1[R1].Left,T2[R2].Right)&&Isomorphic(T1[R1].Right,T2[R2].Left));	
} 

//程式結構:輸入並建立兩個二叉樹,然後判斷是否同構 
//建立兩個函式:讀取資料建立二叉樹的函式,二叉樹同構判別函式 
int main()
{
	Tree R1,R2;   //樹的根 
	 
	R1=BuildTree(T1);   //T1是結構陣列,是全域性變數 
	R2=BuildTree(T2);
	
	if(Isomorphic(R1,R2))	//判別是否同構並輸出
		printf("Yes\n");
	else
		printf("No\n");
	
	return 0; 
}