より多くの例のために、より大きなツリー用に編集されました。
いくつかの制限付きで、考えられるすべての順列を生成する必要があるツリー構造があります。次のようなツリーがあるとします。
A1----(B1, B2)
\
\___(C1)
\__(E1, E2)
/
- A2----(B3, B4)
\ \ \
\ \__(D1)
\
\_(F1, F2)
|
(D4)
A3----(B5, B6)
\__(D2, D3)
または、これが少し漠然としている場合は、Perl 表記で行われた同じ構造を次に示します。
my $nodes = [
{
name => 'A1',
children => [
[ { name => 'B1', children => [] },
{ name => 'B2', children => [] }
],
[
{ name => 'C1',
children => [
[
{ name => 'E1', children => [] },
{ name => 'E2', children => [] }
]
]
}
]
]
},
{
name => 'A2',
children => [
[ { name => 'B3',
children => [
[
{ name => 'D1', children => [] }
]
]
},
{ name => 'B4', children => [] }
],
[
{ name => 'F1', children => [] },
{ name => 'F2', children => [
[ { name => 'D4', children => [] } ]
]
}
]
]
},
{
name => 'A3',
children => [
[ { name => 'B5', children => [] },
{ name => 'B6', children => [
[ { name => 'D2', children => [] },
{ name => 'D3', children => [] }
]
]
}
]
]
}
];
(率直に言って、これを読み取り可能なPerl で理解できるなら、私もそれを採用します。)
ツリーをトラバースして、可能な「パス」をすべて最上位から下に取得しようとしています。ノードのすべての子孫グループは、「パス」内の正確に 1 つのメンバーによって表される必要があります。たとえば、A1 では、(B1、B2) の 1 つと (C1) の 1 つを表す必要があります。したがって、A1 から下る各パスは次のいずれかで始まります。
A1 B1 C1
また
A1 B2 C1
B1、B2、または C1 に子がある場合は、それらも表す必要があります。
上記のツリーに対してこれを手作業で処理すると、次の可能性が得られます。
A1 B1 C1 E1
A1 B1 C1 E2
A1 B2 C1 E1
A1 B2 C1 E2
A2 B3 D1 F1
A2 B3 D1 F2 D4
A2 B4 F1
A2 B4 F2 D4
A3 B5
A3 B6 D2
A3 B6 D3
ここの各ノードは DataRow オブジェクトです。
internal class DataRow
{
internal string tag = "";
internal int id = 0;
internal Dictionary<string, List<DataRow>> children = null;
internal DataRow(int id, string tagname)
{
this.tag = tagname;
this.id = id;
} internal void AddChildren(string type, List<DataRow> drList)
{
if (children == null)
children = new Dictionary<string, List<DataRow>>();
if (!children.ContainsKey(type))
children[type] = new List<DataRow>();
children[type].AddRange(drList);
}
internal void AddChild(string type, DataRow dr)
{
List<DataRow> drList = new List<DataRow>();
drList.Add(dr);
AddChildren(type, drList);
}
public override string ToString()
{
return this.tag + " " + this.id;
}
}
上記のサンプル ツリーを構築するには (後で追加される E および F レベルを除く):
DataRow fullList = new DataRow(null, "");
DataRow dr, dr2, dr3;
// First node above
dr = new DataRow(1, "A");
List<DataRow> drList = new List<DataRow>();
drList.Add(new DataRow(1, "B"));
drList.Add(new DataRow(2, "B"));
dr.AddChildren("B", drList);
drList.Clear();
dr2 = new DataRow(1, "C");
dr2.AddChild("C", new DataRow(1, "E"));
dr2.AddChild("C", new DataRow(2, "E"));
drList.Add(dr2);
dr.AddChildren("C", drList);
fullList.AddChild("A", dr);
// Second Node above (without the "F" stuff)
drList.Clear();
dr = new DataRow(3, "B");
dr.AddChild("D", new DataRow(1, "D"));
drList.Add(dr);
drList.Add(new DataRow(4, "B"));
dr = new DataRow(2, "A");
dr.AddChildren("B", drList);
fullList.AddChild("A", dr);
// Third node above
drList.Clear();
dr3 = new DataRow(6, "B");
dr3.AddChild("B", new DataRow(2, "D"));
dr3.AddChild("B", new DataRow(3, "D"));
dr2 = new DataRow(3, "A");
dr2.AddChild("B", new DataRow(5, "B"));
dr2.AddChild("B", dr3);
fullList.AddChild("A", dr2);
ツリー全体を歩くのは簡単です:
internal void PermutedList()
{
if ( children == null ) return;
foreach (string kidType in children.Keys)
{
foreach (DataRow dr in children[kidType])
{
dr.PermutedList();
}
}
}
しかし、それは私が必要とするものではありません。この問題は完全なツリー ウォークですが、特定の順序です。何が得られないのですか?これはどんな散歩ですか?
私は 10 年前に Perl で書いたこれの面倒で遅い実装を持っていますが、もう自分のコードを解読することはできません (恥を知れ!)。
編集:グラフと以下のリストは展開されていますが、コードは展開されていません。
グラフを説明できれば、プログラムできます。それが何と呼ばれているか知っていれば、それを調べることができた。しかし、私はできません。ということで、もう少し詳しく説明します。
バケット名は重要ではありません!
各ノードには「子のバケット」があります。A1 には 2 つのバケットがあり、1 つは「B」を含み、もう 1 つは「C」を含みます。それだけの場合 (そして C の下にバケットがなかった場合)、「A1 B1 C1」と「A1 B2 C1」が存在することになります。これは、存在するすべての子バケットから少なくとも 1 つの代表です。
したがって、各バケットには、その子の外積が必要だと思います (ずっと下まで)。