找到每个节点的大小

时间:2017-04-23 11:21:51

标签: algorithm recursion graph

我有一棵植根于1的树,我需要找到每个节点的大小。 我正在使用这个递归调用来执行

find_size(int curr , int parent){
       S[curr]=1
       for(int j:Children[curr]){

               if(j==parent) continue;
                find_size(j,curr)
                S[curr]+=S[j];
     }

}

如何使用堆栈或其他东西将我的解决方案减少到non recursive one?由于递归解决方案不适用于大型数据集。

2 个答案:

答案 0 :(得分:0)

我将描述一种可能的迭代方法,它包括两个步骤:

  1. 使用队列来确定每个节点的深度。
  2. 以递减的深度顺序处理节点。
  3. 这种方法基于树的BFS遍历,因此它不直接模仿递归完成的DFS遍历,并且具有更容易迭代实现的优势。

    对于第1步:

    • 最初,只将根节点添加到队列中,用depth = 0标记它。
    • 当队列不为空时,从队列中提取第一个节点,查看其深度(此处表示为currentDepth),并通过用{{1}标记每个节点将其子节点添加到队列末尾}} = childDepth + 1。

    对于第2步:

    • 以反向深度顺序处理节点。节点的处理涉及通过添加所有子节点的大小(加上当前节点的1)来计算其子树大小。
    • 请注意,每次处理节点时,子节点都已处理(因为已经处理了所有深度较高的节点),因此我们已经知道了子子树的大小。

    备注:

    对于步骤2,可以通过从步骤1实现队列来有效地按照递减深度顺序对节点进行排序,其中列表从中我们从未实际删除元素(例如队列头可以保留使用指针,轮询时只能增加此指针)。

    以相反的顺序处理此列表是为了以递减的深度顺序遍历节点所需的全部内容。因此,没有必要明确使用currentDepth字段。

    上述想法的实现如下:

    depth

答案 1 :(得分:0)

您通过索引表示节点,因此我猜您将它们表示为两个数组,如下所示:

int[] parent; // index of parent (the parent of the root is negative, e.g. -1)
int[][] children; // indices of children for each node

您可以从叶节点开始收集总和,并在知道所有子节点O(n)的结果后立即继续:

s = new int[parent.length];
int[] processed = new int[parent.length]; // the number of children that are processed
for (int i = 0; i < parent.length; i++) // initialize
    s[i] = 1;
for (int i = 0; i < parent.length; i++) {
    if (children[i].length == 0) { // leaf node
        int p = parent[i], j = i;
        while (p >= 0 && processed[j] == children[j].length) { // all children are processed
            s[p] += s[j]; // adjust parent score
            processed[p]++; // increase the number of processed child nodes for parent
            j = p; // parent becomes the current node
            p = parent[j]; // and its parent the parent
        }
    }
}