枚举具有n个节点的所有二叉树


10

给定一个整数n,用n个内部节点枚举所有可能的完整二叉树。(完整的二叉树在每个内部节点上恰好有2个子节点)。树结构应作为树的预遍历输出,其中1表示内部节点,0表示外部节点(空)。

以下是前n个示例:

0:
0

1:
100

2:
11000
10100

3:
1110000
1101000
1100100
1011000
1010100

这是一场代码高尔夫,奖金最少的人物。这些树应该每行输出到stdout。该程序应从命令行或标准输入中读取n。


当我尝试创建类似迷宫的书写系统时,我正在思考该问题
Ming-Tang

宣布解决方案之前的标准截止日期是什么?
Kyle Butt

对这个问题进行细微的改动是否会引起任何兴趣,需要将输出排序并进行流传输?
凯尔·巴特

@Kyle Butt只是我的意见,但我不认为我会感兴趣。对我来说,解决这些问题的乐趣之一就是尝试其他方法,并且要求确定的顺序可能会限制可行算法的数量。
migimaru

Answers:


3

Perl- 125 79个字符

Count包含4个字符,用于“ -ln”选项。从标准输入中取n。

新的建设性方法:

@a=0;map{%a=();map{$a{"$`100$'"}=1while/0/g;}@a;@a=keys%a}1..$_;print for@a

通过依次为每个树(n-1)中的每个叶子(“ 0”)替换一个新的内部节点(“ 100”)来形成n的解决方案。

(我将此概念归功于其他解决方案,这些解决方案使用内部节点进行[100-> 0]替换来验证顺序生成的字符串,并且我相信-在基于该概念编写答案之后,我看到了同样的0-在某人的中间编辑中> 100种构建方法。)

先前的递归方法:

sub t{my$n=shift;if($n){--$n;for$R(0..$n){for$r(t($R)){for$l(t($n-$R)){push@_,"1$l$r"}}}}else{push@_,"0"}@_}print for t$_

递归的:

sub tree {
  my ($n) = @_;
  my @result = ();
  if ( $n ) {
    for $right_count ( 0 .. $n-1 ) {
      for $right ( tree( $right_count ) ) {
        for $left ( tree( ($n-1) - $right_count ) ) {
          push @result, "1$left$right";
        }
      }
    }
  }
  else {
    push @result, "0";
  }
  return @result;
}
foreach $tree ( tree($_) ) {
  print $tree;
}

2

PHP (142) (138) (134)(113)

从命令行运行,即“ php golf.php 1”输出“ 100”。

编辑:用替代方法剪切4个字符,从0而不是从$ n递归建立字符串。对缩短的三元运算符使用PHP 5.3;否则,还需要2个字符。

编辑2:在循环中进行了一些更改后,又保存了4个字符。

编辑3:我正在尝试一种不同的方法,终于在旧方法之下得到了它。

所有树都可以视为4 ^ n(或n,当n = 0时为0)和2 * 4 ^ n之间的整数的二进制表示。此函数循环遍历该范围,并获取每个数字的二进制字符串,然后通过将“ 100”替换为“ 0”来重复减少它。如果最后一个字符串为“ 0”,则它是一棵有效的树,因此将其输出。

for($i=$p=pow(4,$argv[1])-1;$i<=2*$p;){$s=$d=decbin($i++);while($o!=$s=str_replace(100,0,$o=$s));echo$s?:"$d\n";}

2

Ruby,99 94 92 89 87个字符

(n=4**gets.to_i).times{|i|s=(n+i-1).to_s 2;t=s*1;0while s.sub!'100',?0;puts t if s==?0}

输入是从stdin中读取的。

> echo 2 | ruby binary_trees.rb
10100
11000

编辑1:更改了IO(请参阅Lowjacker的评论)

b=->n{n==0?[?0]:(k=[];n.times{|z|b[z].product(b[n-1-z]){|l|k<<=?1+l*''}};k)}
puts b[gets.to_i]

编辑2:更改算法。

b=->n{n==0?[?0]:(k=[];b[n-1].map{|s|s.gsub(/0/){k<<=$`+'100'+$'}};k.uniq)}
puts b[gets.to_i]

编辑3:该版本现在采用第三种方法(使用migimaru的思想)。

编辑4:再次两个字符。谢谢migimaru。


接受来自stdin的输入将短一个字符。
Lowjacker

另外,您不需要*?\n,因为会puts在自己的行中打印数组的每个元素。
Lowjacker

@Lowjacker谢谢。
霍华德

我刚刚开始尝试学习Ruby,但是我认为您可以使用0while而不是{} while来保存字符。至少它在NetBeans中有效。
migimaru

还有,子!而不是gsub!就足够了,因此您可以保存另一个字符。
migimaru

1

红宝石1.9 (80)(79)

使用DCharness使用的非递归,建设性方法。

编辑:保存了1个字符。

s=*?0;gets.to_i.times{s.map!{|x|x.gsub(?0).map{$`+'100'+$'}}.flatten!}
puts s&s

0

Haskell 122个字符

main=do n<-readLn;mapM putStrLn$g n n
g 0 0=[['0']]
g u r|r<u||u<0=[]
g u r=do s<-[1,0];map((toEnum$s+48):)$g(u-s)(r-1+s)

由于IO是haskell中代码的重要部分,因此也许有人可以使用另一种语言使用类似的解决方案。本质上,如果对角线交叉,则随机从左下角到右上角走一个正方形。等效于以下内容:

module BinTreeEnum where

import Data.List
import Data.Monoid

data TStruct = NonEmpty | Empty deriving (Enum, Show)
type TreeDef = [TStruct]

printTStruct :: TStruct -> Char
printTStruct NonEmpty = '1'
printTStruct Empty = '0'

printTreeDef :: TreeDef -> String
printTreeDef = map printTStruct

enumBinTrees :: Int -> [TreeDef]
enumBinTrees n = enumBinTrees' n n where
  enumBinTrees' ups rights | rights < ups = mempty
  enumBinTrees' 0   rights = return (replicate (rights+1) Empty)
  enumBinTrees' ups rights = do
    step <- enumFrom (toEnum 0)
    let suffixes =
          case step of
            NonEmpty -> enumBinTrees' (ups - 1) rights
            Empty -> enumBinTrees' ups (rights - 1)
    suffix <- suffixes
    return (step:suffix)

mainExample = do
  print $ map printTreeDef $ enumBinTrees 4

请注意,我无意接受此作为答案,只是以为我会把我扔在那里。
Kyle Butt

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.