看看这样说:
0 00 000 | (0,0) (0,1) (0,2)
001 | (1,2)
1 10 100 | (2,0) (2,1) (2,2)
101 | (3,2)
11 | (4,1)
我用同样的语法可以命名节点(左侧)和相应的位置“(行,列)”到网格(右侧) 。这里有两个顶级部门,0和1. 您可以用“(x,y)”坐标为每个树/顶级部门的深度首次访问标记节点。每当你从父亲到孩子下降,你必须增加1列号。 每次你访问一个新的兄弟姐妹时,你的行索引必须指向一个新的空行(在这个例子中,10的兄弟姐妹是11,但是你(3,1)不能放入,因为第3行已被101部门占用)。
我会按照这些指南编写算法。使用作为递归深度优先访问的参数传递的两个变量以及要访问的当前节点/部门来跟踪当前(x,y)。确保函数根据需要编辑excel表示,但返回使用的最大行索引(以便您可以在访问新的同级时使用它来知道下一行是哪一行 - 如前例所示)。 每次您进行递归调用时,都必须用coords(x,y + 1)调用它,因为它是一个新列。以类似的方式,当你访问一个新的兄弟姐妹时,你用(coords prev_call_retn + 1,y)调用它,因为它是一个新行(其中coords_prev_call_retn是前一个兄弟上次递归调用的值)。 辅助函数将调用根节点上的递归函数,并将其用作基础坐标(0,0)或任何您喜欢的起点。
#include <iostream>
#include <list>
#include <string>
using namespace std;
class Dept {
public:
string id;
list<Dept*> *subDepts;
Dept(string id) {
this->id = id;
this->subDepts = new list<Dept*>();
}
Dept *addChild(Dept *d) {
this->subDepts->push_back(d);
return d;
}
Dept *addChild(string id) {
Dept *d = new Dept(id);
return this->addChild(d);
}
};
void visit(Dept *d, int row, int col) {
cout << "Dept " << d->id << ": (" << row << ", " << col << ")\n";
}
int label(Dept *d, int row, int col) {
if (d == 0) return row;
visit(d, row, col);
list<Dept*> *lst = d->subDepts;
for (list<Dept*>::iterator it = lst->begin() ; it != lst->end(); it++)
{
row = label(*it, row, col+1) + 1;
}
if (lst->size() > 0) row--;
return row;
}
int label(Dept *d) {
label(d, 0, 0);
}
在这个C++代码,标签()是你感兴趣的函数。
参数ROW和COL都应该是部门* d的正确的坐标,这样我们就可以立即访问该节点。
循环递归调用每个孩子(如果有的话)的label()。请注意,我使用变量行来跟踪最后一次使用的行+1。
最后,我们必须返回函数上次使用的行,但要小心减去一个,如果d-> subDepts不是空的。这是因为在上一次迭代中增加了1行的for循环。
下面是主要的一个例子:
int main(int argc, char **argv) {
Dept *d0 = new Dept("0");
Dept *d00 = d0->addChild("00");
Dept *d01 = d0->addChild("01");
Dept *d000 = d00->addChild("000");
Dept *d001 = d00->addChild("001");
Dept *d002 = d00->addChild("002");
Dept *d010 = d01->addChild("010");
Dept *d02 = d0->addChild("02");
label(d0);
return 0;
}
而这里的结果:
bash-4.2$ g++ dept.cpp && ./a.out
Dept 0: (0, 0)
Dept 00: (0, 1)
Dept 000: (0, 2)
Dept 001: (1, 2)
Dept 002: (2, 2)
Dept 01: (3, 1)
Dept 010: (3, 2)
Dept 02: (4, 1)
我希望这有助于。
感谢您的良好回答,我尝试编写代码,但我无法做到,我不擅长算法。你有空时可以抽出一些时间吗? – hguser
不客气。在这里,我通过添加一个有效的C++示例来编辑我的答案。 –
,谢谢。它的工作原理,但是我不知道是否有任何可以计算每个单元格的行跨度和列跨度?在你的例子中,'Dep0'将取一列和两行,'Dep11'取两列和一行。 – hguser