【问题标题】:C# possibilities tree from integers array来自整数数组的 C# 可能性树
【发布时间】:2015-03-24 08:08:50
【问题描述】:

如何使用 C# 从整数数组构建可能性树?如果在每一步都从数组中删除一个元素,我需要制作所有可能的数组变体。

如果我们有来自三个整数 [1,2,3] 的数组,那么树应该如下所示:tree view

【问题讨论】:

  • 好吧,你坚持什么 - 计算排列,还是把它们放到树上?
  • 我需要从数组中生成树的算法(就像我的图片一样)
  • 在图片中...我希望标签要么变长(1、13、132)或变短(123、13、3),要么每个标记(1、3、 2) - 不清楚 (1, 23, 2) / (2, 13, 1) 是什么意思 - 你能澄清一下吗?
  • 好的,那么到目前为止你想出了什么?为什么 middle 列有 2 个数字,而其他只有一个?为什么每个中间节点只有一个分支,而不是两个?对于 1、2、3、4 的数组,结果会是什么? (不需要图片 - 在您的问题中将其放在文本中。)
  • hmm 是的,我的图片有点混乱,再看我更新的图片,我希望现在更清楚了

标签: c# arrays tree


【解决方案1】:

我会将其视为二进制算术问题:

static void Main(string[] args)
{
    int[] arr = { 1, 2, 3 };
    PickElements(0, arr);
}

static void PickElements<T>(int depth, T[] arr, int mask = -1)
{
    int bits = Math.Min(32, arr.Length);
    // keep just the bits from mask that are represented in arr
    mask &= ~(-1 << bits); 
    if (mask == 0) return;

    // UI: write the options
    for (int i = 0; i < depth; i++ )
        Console.Write('>'); // indent to depth
    for (int i = 0; i < arr.Length; i++)
    {
        if ((mask & (1 << i)) != 0)
        {
            Console.Write(' ');
            Console.Write(arr[i]);
        }
    }
    Console.WriteLine();

    // recurse, taking away one bit (naive and basic bit sweep)
    for (int i = 0; i < bits; i++)
    {
        // try and subtract each bit separately; if it
        // is different, recurse
        var childMask = mask & ~(1 << i);
        if (childMask != mask) PickElements(depth + 1, arr, childMask);
    }
}

对于TreeView,只需将Console.Write 等替换为节点创建,大概将父节点传入(和向下)作为递归的一部分(可能代替depth)。


要查看它在做什么,请考虑二进制文件; -1 是:

11111111111111...111111111111111

然后我们查看bits,我们从数组长度派生出来,在这个例子中发现它是3。那么,我们只需要查看 3 位即可;行:

~(-1 << bits)

为此计算掩码,因为:

-1          = 1111111....1111111111111
(-1 << 3)   = 1111111....1111111111000 (left-shift back-fills with 0)
~(-1 << 3)  = 0000000....0000000000111 (binary inverse)

然后我们将其应用于我们的输入掩码,因此我们只通过mask &amp;= ... 查看最低有效 3 位。如果结果是 0,我们已经没有事情可做,所以停止递归。

UI 更新很简单;我们只扫描我们关心的 3 位,检查当前位是否为我们的掩码“打开”; 1 &lt;&lt; i 仅使用“第 i 个设置位”创建掩码; &amp;!= 0 检查该位是否已设置。如果是,我们在输出中包含该元素。

最后,我们需要开始带走位,来查看子树;我们可以对此可能更复杂,但我选择只扫描所有位并尝试它们 - 最坏的情况是每个级别 32 位测试,这没什么。和以前一样,1 &lt;&lt; i 创建了一个仅包含“第 i 个设置位”的掩码。这次我们想禁用那个位,所以我们通过mask &amp; ~(...)“否定”和“与”。该位可能已经被禁用,因此childMask != mask 检查确保我们仅在禁用之前启用的位时实际上递归。

最终结果是我们最终得到了连续的掩码:

11..1111111111111111 (special case for first call; all set)
   110   (first bit disabled)
      100   (first and second bits disabled)
      010   (first and third bits disabled)
   101   (second bit disabled)
      100   (second and first bits disabled)
      001   (second and third bits disabled)
   011   (third bit disabled)
      010   (third and first bits disabled)
      001   (third and second bits disabled)

请注意,对于更简单的组合示例,可以在单个for中迭代,使用位来选择元素;但是,我以递归方式完成了它,因为我们需要构建一个连续减法树,而不仅仅是没有特定顺序的平面可能性。

【讨论】:

    猜你喜欢
    • 2023-03-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多