2011-08-16 51 views
1

我有一個類系:caculate基於樹形結構的行和cols生成excel文件

class Department{ 
    string des; 
    string name; 
    string id; 
    List<Department> subDeps; 
} 

正如代碼所示,一個部門可以有若干個子所在部門。

現在,我已經從數據庫中讀取了信息,並且得到了根部門對象。

然後我想生成一個Excel工作表這樣的方式:

enter image description here

事實上,根「部門」對象是一個樹形結構。

當我嘗試將項目寫入Excel表格時,我必須決定項目的行和列,但是我無法做到。

而且有人可以幫我一個忙嗎?

回答

2

看看這樣說:

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) 

我希望這有助於。

+0

感謝您的良好回答,我嘗試編寫代碼,但我無法做到,我不擅長算法。你有空時可以抽出一些時間嗎? – hguser

+0

不客氣。在這裏,我通過添加一個有效的C++示例來編輯我的答案。 –

+0

,謝謝。它的工作原理,但是我不知道是否有任何可以計算每個單元格的行跨度和列跨度?在你的例子中,'Dep0'將取一列和兩行,'Dep11'取兩列和一行。 – hguser

0

如果您想按照您的示例進行佈局,使用colspans來對齊單元格,那麼在沒有先發現或事先知道(硬編碼)的情況下,我看不出有任何方法可以這樣做,最大深度的樹 - 你需要這個來確定用於部門的總列數。一些表格屬性的

假設(將有助於理解下面的代碼):

  • 只有最右邊的單元跨越多個列,其他所有的列表ColWidth 1個
  • 最右邊的細胞從未跨越多行,總有colHeight 1
  • 存在着一些函數來計算最大寬度,或者可替換地最大列索引,對於該表的「部門」的一部分(設置在代碼中的變量或blockWidthmaxY

僞佈局表:

displayDeptTree(Department root) { 
    startX, startY: beginning coord of the root dept 
    blockWidth: total no. of columns (tree depth + 1, or hardcoded to value > possible depth) 
    maxY = startY + blockWidth - 1 // global var? 

    addDeptIntoCell(root, startX, startY) 
} 

// returns height of the cell 
int addDeptIntoCell(Department d, x, y) { 
    colHeight = 1 
    if (d->subDeps is empty) { 
     colWidth = maxY - y 
     addDepartment(d, x, y, colHeight, colWidth) // colHeight = 1 always 
    } else { 
     currY = y 
     for (Dept child : d->subDeps) { 
      childHeight = addDeptIntoCell(child, x + 1, currY); // increment x pos for children 
      currY += childHeight 
     } 
     colHeight = currY - y 
     addDepartment(d, x, colHeight, 1) 
    } 
    return colHeight 
} 


addDepartment(Department d, x, y, height, width) { 
    // Actually adds the department info into table, parameters should be self-explanatory, implementation not shown 
} 

這可能是一個錯誤等有過,而且我用D-> subDeps Java中的不是C++指針的尊重,但你應該得到的一般想法:)