Java如何實(shí)現(xiàn)樹的同構(gòu)?
樹的同構(gòu)
備忘!
定義:給定兩棵樹r1、r2,如果r1可以通過(guò)若干次的左子樹和右子樹互換,使之與r2完全相同,這說(shuō)明兩者同構(gòu)。
舉例

樹的構(gòu)造
樹可以由數(shù)組或鏈表來(lái)構(gòu)造:
舉例:上圖左上角的樹通過(guò)數(shù)組可表示為
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| A | B | C | D | E | G | - | - | - | F | - | H | - |
該方式浪費(fèi)了部分空間,但適合表示完全二叉樹
鏈表方式則比較直觀
除上述兩種方式外,還可以采用“類數(shù)組”的方式
public static class Node{
String data;
int left;
int right;
}
舉例:上圖左上角的樹可表示為
| 數(shù)組索引 | data | left | right |
|---|---|---|---|
| 0 | A | 1 | 2 |
| 1 | B | 3 | 4 |
| 2 | C | 6 | - |
| 3 | D | - | - |
| 4 | E | 5 | - |
| 5 | F | - | - |
| 6 | G | 7 | - |
| 7 | H | - | - |
本文的樹結(jié)構(gòu)使用了第三種方式
終端輸入:
A,1,2
B,3,-
C,-,-
D,-,-
A,2,1
B,3,-
C,-,-
D,-,-
public class TongGou {
private Scanner scanner;
public TongGou(){
scanner = new Scanner(System.in);
}
//樹結(jié)構(gòu)
public static class Node{
String data;
int left;
int right;
}
/**
* 創(chuàng)建樹
* @param nodes
* @return
*/
public int createTree(Node[] nodes){
int N = nodes.length;
int root = -1;
int[] check = new int[N];
Arrays.fill(check,0); //初始化為0
for (int i=0;i<N;i++){
//輸入格式 data,left,right
String next = scanner.next();
String[] inputList = next!=null?next.split(","):null;
if(inputList!=null&&inputList.length==3){
nodes[i] = new Node();
int left = "-".equals(inputList[1])?-1:Integer.parseInt(inputList[1]);
int right = "-".equals(inputList[2])?-1:Integer.parseInt(inputList[2]);
nodes[i].data = inputList[0];
nodes[i].left = left;
nodes[i].right = right;
if(left>0) {
check[left] = 1;
}
if(right>0){
check[right] = 1;
}
}
}
for(int i=0;i<check.length;i++){
if(check[i]==0&&nodes[i].data!=null){
root = i;
break;
}
}
return root;
}
/**
* 判斷同構(gòu)
* @param r1
* @param r2
* @return
*/
public boolean isomorphic(int r1,int r2,Node[] t1,Node[] t2){
//須注意不要漏掉邏輯!
//兩個(gè)根節(jié)點(diǎn)均為null,必同構(gòu)
if ((r1 == -1) && (r2 == -1)) {
return true;
}
//一個(gè)非空 另一個(gè)空,必不同構(gòu)
if(((r1==-1)&&(r2!=-1))||((r1!=-1)&&(r2==-1))){
return false;
}
//兩個(gè)節(jié)點(diǎn)非空 但值不同,必不同構(gòu)
if(!t1[r1].data.equals(t2[r2].data)){
return false;
}
//兩根節(jié)點(diǎn)的左孩子為空條件下,則須判斷兩根節(jié)點(diǎn)的右子樹是否同構(gòu)
if(t1[r1].left==-1&&t2[r2].left==-1){
return isomorphic(t1[r1].right,t2[r2].right,t1,t2);
}
//兩根節(jié)點(diǎn)的左孩子不為空且左孩子的值也相同,須判斷兩根節(jié)點(diǎn)的左子樹是否同構(gòu)以及兩根節(jié)點(diǎn)的右子樹是否同構(gòu)
//如果左右子樹均同構(gòu),則整棵樹同構(gòu)
if((t1[r1].left!=-1&&t2[r2].left!=-1)&&(t1[t1[r1].left].data.equals(t2[t2[r2].left].data))){
return isomorphic(t1[r1].left,t2[r2].left,t1,t2)&&isomorphic(t1[r1].right,t2[r2].right,t1,t2);
}else{
//分兩種情況解釋:
//1、兩根節(jié)點(diǎn)的左孩子不為空,但左孩子的值不同
//例如:t1[r1.left].data!=t2[r2.left].data。但有t1[r1.left].data==t2[r2.right].data、t1[r1.right].data==t2[r2.left].data
//即有可能r1的左子樹與r2的右子樹同構(gòu)、r1的右子樹與r2的左子樹同構(gòu)
//故須判斷r1的左子樹是否與r2的右子樹同構(gòu),以及r1的右子樹是否與r2的左子樹同構(gòu)
//2、兩根節(jié)點(diǎn)的左孩子一個(gè)為空,一個(gè)不為空
//例如:r1.left==-1、r2.left!=-1,如果r2.right==-1,顯然r1的左子樹與r2的右子樹同構(gòu),此時(shí)則有可能r1的右子樹與r2的左子樹同構(gòu)
//故須判斷r1的左子樹是否與r2的右子樹同構(gòu),以及r1的右子樹是否與r2的左子樹同構(gòu)
return isomorphic(t1[r1].left,t2[r2].right,t1,t2)&&isomorphic(t1[r1].right,t2[r2].left,t1,t2);
}
}
public static void main(String[] args) {
TongGou tongGou = new TongGou();
Node[] nodes = new Node[4];
Node[] nodes1 = new Node[4];
int tree1 = tongGou.createTree(nodes);
System.out.println();
int tree2 = tongGou.createTree(nodes1);
boolean isomorphic = tongGou.isomorphic(tree1, tree2, nodes, nodes1);
System.out.println(isomorphic);
}
}
到此這篇關(guān)于Java如何實(shí)現(xiàn)樹的同構(gòu)?的文章就介紹到這了,更多相關(guān)Java實(shí)現(xiàn)樹的同構(gòu)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
原來(lái)Java接口多實(shí)現(xiàn)還可以這樣玩
JAVA中類不直接支持多繼承,因?yàn)闀?huì)出現(xiàn)調(diào)用的不確定性,所以JAVA將多繼承機(jī)制進(jìn)行改良,在JAVA中變成了多實(shí)現(xiàn),這篇文章主要給大家介紹了關(guān)于Java接口多實(shí)現(xiàn)的相關(guān)資料,需要的朋友可以參考下2021-09-09
Springmvc數(shù)據(jù)回顯實(shí)現(xiàn)原理實(shí)例解析
這篇文章主要介紹了Springmvc數(shù)據(jù)回顯實(shí)現(xiàn)原理實(shí)例解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-09-09
Java基礎(chǔ)之選擇結(jié)構(gòu)與循環(huán)結(jié)構(gòu)
這篇文章主要介紹了Java基礎(chǔ)之選擇結(jié)構(gòu)與循環(huán)結(jié)構(gòu),文中有非常詳細(xì)的代碼示例,對(duì)正在學(xué)習(xí)java基礎(chǔ)的小伙伴們有非常好的幫助,需要的朋友可以參考下2021-04-04
SpringBoot后端接口的實(shí)現(xiàn)(看這一篇就夠了)
這篇文章主要介紹了SpringBoot后端接口的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09
使用kafka如何選擇分區(qū)數(shù)及kafka性能測(cè)試
這篇文章主要介紹了使用kafka如何選擇分區(qū)數(shù)及kafka性能測(cè)試,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-08-08
Java分支結(jié)構(gòu)和循環(huán)結(jié)構(gòu)原理與用法詳解
這篇文章主要介紹了Java分支結(jié)構(gòu)和循環(huán)結(jié)構(gòu)原理與用法,結(jié)合實(shí)例形式分析了java分支結(jié)構(gòu)、循環(huán)結(jié)構(gòu)、跳轉(zhuǎn)語(yǔ)句等相關(guān)概念、原理、使用技巧與操作注意事項(xiàng),需要的朋友可以參考下2020-02-02
Java?定時(shí)任務(wù)技術(shù)趨勢(shì)詳情
這篇文章主要介紹了Java?定時(shí)任務(wù)技術(shù)趨勢(shì)詳情,定時(shí)任務(wù)是每個(gè)業(yè)務(wù)常見的需求,比如每分鐘掃描超時(shí)支付的訂單,每小時(shí)清理一次數(shù)據(jù)庫(kù)歷史數(shù)據(jù),每天統(tǒng)計(jì)前一天的數(shù)據(jù)并生成報(bào)表等,下文更多相關(guān)資料,需要的小伙伴可以參考一下2022-05-05
如何解決Maven下載的依賴版本和引入的依賴版本不一致問(wèn)題
這篇文章主要介紹了如何解決Maven下載的依賴版本和引入的依賴版本不一致問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-05-05
玩轉(zhuǎn)SpringBoot中的那些連接池(小結(jié))
這篇文章主要介紹了玩轉(zhuǎn)SpringBoot中的那些連接池(小結(jié)),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-12-12

