AIZU ONLINE JUDGEのALDS1_7_B BinaryTree
の問題を参考に、2分木の表現方法を学びます。
問題文
与えられた根付き二分木 T の各節点 u
について、以下の情報を出力するプログラムを作成してください。
- uの節点番号
- uの親
- uの兄弟
- uの子の数
- uの深さ
- uの高さ
- 節点の種類(根、内部節点または葉)
ここでは、与えられる二分木は n 個の節点を持ち、それぞれ 0 から n-1 の番号が割り当てられているものとします。
入力例などは以下を参考にしてください。 http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=ALDS1_7_B&lang=jp
2分木を表現する構造体の定義
2分木を表現するための構造体の定義をします。
木を表現するためには、節点が必要になりますが、
2分木では節点は左右の子のみとルートを示す親を持てば
木全体を表現することができることがわかると思います。
struct Node {
int parent;
int left;
int right;
};
2分木の深さをセットする
2分木の深さを求めるために、木のrootから子を探索し
left、right共にNILになるまで、再起的にチェックします。
// 深さを設定する
void setDepth(int u,int d){
// 親の節点が葉のケース
if(u == NIL) return;
gDepth[u] = d;
// 左右の子にもセットする
setDepth(gNode[u].left, d + 1);
setDepth(gNode[u].right, d + 1);
}
兄弟のノードを求める
兄弟のノードを求めるには、
単純に親がいるかをチェックし、親の左の子・右の子を調べます
子が自身のノードである可能性があるので、そのケースを除きます。
int getSibling(int u){
// rootの場合
if(gNode[u].parent == NIL)return NIL;
// 自身が右の子だった場合
if(gNode[gNode[u].parent].left != u && gNode[gNode[u].parent].left != NIL){
return gNode[gNode[u].parent].left;
}
// 自身が左の子だった場合
if(gNode[gNode[u].parent].right != u && gNode[gNode[u].parent].right != NIL){
return gNode[gNode[u].parent].right;
}
// 親が一つしか子を持たない状態
return NIL;
}
2分木の高さを求める
この場合の高さは、あるノードの末尾の子から自分との差分になります。
自分から左右の子が存在するかどうか再帰的にチェックしていき、深い方の子と自分との差分を返します。
// 高さの設定をする
int setHeight(int u){
int h1,h2;
h1 = h2 = 0;
if(gNode[u].left != NIL){
h1 = setHeight(gNode[u].left) + 1;
}
if(gNode[u].right != NIL){
h2 = setHeight(gNode[u].right) + 1;
}
return gHeight[u] = (h1 > h2) ? h1 : h2;
}
最後にc++で書かれた全体のソースを載せます。
#include <stdio.h>
#include <iostream>
using namespace std;
// node最大量
#define MAX 100005
#define NIL -1
struct Node {
int parent;
int left;
int right;
};
// 配列で保持する
Node gNode[MAX];
int gDepth[MAX],gHeight[MAX];
// 兄弟を返す
int getSibling(int u){
// rootの場合
if(gNode[u].parent == NIL)return NIL;
// 自身が右の子だった場合
if(gNode[gNode[u].parent].left != u && gNode[gNode[u].parent].left != NIL){
return gNode[gNode[u].parent].left;
}
// 自身が左の子だった場合
if(gNode[gNode[u].parent].right != u && gNode[gNode[u].parent].right != NIL){
return gNode[gNode[u].parent].right;
}
// 親が一つしか子を持たない状態
return NIL;
}
void print(int node){
cout << "node " << node << ": ";
cout << "parent = " << gNode[node].parent << ", ";
cout << "sibling = " << getSibling(node) << ", ";
int deg = 0;
if(gNode[node].left != NIL) deg++;
if(gNode[node].right != NIL) deg++;
cout << "degree = " << deg << ", ";
cout << "depth = " << gDepth[node] << ", ";
cout << "height = " << gHeight[node] << ", ";
if(gNode[node].parent == NIL){
cout << "root\n";
}else if(gNode[node].left == NIL && gNode[node].right == NIL){
cout << "leaf\n";
}else{
cout << "internal node\n";
}
}
// 深さを設定する
void setDepth(int u,int d){
// 親の節点が葉のケース
if(u == NIL) return;
gDepth[u] = d;
// 左右の子にもセットする
setDepth(gNode[u].left, d + 1);
setDepth(gNode[u].right, d + 1);
}
// 高さの設定をする
int setHeight(int u){
int h1,h2;
h1 = h2 = 0;
if(gNode[u].left != NIL){
h1 = setHeight(gNode[u].left) + 1;
}
if(gNode[u].right != NIL){
h2 = setHeight(gNode[u].right) + 1;
}
return gHeight[u] = (h1 > h2) ? h1 : h2;
}
int main(){
int left,right,v,n,root = 0;
cin >> n;
// 初期化
for(int i = 0;i < n;++i){
gNode[i].parent = gNode[i].left = gNode[i].right = NIL;
}
for(int i = 0;i < n;++i){
cin >> v >> left >> right;
gNode[v].left = left;
gNode[v].right = right;
// 親の設定
if(left != NIL){
gNode[left].parent = v;
}
if(right != NIL){
gNode[right].parent = v;
}
}
// rootを探す
for(int i = 0;i < n;++i){
if(gNode[i].parent == NIL){
root = i;
}
}
// 根からはじめて深さを代入する
setDepth(root, 0);
setHeight(root);
for(int i = 0;i < n;++i){
print(i);
}
return 0;
}
参考ソース
https://book.mynavi.jp/ec/products/detail/id=35408
0 件のコメント:
コメントを投稿