【问题标题】:Visualize arbitrary tree in Racket using tree-layout使用树布局可视化 Racket 中的任意树
【发布时间】:2026-01-28 12:25:02
【问题描述】:

如何可视化任意树?

例如: (define T1 '(and (or x1 x2)(or x3 x4 x5)))

或者一个生成的:

(define functions '(not if and or))
(define terminals '(A0 A1 A2 D0 D1))
(define functions&terminals (append terminals functions ))

(define (pick-one list)
  (list-ref list (random (length list))))

(define arities '((if . 3)(and . 2)(or . 2)(not . 1)))

(define (terminal? symbol)
  (find (lambda (x)(eq? x symbol)) terminals))

(define (function? symbol)
  (find (lambda (x)(eq? x symbol)) functions))

(define (arity non-terminal)
  (let ((arity (find (lambda (x)(eq? non-terminal (car x))) arities)))
    (if arity
        (cdr arity)
        0)))

(define (numbers n)
  (if (= n 0) 
      '()
      (cons n (numbers (- n 1)))))

(define (gen-tree) 
  (let ((node (pick-one functions&terminals))) 
    (if (terminal? node) 
        node 
        (cons node (map (lambda (x) (gen-tree)) (numbers (arity 
node)))))))

> (gen-tree)
'(or (if A1 (and A1 (not (if D1 (and A0 A0) (or A0 A0)))) (or A0 A0)) D0)

球拍似乎有: https://docs.racket-lang.org/pict/Tree_Layout.html

用圆圈中的函数名称和参数可视化函数树是否足够?

【问题讨论】:

    标签: tree racket visualization


    【解决方案1】:

    我认为可以对 assefamaru 的回答进行改进 -

    • 将列表遍历与单个节点渲染分开
    • 简化输入案例分析
      1. 如果输入为空(基本情况),则返回空树,#f
      2. 否则(归纳)输入为空。如果输入是列表,则创建optree-layout 并递归地将draw 应用于args
      3. 否则(归纳)输入为 not null 并且输入 not 是一个列表。创建原子atree-layout

    上面编号的行对应下面的cmets -

    (define (my-node a)
      (cc-superimpose
       (disk 30 #:color "white")
       (text (symbol->string a))))
    
    (define (draw atom->pict a)
      (cond ((null? a) #f)                                 ;; 1
            ((list? a) (match a                            ;; 2
                         ((cons op args)
                          (apply tree-layout
                                 #:pict (atom->pict op)
                                 (map (curry draw atom->pict) args)))
                         (_ #f)))
            (else (tree-layout #:pict (atom->pict a)))))   ;; 3
    
    (define my-tree
      '(or (if A1 (and A1 (not (if D1 (and A0 A0) (or A0 A0)))) (or A0 A0)) D0))
    
    (naive-layered (draw my-node my-tree))
    

    【讨论】:

      【解决方案2】:

      您可以执行以下操作来可视化任意大小的树:

      (require pict
               pict/tree-layout)
      
      (define (draw tree)
        (define (viz tree)
          (cond
            ((null? tree) #f)
            ((not (pair? tree))
             (tree-layout #:pict (cc-superimpose
                                  (disk 30 #:color "white")
                                  (text (symbol->string tree)))))
            ((not (pair? (car tree)))
             (apply tree-layout (map viz (cdr tree))
                    #:pict (cc-superimpose
                            (disk 30 #:color "white")
                            (text (symbol->string (car tree))))))))
        (if (null? tree)
            #f
            (naive-layered (viz tree))))
      

      例如,使用您提供的列表:

      (define t1 '(and (or x1 x2) (or x3 x4 x5)))
      (define t2 '(or (if A1 (and A1 (not (if D1 (and A0 A0) (or A0 A0)))) (or A0 A0)) D0))
      

      【讨论】:

      • 对于附加点如何进行评估和减少的动画?
      • 对于较小的树看起来不错,但对于较大的树,它开始变得很奇怪:(draw '(if (not D0) (if (and (and (and D0 D1)) (or (if (and D0 (if A1 A1 (not D1))) (not (not (or A2) (and (and (and (and A1 A2) A2 (and D1 (and D1 (if A1 A0 (n​​ot (not A0)))))) A2)))) (and D1 (and A0 (非 (或 A0 A0))))) A2)) D1 (非 A1)) D0))
      • 你是如何将树保存为图像的?我正在使用球拍博士
      • 以上只是一张截图,但是你可以将生成的图片转换并保存在本地,方法是:(define generated-pict (draw tree))然后(send (pict->bitmap generated-pict) save-file "example.png" 'png)