東華大学のコンピュータでリーフノードの数を計算する問題
トピックの説明:
データ構造内のツリーの定義から、ルートノードを除いて、ツリー内の各ノードには一意の親ノードがあることがわかります。この機能によると、ツリー内の各ノードを格納するために、連続した一連の格納スペース(1次元配列)を使用できます。自身のノードの情報を保存するだけでなく、ツリー内のノードは配列内の親ノードの位置も保存します(つまり、配列内の添え字を保存します。親の情報が-1の場合、ノードはルートノードです)ツリーを表すこの方法は、親表記と呼ばれます。
ツリーの各ノードのデータ型は、次のように定義されています。
struct PTNode{
char data;//结点数据域
int parent;//结点双亲在数组中的位置
};
ツリーのデータ型は次のように定義されています。
#define MAX_TREE_SIZE 100
struct PTree {
PTNode nodes[MAX_TREE_SIZE];//存储树中的所有结点
int n;//树中的结点数,n不超过100
};
すると、下図のツリーでは、親の表記に基づいた格納構造となり、下図の形式で格納されます(nは10)。
ツリーが上記のフォームを格納していることがわかっているので、リーフノードの数を計算する関数GetLeavesCountを記述してください。
GetLeavesCountの関数プロトタイプは次のとおりです。int GetLeavesCount(PTree T)
これらの中で、パラメーターTはツリー内のノードの数と図bに示すノード配列を格納し、関数はリーフノードの数を返します。
例:図の数値に対して関数GetLeavesCount(T)を呼び出すと、返される結果は6です
。最初の数値n入力は、ツリー内のノードの数を意味し、n行の入力があり、各線はノードの情報を表します。情報はノードのデータで、2番目の情報は配列内のノードの親ノードの位置です。
たとえば、
10
a -1
b 0
c 0
d 0
e 1
f 1
g 1
h 2
i 3
h 3
と入力して、図に対応する番号を作成します。
このツリーで関数GetLeavesCount(T)を呼び出し、結果を6として返し
ます。次のように入力した場合:
8
a -1
b 0
e 1
h 2
c 0
d 0
f 5
g 5
このツリーでGetLeavesCount(T)を呼び出すと、結果は4になります。
アルゴリズムのアイデア:
ノード配列をトラバースします。ノードのノード番号が別のノードを指す場合、ノードは非リーフノードです。ノードをトラバースする場合、ノードへのポインターはありません。このノードはリーフノードです。ここで考え方を変えてみましょう。葉以外のノードの数を数えるのが簡単になります。
#include<iostream>
using namespace std;
struct PTNode{
char data;//结点数据域
int parent;//结点双亲在数组中的位置
};
#define MAX_TREE_SIZE 100
struct PTree {
PTNode nodes[MAX_TREE_SIZE];//存储树中的所有结点
int n;//树中的结点数,n不超过100
};
int GetLeavesCount(PTree T) {
int count = 0;//用来存储非叶子结点的个数
for (int i = 0;i < T.n;i++) {
for (int j = 0;j < T.n;j++) {
if (i == j)
continue;//自己不和自己比较
if (i == T.nodes[j].parent) {//检测到该结点有叶子结点
count++;//非叶子结点数增加
break;//不重复计算该结点
}
}
}
return T.n - count;//返回叶子结点数
}
int main() {
int n;
cout << "输入结点个数:";
cin >> n;
PTree T;
T.n = n;
cout << "输入结点信息:" << endl;
for (int i = 0;i < n;i++) {
cin >> T.nodes[i].data >> T.nodes[i].parent;
}
cout << "叶子结点个数为:" << GetLeavesCount(T) << endl;
return 0;
}
テスト結果の実行: